很多网站都会需要文件上传、下载的功能,但是服务器本身配置(如容量、带宽等等)可能扛不住大量的上传、下载,这时候,利用一些现成的云存储服务来分担一下服务器的压力。这里主要介绍一下腾讯云COS的使用,大概的功能流程是:
前端(JS)实现文件上传功能;
后端(PHP)给前端发放签名,使前端可以直接访问COS;
根据COS生成的文件链接访问文件。
PHP后端签名机制
以Laravel项目为例:
首先,在项目目录下,新建目录app/Plugins/Qcloud/Cos;然后,下载COS的PHP SDK,将SDK中src/qcloud/cos下所有文件复制到项目的app/Plugins/Qcloud/Cos下,这里只用到Auth.php。大概代码:
routes/web.php
1
2
3
4<?php
Route::post('/qcloud/cos/sign', 'QcloudController@postCosSign');
Route::post('/qcloud/cos/sign-once', 'QcloudController@postCosSignOnce');
app/Plugins/Qcloud/Cos/Auth.php
1
2
3
4
5
6
7
8
9
10
11<?php
/**
* Signature create related functions for authenticating with cos system.
*/
namespace App\Plugins\QCloud\Cos;// 加上命名空间
/**
* Auth class for creating reusable or nonreusable signature.
*/
class Auth{
...
}
config/web.php
1
2
3
4
5
6
7
8
9
10<?php
return [
'qcloud_cos' => [
'app_id' => '1234567890',
'secret_id' => '************************************',
'secret_key' => '********************************',
'region' => 'gz', //广州
'timeout' => 60
],
];
QcloudController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<?php
use App\Plugins\QCloud\Cos\Auth as CosAuth;
class QcloudController extends Controller{
...
// 多次复用的签名
public function postQcloudCosSign(Request $request){
$team = $this->getAuthUser();
$bucket = $request->input('bucket');
$timeout = time()+2*60*60;
$config = config('web.qcloud_cos');
$cos_auth = new CosAuth($config['app_id'], $config['secret_id'], $config['secret_key']);
$sign = $cos_auth->createReusableSignature($timeout, $bucket);
return $this->responseJSON(['sign'=>$sign]);
}
// 单次使用的签名
public function postQcloudCosSignOnce(Request $request){
$bucket = $request->input('bucket');
$timeout = time()+2*60*60;
$config = config('web.qcloud_cos');
$cos_auth = new CosAuth($config['app_id'], $config['secret_id'], $config['secret_key']);
$sign = $cos_auth->createNonreusableSignature($bucket, '/');
return $this->responseJSON(['sign'=>$sign]);
}
}
JS前端上传文件
下载COS的JS SDK,将SDK中dist/cos-js-sdk-v4.js复制到项目的public/js下,注意使用SDK需要浏览器支持HTML 5
。大概代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Demo请上传
var USERID = $('#user').data('id')
var PREFIX = Date.now()+'_'+USERID+'_'
var COS = new CosCloud({
appid: '1234567890',
bucket: 'public',
region: 'gz',
getAppSign: function (callback){
$.post('/qcloud/cos/sign').done(function (data){
var sign = data.sign
callback(sign)
}).fail(function (){
B.alert('请求失败,稍后再试')
})
},
getAppSignOnce: function (callback){
$.post('/qcloud/cos/sign-once').done(function (data){
var sign = data.sign
callback(sign)
}).fail(function (){
B.alert('请求失败,稍后再试')
})
}
})
$('#do_upload').click(function (){
var $this = $(this)
var files = document.getElementById('upload_file').files
if(!files.length || !files[0]) {
return 0
}
var file = files[0]
if(file.size && file.size < 50*1024*1024) {
$this.prop('disabled', true)
$this.text('开始上传 ')
COS.uploadFile(function (result){
// successCallBack
setTimeout(function(){
$this.prop('disabled', true)
$this.text('请上传 ')
}, 1800)
$this.text('上传成功 ')
}, function (result){
// errorCallBack
setTimeout(function(){
$this.prop('disabled', true)
$this.text('请上传 ')
}, 1800)
$this.text('上传失败 ')
}, function (current){
// progressCallBack
$this.text('正在上传 '+ (current*100).toFixed(1)+'%')
}, COS.bucket, PREFIX+file.name, file, 0)
} else {
B.alert('文件不能大于50MB')
}
})
其他
防盗链
如果不想存在COS上的文件,被其他网站盗用,那么可以在COS后台上给对应的存储痛(Bucket)设置Referer白名单,防止被恶意盗链。当然,伪造Referer的请求应该也防不了。
定时清理
因为前端可以直接与COS连接,上传的文件没有经过后端检验,所以有效的上传文件信息都应该记录在数据库里,然后在每天空闲时段将昨天上传的文件都遍历一遍(文件名前缀设为日期就可以据此检索),不记录在库的、类型不匹配的,体积过大的等此类文件都可以删除。
最后
一个网站本身要实现文件上传、下载功能并不难,但是总是会有各样的隐患(可参考HTTP文件上传的一个后端完善方案(NginX))。于此,借用现成的云存储服务来实现文件上传、下载功能,也是一个不错的可行方案。