单纯的javascript/js上传文件到oss会直接泄漏相应的key/secret等重要信息,所以上传时要先请求下PHP,然后拿着对应的信息就可以直接上传到OSS了。
第1步:上传表单:
<tr><td style="text-align:right;">上传mp3封面:</td><td style="text-align:left;"> <span class="imgs"></span> <span class="imgs_file_btn"> <input type="file" name="file_conver" class="myfile layui-btn layui-btn-primary" value="" > </span> </td></tr>
第2步:
引入我们写好的js文件:
<script src="{$Think.BASE_SITE_ROOT}/static/oss_jq.js?time=1557452966" charset="utf-8"></script>
oss_jq.js内容如下:
;(function ($) { $.fn.extend({ uploadUtil: function uploadUtil(options) { var that = this; $(this).on('change', function (e) { var file = e.target.files[0]; var tokenUrl = options.tokenUrl; var filePrefix = options.filePrefix; var match = options.match; var callback = options.callback; var bucket = options.bucket; if (!bucket) { bucket = 'mymall';//桶 } // 只选择图片文件 if (match) { if (!file.type.match(match)) { return false; } } $.get(tokenUrl, { prefix: filePrefix, bucket: bucket }, function (res) { var ossData = new FormData(); var realFilename = file.type.split('/'); ossData.append('OSSAccessKeyId', res.accessid); ossData.append('policy', res.policy); ossData.append('Signature', res.signature); ossData.append('key', res.dir); ossData.append('success_action_status', 201); // 指定返回的状态码 ossData.append('file', file, filePrefix + res.timestamp + '.' + realFilename[1]); $.ajax({ url: res.host, data: ossData, dataType: 'xml', processData: false, contentType: false, type: 'POST', context: that }).done(function (data) { // 返回的上传信息 if ($(data).find('PostResponse')) { var resq = $(data).find('PostResponse'); var nameKey = $(e.target).attr('id'); that[0].value = ''; $('img[name="' + nameKey + '"]').attr('src', resq.find('Location').text()).show(); $('input[name="' + nameKey + '"]').val(resq.find('Key').text()); if (callback) { callback.apply(this, [res.host, resq.find('Key').text()]); } } }); }, 'json'); }); } }); })(jQuery);
第3步:调用上面的JS写好的方法:
//图片上传 $('input[name="file_conver"]').uploadUtil({ tokenUrl: '/api/oss_token/getToken',//获取oss信息 filePrefix: 'music/{$day}/',//目录前缀,可以自定义 match: 'image.*',//上传要匹配的文件类型 callback: function (imgHost, imgStr) { let arr = imgStr.split('/'); let html = '<img src="' + imgHost + imgStr + '">' + '<input type="hidden" name="image" value="' + imgHost + imgStr + '">';//将上传后的图片显示出来并将值放到隐藏域 $('.imgs').html(html); $('.imgs_file_btn').hide(); } });
第4步:/api/oss_token/getToken取出key/secret代码:
<?php namespace app\api\controller; use think\Controller; class OssToken extends Controller { public function getToken() { $bucket = request()->get('bucket'); $bucket = empty($bucket) ? 'mymall' : $bucket; //自行设置AccessKey和相应Bucket的外网域名 $id = 'OSS后台的id'; $key = 'OSS后台的key'; // h5下去除协议名称,由前端自行决定采用协议的类型 $host = '//'.$bucket.'.阿里云OSS给我们的域名/'; $prefix = request()->get('prefix'); $prefixs = explode('/', $prefix); array_pop($prefixs); $now = time(); $expire = 10; //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问 $end = $now + $expire; $expiration = $this->gmt_iso8601($end); //文件大小范围.用户可以自己设置 $condition = array('content-length-range', 0, 1048576000); //设置用户上传指定的前缀 $dir = 'home/' . implode('/', $prefixs) . '/'; //用户上传数据的位置匹配,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录 $start = array('starts-with', '$key', $dir); //设置bucket $bucket = array('eq', '$bucket', $bucket); $conditions = array($bucket, $condition, $start); $arr = array('expiration'=>$expiration,'conditions'=>$conditions); //echo json_encode($arr); //return; $policy = json_encode($arr); $base64_policy = base64_encode($policy); $signature = base64_encode(hash_hmac('sha1', $base64_policy, $key, true)); $response = array( 'accessid' => $id, 'host' => $host, 'policy' => $base64_policy, 'signature' => $signature, 'expire' => $end, 'timestamp' => date('YmdHis') . mt_rand(10000, 99999), 'dir' => $dir.'${filename}' ); header('Content-Type: application/json;charset=utf-8'); echo json_encode($response); exit; } function gmt_iso8601($time) { $dtStr = date("c", $time); $mydatetime = new \DateTime($dtStr); $expiration = $mydatetime->format(\DateTime::ISO8601); $pos = strpos($expiration, '+'); $expiration = substr($expiration, 0, $pos); return $expiration."Z"; } }
第5步:大功告成。注意:由于是在H5/pc上的代码,返回的文件地址是//开头的协议文件地址,传到PHP后台时,要处理下。不然APP无法识别。
作者:OK兄 浏览次数:78