后台PHP生成策略,以及签名,设置有效期
// 获取上传策略签名 $type=null默认上传到app文件夹,$type=1为上传到log文件夹(供机器使用)
public function getOssPolicy ($type=null) {
$config = config('ali.');
$id= $config['zmkm_ram_key']; // 请填写您的AccessKeyId。
$key= $config['zmkm_ram_secret']; // 请填写您的AccessKeySecret。
// $host的格式为 bucketname.endpoint,请替换为您的真实信息。
$host = 'https://' . $config['bucket_endpoint'];
// $callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实URL信息。
$web_site = config('common.web_site');
$callbackUrl = $web_site . '/api/notify/ali_oss_url';
$dir = $type == 1?'log/'.date('Ymd').'':'app'; // 用户上传文件时指定的前缀。
$callback_string = '{
"callbackUrl" : "'.$callbackUrl.'",
"callbackBody" : "{\"bucket\":${mimeType}, \"object\":${object},\"size\":${size},\"mimeType\":${mimeType},\"my_var\":${x:my_var}}",
"callbackBodyType" : "application/json"
}';
$base64_callback_body = base64_encode($callback_string);
$now = time();
$expire = 30; //设置该policy超时时间是30秒. 即这个policy过了这个有效时间,将不能访问。
$end = $now + $expire;
$expiration = gmt_iso08($end);
//最大文件大小.用户可以自己设置
$condition = array(0=>'content-length-range', 1=>0, 2=>1048576000);
$conditions[] = $condition;
// 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。
$start = array(0=>'starts-with', 1=>'$key', 2=>$dir);
$conditions[] = $start;
$arr = array('expiration'=>$expiration,'conditions'=>$conditions);
$policy = json_encode($arr);
$base64_policy = base64_encode($policy);
$string_to_sign = $base64_policy;
$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true));
$response = array();
$response['accessid'] = $id;
$response['host'] = $host;
$response['policy'] = $base64_policy;
$response['signature'] = $signature;
$response['expire'] = $end;
$response['callback'] = $base64_callback_body;
$response['dir'] = $dir; // 这个参数是设置用户上传文件时指定的前缀。
return $response;
}注意$dir不能以斜杠 / 开头,最好也不要以斜杠 / 结束否则,可能会报以下错误
<Error><Code>InvalidObjectName</Code> <Message>The specified object is not valid.</Message> <RequestId>62CFDC594931713732A003F5</RequestId> <HostId>bucket.zhimeikm.com</HostId> <ObjectName>/log/20220714/1657789530867.png</ObjectName> </Error>
或者
<Error><Code>AccessDenied</Code> <Message>Invalid according to Policy: Policy Condition failed: ["starts-with", "$key", "/log/20220714/"]</Message> <RequestId>62CFDEA8DDEEC03330E9CB4E</RequestId> <HostId>bucket.zhimeikm.com</HostId> </Error>
设置失效时间为当前时间+30秒,注意阿里云oss接受的失效时间为UTC国际协调时间,与东八区时间相差8小时,因此转化为UTC标准时间的函数为
function gmt_iso08($time){
return str_replace('+00:00', '.000Z', gmdate('c', $time));
}另外,callback url中,必须返回json格式
public function ali_oss_url () {
$postStr = file_get_contents("php://input");
putArray($postStr,'ali_oss_url',Cache::get('put_array_num'),'aaa');
$param = request()->param();
putArray($param,'$param',Cache::get('put_array_num'),'aaa');
header('Content-type: application/json; charset=UTF-8');
$data['code'] = 200;
$data['message'] = "message";
$data['data'] = 1;
echo json_encode($data);
die;
}否则,阿里云oss上传会返回会报错
<Error><Code>CallbackFailed</Code> <Message>Response body is not valid json format.</Message> <RequestId>62CFE3B90059583335DD2265</RequestId> <HostId>bucket.zhimeikm.com</HostId> </Error>
前端使用此签名,策略,callback 等参数上传
<script>
//发送ajax获取服务端签名
function getOssSignature(){
var file = $('#files').get(0).files[0];//获取需要上传的文件对象
console.log(file)
//检测文件是否存在
if(!file){
alert('请先选择文件');
return false;
}
//检测是否没有输入OSS文件路径
if(!$('#dir').val()){
alert('请填写上传至OSS的文件夹路径');
return false;
}
var dir = $('#dir').val() + '/';
//获取上传的文件名,并得到文件后缀
var location=$("#files").val();
var point = location.lastIndexOf(".");
var file_type = location.substr(point);//获取文件后缀
var file_name = dir + (new Date()).getTime() + file_type;//将OSS文件路径与新的文件名拼接在一起,生成新的路径+文件名
//发送ajax请求我方php后端获取上传OSS时必要的参数信息
res = {
"accessid": "LTAI4GG993RoqYyvRmT6n6Z5",
"host": "https://bucket.zhimeikm.com",
"policy": "eyJleHBpcmF0aW9uIjoiMjAyMi0wNy0xNVQwMzowNzoxNi4wMDBaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCJsb2dcLzIwMjIwNzE1Il1dfQ==",
"signature": "KahAf16bygALsOGi9IRuuvyqK6k=",
"expire": 1657883236,
"callback": "ewogICAgImNhbGxiYWNrVXJsIiA6ICJodHRwczovL3Rlc3QubHppYW5nLmNvbS9hcGkvbm90aWZ5L2FsaV9vc3NfdXJsIiwKICAgICJjYWxsYmFja0JvZHkiIDogIntcImJ1Y2tldFwiOiR7bWltZVR5cGV9LCBcIm9iamVjdFwiOiR7b2JqZWN0fSxcInNpemVcIjoke3NpemV9LFwibWltZVR5cGVcIjoke21pbWVUeXBlfSxcIm15X3ZhclwiOiR7eDpteV92YXJ9fSIsCiAgICAiY2FsbGJhY2tCb2R5VHlwZSIgOiAiYXBwbGljYXRpb24vanNvbiIKfQ==",
"dir": "log/20220715"
};
console.log(111111)
console.log(file_name)
//上返回的参数使用formData中
let formData = new FormData();
formData.append('key', file_name);
formData.append('OSSAccessKeyId', res.accessid);
formData.append('policy', res.policy);
formData.append('Signature', res.signature);
formData.append('callback', res.callback);
formData.append('success_action_status', 200); // 成功后返回的操作码
formData.append('file', file);
//接收到服务端返回的签名参数,开始通过另一个Ajax请求来上传文件到OSS
//成功获取签名后上传文件到阿里云OSS
$.ajax({
type : "POST", //提交方式
url : res.host,//路径
dataType:'JSON',
processData: false,
cache: false,
async: false,
contentType: false,
//关键是要设置contentType 为false,不然发出的请求头 没有boundary
//该参数是让jQuery去判断contentType
data : formData,//要发送到OSS数据,使用我这个ajax的格式可避开跨域问题。
success : function(res2) {//返回数据根据结果进行相应的处理
console.log(res2);//返回success:ok 说明你就上传成功了
}
});
}
</script>参考链接:
上传回调中的常见错误及分析处理,
https://help.aliyun.com/document_detail/50092.html
服务端签名直传并设置上传回调 >概述,
服务端签名直传并设置上传回调 >PHP,
https://help.aliyun.com/document_detail/91771.html
注意步骤2中的(下载应用服务器源码(PHP版本))