layui OSS Web直传
此次封装的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策略 }
可能有有些还不够完善,有啥问题再继续更新修改吧!!!!!!