后台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版本))