概述
在開發稍微複雜一點的網站時不能避免的一個問題是如何處理大量的附件,將附件託管在雲上無疑是一個很好的選擇,運營和維護成本都很低。可以讓你瀟灑的跳過附件維護這個坑。你不用再關心應該給服務器配置多大的硬盤來保存附件,不用再精打細算節約硬盤空間,也不用在擔心附件集中下載影響服務器的帶寬。如果你需要還可以方便的配置CDN加速,大幅提升用戶體驗。主流的附件託管服務就是aws s3和aliyun oss。這兩個的價格基本差不多,基本都是0.1元/GB/月。相對於服務器的成本,這基本可以忽略了。本文只針對aws s3展開,並不涉及aliyun oss,有需要的同學可以自行查看oss文檔,原理基本一樣。
準備工作
首先你需要創建aws賬號,並配置好安全憑證。請參考這裏。
安裝AWS SDK,按照文檔介紹的來就行,只是使用composer安裝sdk時會比較慢,等等就好了。
準備工作都做好了,可以開始碼代碼了。
自定義s3Attachment組件
如果你還不知道yii2中應該如何自定義組件請參考這裏。
我們自定義s3組件的目的是將上傳,刪除等基本功能封裝好,需要的地方直接調用就行。參考s3文檔示例代碼,簡單修改下就能正常使用了。
<?php
namespace common\components;
use Yii;
use Yii\base\Exception;
use yii\base\Component;
use Aws\Sdk;
use Aws\Exception\AwsException;
use Aws\Exception\MultipartUploadException;
class s3Attachment extends Component
{
/*
* 常規上傳附件
*
* @param string $bucket 存儲桶名稱.
* @param string $key 附件公網訪問地址.
* @param string $source_file 待上傳的附件.
* @param string $content_type 附件類型.
* @param string $ACL 訪問控制.
* 如果上傳成功返回公網訪問地址,如果上傳失敗返回false.
*/
public function Upload($bucket, $key, $source_file, $content_type, $ACL)
{
if(empty($bucket) || empty($key) || empty($source_file) || empty($content_type) || empty($ACL)){
return false;
}
try{
$config = [
'region' => Yii::$app->params['S3']['region'],
'version' => Yii::$app->params['S3']['version'],
'credentials' => [
'key' => Yii::$app->params['S3']['access_key_id'],
'secret' => Yii::$app->params['S3']['access_key_secret'],
],
];
$sdk = new Sdk($config);
$client = $sdk->createS3();
$result = $client->putObject([
'Bucket' => $bucket,
'Key' => $key,
'SourceFile' => $source_file,
'ContentType' => $content_type,
'ACL' => Yii::$app->params['S3'][$ACL],
]);
}catch (AwsException $e){
Yii::info('上傳附件失敗,錯誤信息:'.$e->getMessage(), 'exception');
return false;
}
return isset($result['ObjectURL']) ? $key : false;
}
/*
* 刪除附件
*
* @param string $key 附件公網訪問地址.
*/
public function Delete($key)
{
if(empty($key)){
return false;
}
try{
$config = [
'region' => Yii::$app->params['S3']['region'],
'version' => Yii::$app->params['S3']['version'],
'credentials' => [
'key' => Yii::$app->params['S3']['access_key_id'],
'secret' => Yii::$app->params['S3']['access_key_secret'],
],
];
$sdk = new Sdk($config);
$client = $sdk->createS3();
$client->deleteObject([
'Bucket' => Yii::$app->params['S3Bucket'],
'Key' => $key
]);
}catch (AwsException $e){
Yii::info('刪除附件失敗,錯誤信息:'.$e->getMessage(), 'exception');
return false;
}
return true;
}
}
這樣我們根據業務邏輯在需要的調用upload和delete就能實現上傳和刪除附件了。如下示例代碼所示,在controller中調用upload方法就可以實現附件上傳到s3了,然後將s3返回的key保存在數據庫中,在顯示的時候拼接上s3的域名就可以了。
使用自定義組件上傳附件到s3
/*
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate()
{
$model = new Post();
if ($model->load(Yii::$app->request->post())) {
$source_file = UploadedFile::getInstance($model, 'image');
$result = Yii::$app->s3Attachment->Upload($bucket, $key, $source_file, $content_type, $ACL);
if($model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('create', [
'model' => $model,
]);
}
當然刪除也是一樣的道理,文中就不給示例代碼了。關於業務中如何使用文中並不展開,畢竟每個項目的需求都不同,大家根據自己的需求使用吧。
真正的使用環境,以上的給出的示例代碼顯然是不夠的,之後會持續更新進階使用方式。