在laravel中使用OSS上傳回調(diào) WEB直傳

控制器

/**
 * 阿里OSS后臺(tái)簽名并進(jìn)行上傳回調(diào)
 * Class UploadController
 * @package App\Http\Controllers
 */
class UploadController extends Controller
{
    /**
     * 返回OSS的簽名驗(yàn)證
     * @return JSON 簽名信息
     */
    public function getGetkey(Request $request)
    {
        //初始化一下必要的請(qǐng)求數(shù)據(jù)
        $id = env('ACCESSKEYID');   //AccessKeyId
        $key = env('ACCESSKEYSECRET');  //AccessKeySecret
        $host = 'http://outside-leader.oss-cn-qingdao.aliyuncs.com';  //OSS庫(kù)地址
        $callbackUrl = url('upload/callback');  //上傳回調(diào)的地址

        //上傳回調(diào)的參數(shù),callbackUrl地址,callbackBody回調(diào)接收的參數(shù),callbackBodyType通過(guò)POST調(diào)用的回調(diào)函數(shù),所以要設(shè)置這個(gè)頭
        $callback_param = array(
            'callbackUrl' => $callbackUrl,
            'callbackBody' => 'filename=${object}&size=${size}&mimeType =${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
            'callbackBodyType' => "application/x-www-form-urlencoded"
        );
        $callback_string = json_encode($callback_param);  //轉(zhuǎn)換成json格式
        $base64_callback_body = base64_encode($callback_string); //要返回的回調(diào)函數(shù)參數(shù)信息

        //設(shè)置過(guò)期時(shí)間
        $now = time();
        $expire = 30; //設(shè)置該policy超時(shí)時(shí)間是30s. 即這個(gè)policy過(guò)了這個(gè)有效時(shí)間,將不能訪(fǎng)問(wèn)
        $end = $now + $expire;
        $expiration = $this->gmt_iso8601($end);  //進(jìn)行時(shí)間格式的轉(zhuǎn)換

        $dir = $request['dir'];  //上傳目錄設(shè)置

        //處理上傳限制條件
        //最大文件大小.用戶(hù)可以自己設(shè)置
        $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
        $conditions[] = $condition; //設(shè)定文件大小
        //表示用戶(hù)上傳的數(shù)據(jù),必須是以$dir開(kāi)始, 不然上傳會(huì)失敗,這一步不是必須項(xiàng),只是為了安全起見(jiàn),防止用戶(hù)通過(guò)policy上傳到別人的目錄
        $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
        $conditions[] = $start;  //必須以設(shè)定的目錄開(kāi)頭,防止上傳錯(cuò)誤
        $arr = array('expiration' => $expiration, 'conditions' => $conditions);
        $policy = json_encode($arr);
        $base64_policy = base64_encode($policy);  //要返回的上傳限制參數(shù)

        //簽名信息
        $string_to_sign = $base64_policy;
        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true));  //要返回的簽名信息

        //設(shè)置返回信息
        $response = array(
            'accessid' => $id,  //accessid
            'host' => $host,    //上傳地址
            'policy' => $base64_policy,  //上傳文件限制
            'signature' => $signature,   //簽名信息
            'expire' => $end,    //失效時(shí)間
            'callback' => $base64_callback_body,  //上傳回調(diào)參數(shù)
            'dir' => $dir     //上傳的目錄
        );
        return response()->json($response);   //返回信息

    }

    //格式化時(shí)間,格式為2016-07-07T23:48:43Z
    function gmt_iso8601($time)
    {
        $dtStr = date("c", $time);
        $pos = strpos($dtStr, '+');
        $expiration = substr($dtStr, 0, $pos);
        return $expiration . "Z";
    }

    //測(cè)試用的回調(diào)函數(shù)
    public function postCallback(Request $request)
    {
        // 1.獲取OSS的簽名header和公鑰url header
        $authorizationBase64 = "";
        $pubKeyUrlBase64 = "";
        if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $authorizationBase64 = $_SERVER['HTTP_AUTHORIZATION'];
        }
        if (isset($_SERVER['HTTP_X_OSS_PUB_KEY_URL'])) {
            $pubKeyUrlBase64 = $_SERVER['HTTP_X_OSS_PUB_KEY_URL'];
        }
        if ($authorizationBase64 == '' || $pubKeyUrlBase64 == '') {
            header("http/1.1 403 Forbidden");
            exit();
        }

        // 2.獲取OSS的簽名
        $authorization = base64_decode($authorizationBase64);  //OSS簽名

        // 3.獲取公鑰
        $pubKeyUrl = base64_decode($pubKeyUrlBase64);  //公鑰的URL
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $pubKeyUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        $pubKey = curl_exec($ch);
        if ($pubKey == "") {
            exit();   //header("http/1.1 403 Forbidden");
        }

        // 4.獲取回調(diào)body,上傳的圖片的相關(guān)信息都在這里
        $body = file_get_contents('php://input');

        // 5.拼接待簽名字符串
        $authStr = '';
        $path = $_SERVER['REQUEST_URI'];
        $pos = strpos($path, '?');
        if ($pos === false) {
            $authStr = urldecode($path) . "\n" . $body;
        } else {
            $authStr = urldecode(substr($path, 0, $pos)) . substr($path, $pos, strlen($path) - $pos) . "\n" . $body;
        }

        // 6.驗(yàn)證簽名
        $ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
        if ($ok == 1) {
            header("Content-Type: application/json");
            $data = array("Status" => "Ok");
            return response()->json($data);
        } else {
            exit(); //header("http/1.1 403 Forbidden");
        }
    }
}

前臺(tái)html

<!DOCTYPE html>
<html>
<head>
    <title>阿里OSS</title>
    <meta charset="utf-8"/>
</head>
<body>

<form name=theform>
    <input type="radio" name="myradio" value="local_name" checked=true/> 上傳文件名字保持本地文件名字
    <input type="radio" name="myradio" value="random_name"/> 上傳文件名字是隨機(jī)文件名, 后綴保留
</form>

<h4>您所選擇的文件列表:</h4>
<div id="ossfile">你的瀏覽器不支持flash,Silverlight或者HTML5!</div>

<br/>


<div id="container">
    <a id="selectfiles" href="javascript:void(0);" class='btn'>選擇文件</a>
    <a id="postfiles" href="javascript:void(0);" class='btn'>開(kāi)始上傳</a>
</div>

<pre id="console"></pre>

<p>&nbsp;</p>

<script type="text/javascript" src="{{ asset('assets/plupload/js/plupload.full.min.js') }}"></script>
<script>
    var expire = 0; //初始化過(guò)期時(shí)間

    /**
     * 發(fā)送ajax請(qǐng)求的函數(shù)
     * @returns Json 服務(wù)器返回的簽名
     */
    function send_request() {
        var xmlhttp = null;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        }
        else if (window.ActiveXObject) {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        if (xmlhttp != null) {
            var serverUrl = '{{ url('upload/key?dir=') }}';
            xmlhttp.open("GET", serverUrl, false);
            xmlhttp.send(null);
            return xmlhttp.responseText;
        } else {
            alert("Your browser does not support XMLHTTP.");
        }
    }

    /**
     * 選擇服務(wù)器端保存文件名的方式
     */
    function check_object_radio() {
        var tt = document.getElementsByName('myradio');
        for (var i = 0; i < tt.length; i++) {
            if (tt[i].checked) {
                g_object_name_type = tt[i].value;
                break;
            }
        }
    }

    /**
     * 從服務(wù)器獲取簽名之后,定義全局變量
     * @returns {boolean}
     */
    function get_signature() {
        //可以判斷當(dāng)前expire是否超過(guò)了當(dāng)前時(shí)間,如果超過(guò)了當(dāng)前時(shí)間,就重新取一下.3s 做為緩沖
        now = timestamp = Date.parse(new Date()) / 1000;
        if (expire < now + 3) {
            body = send_request(); //發(fā)送ajax請(qǐng)求
            var obj = eval("(" + body + ")");
            //定義全局變量,值為服務(wù)器返回來(lái)的值
            host = obj['host'];
            policyBase64 = obj['policy'];
            accessid = obj['accessid'];
            signature = obj['signature'];
            expire = parseInt(obj['expire']);
            callbackbody = obj['callback'];
            key = obj['dir'];
            return true;
        }
        return false;
    }

    /**
     * 生成隨機(jī)文件名,不一定能唯一
     * @param len  名字的長(zhǎng)度
     * @returns {string}
     */
    function random_string(len) {
        len = len || 32;
        var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
        var maxPos = chars.length;
        var pwd = '';
        for (i = 0; i < len; i++) {
            pwd += chars.charAt(Math.floor(Math.random() * maxPos));
        }
        return pwd;
    }

    /**
     *
     * @param filename
     * @returns {string}
     */
    function get_suffix(filename) {
        pos = filename.lastIndexOf('.');
        suffix = '';
        if (pos != -1) {
            suffix = filename.substring(pos)
        }
        return suffix;
    }

    /**
     * 根據(jù)選擇文件名的方式處理文件名
     * @param filename
     * @returns {string}
     */
    function calculate_object_name(filename) {
        if (g_object_name_type == 'local_name') {
            g_object_name += "${filename}"
        }
        else if (g_object_name_type == 'random_name') {
            suffix = get_suffix(filename);
            g_object_name = key + random_string(10) + suffix
        }
        return '';
    }

    //獲取上傳文件的名字
    function get_uploaded_object_name(filename) {
        if (g_object_name_type == 'local_name') {
            tmp_name = g_object_name;
            tmp_name = tmp_name.replace("${filename}", filename);
            return tmp_name;
        }
        else if (g_object_name_type == 'random_name') {
            return g_object_name;
        }
    }

    //設(shè)置文件上傳到OSS需要的參數(shù)
    function set_upload_param(up, filename, ret) {
        if (ret == false) {  //如果沒(méi)有簽名,去請(qǐng)求請(qǐng)求簽名
            ret = get_signature()
        }
        g_object_name = key; //
        if (filename != '') {
            suffix = get_suffix(filename);
            calculate_object_name(filename)
        }
        new_multipart_params = {
            'key': g_object_name,
            'policy': policyBase64,
            'OSSAccessKeyId': accessid,
            'success_action_status': '200', //讓服務(wù)端返回200,不然,默認(rèn)會(huì)返回204
            'callback': callbackbody,
            'signature': signature
        };

        up.setOption({
            'url': host,
            'multipart_params': new_multipart_params
        });

        up.start();
    }

    //文件上傳對(duì)象
    var uploader = new plupload.Uploader({
        runtimes: 'html5,flash,silverlight,html4',  //設(shè)置支持上傳的協(xié)議
        browse_button: 'selectfiles',
        //multi_selection: false,       //是否允許多文件上傳
        container: document.getElementById('container'),
        flash_swf_url: '{{ asset('plupload/js/Moxie.swf') }}',
        silverlight_xap_url: '{{ asset('plupload/js/Moxie.xap') }}',
        url: 'http://oss.aliyuncs.com',

        //文件過(guò)濾規(guī)則
        filters: {
            mime_types: [ //只允許上傳圖片和zip文件
                {title: "Image files", extensions: "jpg,gif,png,bmp"},
                {title: "Zip files", extensions: "zip,rar"}
            ],
            max_file_size: '3mb', //最大只能上傳3mb的文件
            prevent_duplicates: true //不允許選取重復(fù)文件
        },

        //執(zhí)行上傳的對(duì)象
        init: {
            //一初始化就執(zhí)行的函數(shù)
            PostInit: function () {
                document.getElementById('ossfile').innerHTML = '';
                document.getElementById('postfiles').onclick = function () {
                    set_upload_param(uploader, '', false);
                    return false;
                };
            },

            //一選擇文件就執(zhí)行的函數(shù)
            FilesAdded: function (up, files) {
                plupload.each(files, function (file) {
                    document.getElementById('ossfile').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ')<b></b>'
                            + '<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>'
                            + '</div>';
                });
            },

            //上傳之前執(zhí)行的函數(shù)
            BeforeUpload: function (up, file) {
                check_object_radio();  //選擇文件名
                set_upload_param(up, file.name, true);  //設(shè)置上傳參數(shù)
            },

            //上傳進(jìn)度條
            UploadProgress: function (up, file) {
                var d = document.getElementById(file.id);
                d.getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
                var prog = d.getElementsByTagName('div')[0];
                var progBar = prog.getElementsByTagName('div')[0]
                progBar.style.width = 2 * file.percent + 'px';
                progBar.setAttribute('aria-valuenow', file.percent);
            },

            //執(zhí)行文件上傳
            FileUploaded: function (up, file, info) {
                if (info.status == 200) {
                    document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = 'upload to oss success, object name:' + get_uploaded_object_name(file.name) + ' 回調(diào)服務(wù)器返回的內(nèi)容是:' + info.response;
                }
                else if (info.status == 203) {
                    document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '上傳到OSS成功,但是oss訪(fǎng)問(wèn)用戶(hù)設(shè)置的上傳回調(diào)服務(wù)器失敗,失敗原因是:' + info.response;
                }
                else {
                    document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = info.response;
                }
            },

            //報(bào)錯(cuò)信息
            Error: function (up, err) {
                if (err.code == -600) {
                    document.getElementById('console').appendChild(document.createTextNode("\n選擇的文件太大了,可以根據(jù)應(yīng)用情況,在upload.js 設(shè)置一下上傳的最大大小"));
                }
                else if (err.code == -601) {
                    document.getElementById('console').appendChild(document.createTextNode("\n選擇的文件后綴不對(duì),可以根據(jù)應(yīng)用情況,在upload.js進(jìn)行設(shè)置可允許的上傳文件類(lèi)型"));
                }
                else if (err.code == -602) {
                    document.getElementById('console').appendChild(document.createTextNode("\n這個(gè)文件已經(jīng)上傳過(guò)一遍了"));
                }
                else {
                    document.getElementById('console').appendChild(document.createTextNode("\nError xml:" + err.response));
                }
            }
        }
    });

    uploader.init();

</script>
</body>
</html>

/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容