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

控制器

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

        //上傳回調(diào)的參數(shù),callbackUrl地址,callbackBody回調(diào)接收的參數(shù),callbackBodyType通過POST調(diào)用的回調(diào)函數(shù),所以要設(shè)置這個頭
        $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è)置過期時間
        $now = time();
        $expire = 30; //設(shè)置該policy超時時間是30s. 即這個policy過了這個有效時間泥从,將不能訪問
        $end = $now + $expire;
        $expiration = $this->gmt_iso8601($end);  //進行時間格式的轉(zhuǎn)換

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

        //處理上傳限制條件
        //最大文件大小.用戶可以自己設(shè)置
        $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
        $conditions[] = $condition; //設(shè)定文件大小
        //表示用戶上傳的數(shù)據(jù),必須是以$dir開始, 不然上傳會失敗,這一步不是必須項,只是為了安全起見,防止用戶通過policy上傳到別人的目錄
        $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
        $conditions[] = $start;  //必須以設(shè)定的目錄開頭,防止上傳錯誤
        $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,    //失效時間
            'callback' => $base64_callback_body,  //上傳回調(diào)參數(shù)
            'dir' => $dir     //上傳的目錄
        );
        return response()->json($response);   //返回信息

    }

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

    //測試用的回調(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.驗證簽名
        $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");
        }
    }
}

前臺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"/> 上傳文件名字是隨機文件名, 后綴保留
</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'>開始上傳</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; //初始化過期時間

    /**
     * 發(fā)送ajax請求的函數(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() {
        //可以判斷當前expire是否超過了當前時間,如果超過了當前時間,就重新取一下.3s 做為緩沖
        now = timestamp = Date.parse(new Date()) / 1000;
        if (expire < now + 3) {
            body = send_request(); //發(fā)送ajax請求
            var obj = eval("(" + body + ")");
            //定義全局變量,值為服務(wù)器返回來的值
            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;
    }

    /**
     * 生成隨機文件名,不一定能唯一
     * @param len  名字的長度
     * @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) {  //如果沒有簽名,去請求請求簽名
            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,不然奕筐,默認會返回204
            'callback': callbackbody,
            'signature': signature
        };

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

        up.start();
    }

    //文件上傳對象
    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ī)則
        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 //不允許選取重復文件
        },

        //執(zhí)行上傳的對象
        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ù)
            },

            //上傳進度條
            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訪問用戶設(shè)置的上傳回調(diào)服務(wù)器失敗渊胸,失敗原因是:' + info.response;
                }
                else {
                    document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = info.response;
                }
            },

            //報錯信息
            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選擇的文件后綴不對,可以根據(jù)應(yīng)用情況接剩,在upload.js進行設(shè)置可允許的上傳文件類型"));
                }
                else if (err.code == -602) {
                    document.getElementById('console').appendChild(document.createTextNode("\n這個文件已經(jīng)上傳過一遍了"));
                }
                else {
                    document.getElementById('console').appendChild(document.createTextNode("\nError xml:" + err.response));
                }
            }
        }
    });

    uploader.init();

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

/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懊缺,一起剝皮案震驚了整個濱河市鹃两,隨后出現(xiàn)的幾起案子舀凛,更是在濱河造成了極大的恐慌,老刑警劉巖馋记,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抗果,死亡現(xiàn)場離奇詭異奸晴,居然都是意外死亡日麸,警方通過查閱死者的電腦和手機代箭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門嗡综,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人察净,你說我怎么就攤上這事盼樟。” “怎么了译秦?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵筑悴,是天一觀的道長。 經(jīng)常有香客問我砚婆,道長求摇,這世上最難降的妖魔是什么与境? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任摔刁,我火速辦了婚禮,結(jié)果婚禮上共屈,老公的妹妹穿的比我還像新娘拗引。我一直安慰自己,他們只是感情好壤玫,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布欲间。 她就那樣靜靜地躺著断部,像睡著了一般。 火紅的嫁衣襯著肌膚如雪她渴。 梳的紋絲不亂的頭發(fā)上虱疏,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天做瞪,我揣著相機與錄音对粪,去河邊找鬼右冻。 笑死,一個胖子當著我的面吹牛著拭,可吹牛的內(nèi)容都是我干的纱扭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼儡遮,長吁一口氣:“原來是場噩夢啊……” “哼乳蛾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鄙币,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤肃叶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后因惭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡绩衷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年蹦魔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咳燕。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡勿决,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出招盲,到底是詐尸還是另有隱情低缩,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布曹货,位于F島的核電站表制,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏控乾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一娜遵、第九天 我趴在偏房一處隱蔽的房頂上張望蜕衡。 院中可真熱鬧,春花似錦设拟、人聲如沸慨仿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镰吆。三九已至,卻和暖如春跑慕,著一層夾襖步出監(jiān)牢的瞬間万皿,已是汗流浹背摧找。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留牢硅,地道東北人蹬耘。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像减余,于是被迫代替她去往敵國和親综苔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容