阿里云oss服务端直签使用

ThinkPhp 发表时间:2022-07-15 14:16:32 作者:梁子亮 浏览次数:998

后台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

服务端签名直传并设置上传回调 >概述,

https://help.aliyun.com/document_detail/31927.htm?spm=a2c4g.11186623.0.0.16074a9c2Psl1h#concept-qp2-g4y-5db

服务端签名直传并设置上传回调 >PHP,

https://help.aliyun.com/document_detail/91771.html

注意步骤2中的(下载应用服务器源码(PHP版本))

上一篇   springboot注解