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}&param=${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策略
}

 

可能有有些还不够完善,有啥问题再继续更新修改吧!!!!!!

 

posted @ 2021-06-25 16:31  WidgetBox  阅读(763)  评论(0编辑  收藏  举报