单纯的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无法识别。 |