此次封装的oss直传 使用的是官网Browser.js和layui结合封装的插件。调用方式相对来说简单快捷
1、html是一个上传按钮。这里注意一下两个id,
id="upload-normal" :上传按钮的id。
id="upload-normal-list":上传完图片(文件)展示的地方 这两个是有规则的,必须为上传按钮的id 拼接上 -list
.close_btn{ position: absolute; top:-7px!important; right: -7px!important; background: rgba(0,0,0,0.5); border-radius: 50%; width: 15px; height: 15px; border-radius: 50%; line-height: 15px;}
1 <div class="layui-form-item">
2 <label class="layui-form-label">图片</label>
3 <div class="layui-input-block">
4 <div class="layui-upload">
5 <button type="button" class="layui-btn layui-btn-sm" id="upload-normal">上传图片</button>
6 <div class="layui-upload-list" id="upload-normal-list" style="display: flex; flex-wrap: wrap;">
7 </div>
8 </div>
9 </div>
10 </div>
2、js
首先去官网下载sdk并按照文档引入js
官方链接:https://helpcdn.aliyun.com/document_detail/64041.html?spm=a2c4g.11186623.6.1218.4d8b23f2hNmYrh
封装后的js(注意最好使用layui2.6.5及以上版本 因为他这个版本修复了(这个版本之前的自己去修改下layui.js)
- [修复] form 组件的 name="arr[]" 在元素动态插入后出现序号异常的问题
<script src="src/lib/extend/aliyun-oss-sdk.min.js"></script>
1 layui.extend({}).define(['layer', 'upload', 'setter', 'jquery'], function (exports) {
2 var $ = layui.$,
3 layer = layui.layer,
4 setter = layui.setter,
5 upload = layui.upload,
6 layer = layui.layer;
7
8 var Class = function (options) {
9 var that = this;
10 that.options = options;
11 that.init();
12 };
13
14 Class.prototype.init = function () {
15 var that = this,
16 options = that.options;
17
18 if (!that.strIsNull(that.options.fileType)) {
19 fileType = that.options.fileType;
20 } else {
21 fileType = 'file';
22 }
23
24 if (typeof that.options.uploadRenderData != 'undefined') {
25 uploadRenderData = that.options.uploadRenderData;
26 } else {
27 uploadRenderData = {};
28 }
29
30
31
32 var loadingIndex;
33 var uploadRender = upload.render($.extend({
34 elem: that.options.elm,
35 accept: fileType,
36 multiple: that.options.multiple,
37 auto: false,
38 number: that.options.number ? that.options.number : 0,
39 choose: function (obj) {
40
41 uploadRender.config.elem.next()[0].value = '';
42 let d = new Date();
43 var year = d.getFullYear();
44 var month = d.getMonth() + 1;
45 var day = d.getDate();
46 var folder = that.options.folder ? that.options.folder : 'default';
47 var save_path = folder + '/' + year + '/' + month + day + '/';
48 let admin_info = layui.data(setter.tableName).admin;
49
50 let curFiles = obj.pushFile();
51 var file_length = Object.keys(curFiles).length;
52
53 //loading层
54 loadingIndex = layer.load(2, { //icon支持传入0-2
55 shade: [0.5, '#000'], //0.5透明度的灰色背景
56 content: '上传中...',
57 success: function (layero) {
58 layero.find('.layui-layer-content').css({
59 'padding-top': '39px',
60 'width': '60px'
61 });
62 }
63 });
64
65 obj.preview(function (index, file, result1) {
66 var size = file.size;
67 var file_name = file.name;
68 var file_type = file.type;
69
70 let index1 = file_name.lastIndexOf('.');
71 let file_ext = file_name.substring(index1);
72
73 var code = "";
74 for (var i = 0; i < 6; i++) {
75 var radom = Math.floor(Math.random() * 10);
76 code += radom;
77 }
78 var save_name = d.getTime() + code + file_ext;
79 var storeAs = save_path + save_name;
80
81 var max_size = that.options.max_size ? that.options.max_size : 100 * 1024 * 1024;
82 if (size > max_size) {
83 layer.msg('上传的文件大小超出限制', { icon: 5 });
84 layer.close(loadingIndex);
85 return false;
86 }
87
88 //组装传输的参数,上传后阿里云会带着这些参数访问回掉方法
89 let data_param = {
90 uid: admin_info.uid, //后台操作uid
91 filename: file_name, //文件名称
92 filesize: size, //文件大小
93 file_type: file_type, //文件类型
94 file_ext: file_ext, //文件文件后缀
95 save_name: save_name, //阿里云的保存名称
96 save_path: save_path, //阿里云的保存路径
97 all_path: storeAs, //阿里云全路径
98 };
99
100 //上传
101 OSS.urllib.request('获取你签名的后台地址', { method: 'GET'}, (err, response) => {
102
103
104 if (err) {
105 return alert(err);
106 }
107 try {
108 result = JSON.parse(response);
109 } catch (e) {
110 return alert('parse sts response info error: ' + e.message);
111 }
112 let client = new OSS({
113 accessKeyId: result.data.AccessKeyId,
114 accessKeySecret: result.data.AccessKeySecret,
115 stsToken: result.data.SecurityToken,
116 // region表示您申请OSS服务所在的地域,例如oss-cn-hangzhou。
117 region: '',
118 bucket: ''
119 });
120
121 //记录断点
122 if (!tempCheckpoint) {
123 var tempCheckpoint;
124 }
125 // storeAs可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或Bucket下的指定目录。
126 // file可以自定义为File对象、Blob数据以及OSS Buffer。
127 client.multipartUpload(storeAs, file, {
128 progress: async function (p, checkpoint) {
129 tempCheckpoint = checkpoint;
130 },
131 parallel: that.options.parallel ? that.options.parallel : 1,
132 partSize: that.options.partSize ? that.options.partSize : 102400,
133 checkpoint: tempCheckpoint,
134 callback: {
135 url: setter.callback_api_url + '/admin/CommonOss/callbackFile',
136 body: 'bucket=${bucket}&object=${object}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}¶m=${x:param}',
137 contentType: 'application/x-www-form-urlencoded',
138 customValue: {
139 'param': JSON.stringify(data_param)
140 }
141 },
142 }).then(function (result) {
143
144 var list_id = that.options.elm + '-list';
145
146 var orgin_res = result.data.data;
147 if (!orgin_res) {
148 layer.msg('上传失败', { icon: 5, time: 1500 });
149 layer.close(loadingIndex);
150 }
151
152 var img_type = '';
153 var image_type = orgin_res.file_type;
154 img_type = image_type.split('/')[0];
155
156 html = '';
157 html1 = '';
158 attach_name = that.options.attach_name ? that.options.attach_name : '';
159 if (that.options.multiple) {
160 html1 += '<input type="hidden" name="' + attach_name + '[]" value="' + orgin_res.attach_id + '">';
161 } else {
162 html1 += '<input type="hidden" name="' + attach_name + '" value="' + orgin_res.attach_id + '">'
163 }
164
165
166 if (img_type == 'image') {
167
168 html += '<div style="position:relative; width: 100px; margin:0 10px 10px 0;">' +
169 '<img src="' + orgin_res.full_path + '" alt="" width="100" class="view_btn">' +
170 '<i class="layui-icon close_btn close_blog" close="">ဆ</i>' + html1 +
171 '</div>';
172
173 } else if (img_type == 'video') {
174
175 html += '<div style="position:relative; width: 150px; margin:0 10px 10px 0;">' +
176 '<video src="' + orgin_res.full_path + '" width="150" controls="controls"></video>' +
177 '<i class="layui-icon close_btn close_blog" close="">ဆ</i>' + html1 +
178 '</div>';
179 } else {
180
181 html += '<div>' +
182 '<a href="' + orgin_res.full_path + '">' + orgin_res.filename + '</a>' +
183 '<span class="close_blog" style="margin-left: 15px;color:red; cursor:pointer">删除</span>' + html1 +
184 '</div>';
185 }
186
187
188
189 if (that.options.multiple) {
190 $(list_id).append(html);
191 } else {
192 $(list_id).html(html);
193 }
194
195 if (Object.keys(curFiles).length > 0) {
196 delete curFiles[index]
197 file_length--
198 if (file_length == 0) {
199 layer.close(loadingIndex);
200 }
201 }
202
203
204
205 }).catch(function (err) {
206 console.log(err);
207 layer.msg('上传失败', { icon: 5, time: 1500 });
208 layer.close(loadingIndex);
209 });
210 });
211
212 });
213 }
214
215 }), uploadRenderData);
216
217 };
218
219
220
221 Class.prototype.strIsNull = function (str) {
222 if (typeof str == "undefined" || str == null || str == "")
223 return true;
224 else
225 return false;
226 };
227
228 var aliossUpload = {
229 render: function (options) {
230 var inst = new Class(options);
231 return inst;
232 }
233 };
234
235
236 $(document).on('click', ".close_blog", function () {
237 $(this).parent().remove();
238 });
239
240 $(document).on('click', ".view_btn", function () {
241 var attach_url = $(this)[0].src
242 window.open(attach_url);
243 });
244
245 exports('aliossUpload', aliossUpload);
246
247
248 })
3、调用方式
1 layui.define(['jquery','upload', 'form', 'aliossUpload'], function (exports) {
2 var $ = layui.jquery
3 , aliossUpload = layui.aliossUpload
4
5 aliossUpload.render({
6 elm: '#upload-normal', //上传按钮id
7 fileType: 'images', //限制上传类型
8 multiple: false, //单图or 多图
9 attach_name:'image', //上传input的name值
10 folder: 'slide', //上传oss目录
11 number: 1 //设置同时可上传的文件数量,一般配合 multiple 参数出现。0(即不限制)
12 });
13
14 exports('slide_upload', {})
15 });
以上是前端上传的代码及调用方式。接下来稍微简单说一下后代返回的签名及上传回调
你可以使用官网php的sdk,也可以用composer安装
我使用的是composer
composer require aliyunsts/aliyun-sts
1、 获取签名代码:
public function sts()
{
$config = config("aliyun.oss_sts");
$AccessKeyID = $config['AccessKeyID'];
$AccessKeySecret = $config['AccessKeySecret'];
$roleArn = $config['RoleArn'];
$RoleSessionName = $config['RoleSessionName'];
$tokenExpire = $config['DurationSeconds'];
$policy = $this->_getPolicy();
$iClientProfile = DefaultProfile::getProfile("cn-beijing", $AccessKeyID, $AccessKeySecret);
$client = new DefaultAcsClient($iClientProfile);
$request = new AssumeRoleRequest();
$request->setRoleSessionName($RoleSessionName);
$request->setRoleArn($roleArn);
$request->setPolicy($policy);
$request->setDurationSeconds($tokenExpire);
$response = $client->doAction($request);
$rows = array();
$body = $response->getBody();
$content = json_decode($body);
$rows['status'] = $response->getStatus();
if ($response->getStatus() == 200) {
$rows['AccessKeyId'] = $content->Credentials->AccessKeyId;
$rows['AccessKeySecret'] = $content->Credentials->AccessKeySecret;
$rows['Expiration'] = $content->Credentials->Expiration;
$rows['SecurityToken'] = $content->Credentials->SecurityToken;
return $this->jsonSuccess($rows);
}
return $this->jsonError($content->Message);
}
2、aliyun文件回调
public function callbackFile()
{
$is_success = false;
try {
// 1.获取OSS的签名header和公钥url header
$authorizationBase64 = "";
$pubKeyUrlBase64 = "";
/*
* 注意:如果要使用HTTP_AUTHORIZATION头,你需要先在apache或者nginx中设置rewrite,以apache为例,修改
* 配置文件/etc/httpd/conf/httpd.conf(以你的apache安装路径为准),在DirectoryIndex index.php这行下面增加以下两行
RewriteEngine On
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
* */
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$authorizationBase64 = $_SERVER['HTTP_AUTHORIZATION'];
}
if (isset($_SERVER['HTTP_X_OSS_PUB_KEY_URL'])) {
$pubKeyUrlBase64 = $_SERVER['HTTP_X_OSS_PUB_KEY_URL'];
}
if ($authorizationBase64 == '' || $pubKeyUrlBase64 == '') {
header("http/1.1 403 Forbidden");
exit();
}
// 2.获取OSS的签名
$authorization = base64_decode($authorizationBase64);
// 3.获取公钥
$pubKeyUrl = base64_decode($pubKeyUrlBase64);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $pubKeyUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
$pubKey = curl_exec($ch);
if ($pubKey == "") {
//header("http/1.1 403 Forbidden");
exit();
}
// 4.获取回调body
$body = file_get_contents('php://input');
trace($body, __METHOD__);
// 5.拼接待签名字符串
$path = $_SERVER['REQUEST_URI'];
$pos = strpos($path, '?');
if ($pos === false) {
$authStr = urldecode($path) . "\n" . $body;
} else {
$authStr = urldecode(substr($path, 0, $pos)) . substr($path, $pos, strlen($path) - $pos) . "\n" . $body;
}
// 6.验证签名
$ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
if (empty($ok)) {
throw new Exception('验证签名失败');
}
// 7.处理相关业务
$is_success = true;
} catch (\Exception $e) {
$body = file_get_contents('php://input');
$res = 'oss callback error' . $e->getMessage() . $e->getLine();
Log::record($res . ",data:" . json_encode($body), 'warning');
}
if ($is_success) {
return $this->jsonSuccess($res);
} else {
return $this->jsonError($res);
}
}
sts策略
private function _getPolicy(){
//你的sts策略
}
可能有有些还不够完善,有啥问题再继续更新修改吧!!!!!!