1. 程式人生 > >微信小程式/網站 上傳圖片到騰訊雲COS

微信小程式/網站 上傳圖片到騰訊雲COS

COS簡介: 騰訊雲提供的一種物件儲存服務,供開發者儲存海量檔案的分散式儲存服務。可以將自己開發的應用的儲存部分全部接入COS的儲存桶中,有效減少應用伺服器的頻寬消耗等。個人也可以通過騰訊雲賬號免費使用COS6個月,https://cloud.tencent.com/product/cos

整體流程簡介: 

1. 前端引入cos的SDK檔案

2. 監聽上傳控制元件,並在圖片載入至網頁臨時流中發起簽名請求

3.後端根據上傳的請求方式和路徑引數返回簽名Authorization和token XCosSecurityToken

4.前端再根據返回的引數和SDK以3的請求方式上傳圖片。

PHP簽名返回流程:

1.在騰訊雲的建好儲存桶並配置CORS規則https://cloud.tencent.com/document/product/436/11459

2.在平臺上拿到Bucket(儲存桶),Region(地域),SecretId,SecretKey等引數。

3.使用(SecretId,Timestamp…)引數進行簽名通過騰訊雲的介面獲取臨時金鑰,返回給前端的token也在臨時金鑰

4.根據前端傳的(上傳請求方式,路徑)和臨時金鑰進行簽名(前端上傳所使用的)並返回。

一、PHP獲取簽名部分(tp5)

<?php
// +----------------------------------------------------------------------
// | When work is a pleasure, life is a joy!
// +----------------------------------------------------------------------
// | User: 傅超| Email:[email protected] | Time:2018/04/21 17:55 // +---------------------------------------------------------------------- // | TITLE: 小程式介面 // +---------------------------------------------------------------------- namespace app\v1\controller; use think\Request; use think\Db; use app\v1\location
\Location; use think\Cache; use \app\v1\auth\AccessToken; use \app\v1\extend\Loginlog; // 返回資料給前端 header('Content-Type: application/json'); header('Allow-Control-Allow-Origin: *'); // 這裡修改允許跨域訪問的網站 // header('Allow-Control-Allow-Origin: http://127.0.0.1'); // 這裡修改允許跨域訪問的網站 //header('Allow-Control-Allow-Origin: http://mer.runmoneyin.com'); // 這裡修改允許跨域訪問的網站 header('Allow-Control-Allow-Headers: origin,accept,content-type'); /** * Class Cosauth * @title 獲取騰訊雲cos簽名介面 * @url http://119.29.10.64/v1/Cosauth * @desc 小程式介面包含:獲取上傳圖片簽名 * @version 1.0 */ classCosauthextendsBase{ // 附加方法 protected $extraActionList = ['getCosAuth', 'getCosAuth']; // 跳過驗證方法 protected $skipAuthActionList = ['getCosAuth', 'getCosAuthEsay']; // appid //protected $appid = 'wx4c0e1852239664b4'; // cos配置引數 protected $config = array( 'Url' => 'https://sts.api.qcloud.com/v2/index.php', 'Domain' => 'sts.api.qcloud.com', 'Proxy' => '', 'SecretId' => 'AK********************BLK9nF5dZL', // 固定金鑰 'SecretKey' => 'jHj5G*********************IUcqJu', // 固定金鑰 'Bucket' => 'activity-1255484416', // 儲存桶 'Region' => 'ap-guangzhou', 'AllowPrefix' => '*', // 這裡改成允許的路徑字首,這裡可以根據自己網站的使用者登入態判斷允許上傳的目錄,例子:* 或者 a/* 或者 a.jpg ); /** * @title 獲取簽名入口 * http://119.29.10.64/v1/Cosauth/getCosAuth */ public functiongetCosAuth(){ // $data['say'] = 'hello'; // echo json_encode($data); // die; // 快取臨時金鑰 if (!isset($_SESSION['tempKeysCache'])) { $_SESSION['tempKeysCache'] = array( 'policyStr' => '', 'expiredTime' => 0 ); } // 獲取前端過來的引數 // $method = isset($_GET['method']) ? $_GET['method'] : 'get'; // $pathname = isset($_GET['pathname']) ? $_GET['pathname'] : '/'; $method = input('method') ? input('method') : 'post'; $pathname = input('pathname') ? input('pathname') : '/'; $callback = input('callback') ? input('callback') : ''; // 前端跨域的jsonp引數(可忽略) // 獲取臨時金鑰,計算簽名 $tempKeys = $this->getTempKeys(); if ($tempKeys && $tempKeys['credentials']) { // $datas = $this->getAuthorization($tempKeys, $method, $pathname); // echo json_encode($datas); // die; $data = array( 'Authorization' => $this->getAuthorization($tempKeys, $method, $pathname), 'XCosSecurityToken' => $tempKeys['credentials']['sessionToken'], ); } else { $data = array('error'=> $tempKeys); } //echo $callback . '(' . json_encode($data) . ')'; // 通過回撥返回給其他域(可忽略) echo json_encode($data); // 正常寫法的返回 die; } // json 轉 query string public functionjson2str($obj, $notEncode = false){ ksort($obj); $arr = array(); foreach ($obj as $key => $val) { !$notEncode && ($val = urlencode($val)); array_push($arr, $key . '=' . $val); } return join('&', $arr); } // 計算臨時金鑰用的簽名 public functiongetSignature($opt, $key, $method){ //global $config; $formatString = $method . $this->config['Domain'] . '/v2/index.php?' . $this->json2str($opt, 1); $sign = hash_hmac('sha1', $formatString, $key); $sign = base64_encode(hex2bin($sign)); return $sign; } // 獲取臨時金鑰 public functiongetTempKeys(){ //global $config; // 判斷是否修改了 AllowPrefix if ($this->config['AllowPrefix'] === '_ALLOW_DIR_/*') { return array('error'=> '請修改 AllowPrefix 配置項,指定允許上傳的路徑字首'); } $ShortBucketName = substr($this->config['Bucket'],0, strripos($this->config['Bucket'], '-')); $AppId = substr($this->config['Bucket'], 1 + strripos($this->config['Bucket'], '-')); $policy = array( 'version'=> '2.0', 'statement'=> array( array( 'action'=> array( // 簡單檔案操作 'name/cos:PutObject', 'name/cos:PostObject', 'name/cos:AppendObject', 'name/cos:GetObject', 'name/cos:HeadObject', 'name/cos:OptionsObject', 'name/cos:PutObjectCopy', 'name/cos:PostObjectRestore', // 分片上傳操作 'name/cos:InitiateMultipartUpload', 'name/cos:ListMultipartUploads', 'name/cos:ListParts', 'name/cos:UploadPart', 'name/cos:CompleteMultipartUpload', 'name/cos:AbortMultipartUpload', ), 'effect'=> 'allow', 'principal'=> array('qcs'=> array('*')), 'resource'=> array( 'qcs::cos:' . $this->config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/', 'qcs::cos:' . $this->config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/' . $this->config['AllowPrefix'] ) ) ) ); $policyStr = str_replace('\\/', '/', json_encode($policy)); $Action = 'GetFederationToken'; $Nonce = rand(10000, 20000); $Timestamp = time() - 1; $Method = 'GET'; $params = array( 'Action'=> $Action, 'Nonce'=> $Nonce, 'Region'=> '', 'SecretId'=> $this->config['SecretId'], 'Timestamp'=> $Timestamp, 'durationSeconds'=> 7200, 'name'=> '', 'policy'=> $policyStr ); $params['Signature'] = urlencode($this->getSignature($params, $this->config['SecretKey'], $Method)); $url = $this->config['Url'] . '?' . $this->json2str($params, 1); $ch = curl_init($url); $this->config['Proxy'] && curl_setopt($ch, CURLOPT_PROXY, $this->config['Proxy']); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); if(curl_errno($ch)) $result = curl_error($ch); curl_close($ch); $result = json_decode($result, 1); $_SESSION['tempKeysCache'] = $result['data']; $_SESSION['tempKeysCache']['policyStr'] = $policyStr; return $result['data']; } // 計算 COS API 請求用的簽名 public functiongetAuthorization($keys, $method, $pathname){ // 獲取個人 API 金鑰 https://console.qcloud.com/capi $SecretId = $keys['credentials']['tmpSecretId']; $SecretKey = $keys['credentials']['tmpSecretKey']; // 整理引數 $query = array(); $headers = array(); $method = strtolower($method ? $method : 'get'); $pathname = $pathname ? $pathname : '/'; substr($pathname, 0, 1) != '/' && ($pathname = '/' . $pathname); // 工具方法 functiongetObjectKeys($obj){ $list = array_keys($obj); sort($list); return $list; } functionobj2str($obj){ $list = array(); $keyList = getObjectKeys($obj); $len = count($keyList); for ($i = 0; $i < $len; $i++) { $key = $keyList[$i]; $val = $obj[$key] ? $obj[$key] : ''; $key = strtolower($key); $list[] = rawurlencode($key) . '=' . rawurlencode($val); } return implode('&', $list); } // 簽名有效起止時間 $now = time() - 1; $expired = $now + 3600; // 簽名過期時刻,600 秒後 // 要用到的 Authorization 引數列表 $qSignAlgorithm = 'sha1'; $qAk = $SecretId; $qSignTime = $now . ';' . $expired; $qKeyTime = $now . ';' . $expired; $qHeaderList = strtolower(implode(';', getObjectKeys($headers))); $qUrlParamList = strtolower(implode(';', getObjectKeys($query))); // 簽名演算法說明文件:https://www.qcloud.com/document/product/436/7778 // 步驟一:計算 SignKey $signKey = hash_hmac("sha1", $qKeyTime, $SecretKey); // 步驟二:構成 FormatString $formatString = implode("\n", array(strtolower($method), $pathname, obj2str($query), obj2str($headers), '')); // 自定義頭部(暫時關閉) // header('x-test-method', $method); // header('x-test-pathname', $pathname); // 步驟三:計算 StringToSign $stringToSign = implode("\n", array('sha1', $qSignTime, sha1($formatString), '')); // 步驟四:計算 Signature $qSignature = hash_hmac('sha1', $stringToSign, $signKey); // 步驟五:構造 Authorization $authorization = implode('&', array( 'q-sign-algorithm=' . $qSignAlgorithm, 'q-ak=' . $qAk, 'q-sign-time=' . $qSignTime, 'q-key-time=' . $qKeyTime, 'q-header-list=' . $qHeaderList, 'q-url-param-list=' . $qUrlParamList, 'q-signature=' . $qSignature )); return $authorization; } /*********************************************************************************************************************************************/ // // cos配置引數 // protected $config = array( // 'Url' => 'https://sts.api.qcloud.com/v2/index.php', // 'Domain' => 'sts.api.qcloud.com', // 'Proxy' => '', // 'SecretId' => 'AKIDwqbCewU2ZxABC3QDWp1EWrBLK9nF5dZL', // 固定金鑰 // 'SecretKey' => 'jHj5GIAvV8eFk3B8tSwKXYO4f0IUcqJu', // 固定金鑰 // 'Bucket' => 'xcx-1255484416', // 'Region' => 'ap-guangzhou', // 'AllowPrefix' => '*', // 這裡改成允許的路徑字首,這裡可以根據自己網站的使用者登入態判斷允許上傳的目錄,例子:* 或者 a/* 或者 a.jpg // ); // // $config = array( // // 'Url' => 'https://sts.api.qcloud.com/v2/index.php', // // 'Domain' => 'sts.api.qcloud.com', // // 'Proxy' => '', // // 'SecretId' => 'AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // 固定金鑰 // // 'SecretKey' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // 固定金鑰 // // 'Bucket' => 'test-1250000000', // // 'Region' => 'ap-guangzhou', // // 'AllowPrefix' => '_ALLOW_DIR_/*', // 必填,這裡改成允許的路徑字首,這裡可以根據自己網站的使用者登入態判斷允許上傳的目錄,例子:* 或者 a/* 或者 a.jpg // // ); // // json 轉 query string // function json2str($obj, $notEncode = false) // { // ksort($obj); // $arr = array(); // foreach ($obj as $key => $val) { // !$notEncode && ($val = urlencode($val)); // array_push($arr, $key . '=' . $val); // } // return join('&', $arr); // } // // 計算臨時金鑰用的簽名 // function getSignature($opt, $key, $method) // { // $formatString = $method . $this->config['Domain'] . '/v2/index.php?' . self::json2str($opt, 1); // $sign = hash_hmac('sha1', $formatString, $key); // $sign = base64_encode(hex2bin($sign)); // return $sign; // } // // 獲取臨時金鑰 // function getTempKeys() // { // // 判斷是否修改了 AllowPrefix // if ($this->config['AllowPrefix'] === '_ALLOW_DIR_/*') { // return array('error'=> '請修改 AllowPrefix 配置項,指定允許上傳的路徑字首'); // } // // dump($this->config); // $ShortBucketName = substr($this->config['Bucket'],0, strripos($this->config['Bucket'], '-')); // $AppId = substr($this->config['Bucket'], 1 + strripos($this->config['Bucket'], '-')); // $policy = array( // 'version'=> '2.0', // 'statement'=> array( // array( // 'action'=> array( // // // 這裡可以從臨時金鑰的許可權上控制前端允許的操作 // 'name/cos:*', // 這樣寫可以包含下面所有許可權 // // // 列出所有允許的操作 // // // ACL 讀寫 // // 'name/cos:GetBucketACL', // // 'name/cos:PutBucketACL', // // 'name/cos:GetObjectACL', // // 'name/cos:PutObjectACL', // // // 簡單 Bucket 操作 // // 'name/cos:PutBucket', // // 'name/cos:HeadBucket', // // 'name/cos:GetBucket', // // 'name/cos:DeleteBucket', // // 'name/cos:GetBucketLocation', // // // Versioning // // 'name/cos:PutBucketVersioning', // // 'name/cos:GetBucketVersioning', // // // CORS // // 'name/cos:PutBucketCORS', // // 'name/cos:GetBucketCORS', // // 'name/cos:DeleteBucketCORS', // // // Lifecycle // // 'name/cos:PutBucketLifecycle', // // 'name/cos:GetBucketLifecycle', // // 'name/cos:DeleteBucketLifecycle', // // // Replication // // 'name/cos:PutBucketReplication', // // 'name/cos:GetBucketReplication', // // 'name/cos:DeleteBucketReplication', // // // 刪除檔案 // // 'name/cos:DeleteMultipleObject', // // 'name/cos:DeleteObject', // // 簡單檔案操作 // 'name/cos:PutObject', // 'name/cos:PostObject', // 'name/cos:AppendObject', // 'name/cos:GetObject', // 'name/cos:HeadObject', // 'name/cos:OptionsObject', // 'name/cos:PutObjectCopy', // 'name/cos:PostObjectRestore', // // 分片上傳操作 // 'name/cos:InitiateMultipartUpload', // 'name/cos:ListMultipartUploads', // 'name/cos:ListParts', // 'name/cos:UploadPart', // 'name/cos:CompleteMultipartUpload', // 'name/cos:AbortMultipartUpload', // ), // 'effect'=> 'allow', // 'principal'=> array('qcs'=> array('*')), // 'resource'=> array( // 'qcs::cos:' . $this->config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/', // 'qcs::cos:' . $this->config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/' . $this->config['AllowPrefix'] // ) // ) // ) // ); // $policyStr = str_replace('\\/', '/', json_encode($policy)); // $Action = 'GetFederationToken'; // $Nonce = rand(10000, 20000); // $Timestamp = time() - 1; // $Method = 'GET'; // $params = array( // 'Action'=> $Action, // 'Nonce'=> $Nonce, // 'Region'=> '', // 'SecretId'=> $this->config['SecretId'], // 'Timestamp'=> $Timestamp, // 'durationSeconds'=> 7200, // 'name'=> '', // 'policy'=> $policyStr // ); // $params['Signature'] = urlencode(self::getSignature($params, $this->config['SecretKey'], $Method)); // $url = $this->config['Url'] . '?' . self::json2str($params, 1); // $ch = curl_init($url); // $this->config['Proxy'] && curl_setopt($ch, CURLOPT_PROXY, $this->config['Proxy']); // curl_setopt($ch, CURLOPT_HEADER, 0); // curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0); // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // $result = curl_exec($ch); // if(curl_errno($ch)) $result = curl_error($ch); // curl_close($ch); // $result = json_decode($result, 1); // return $result['data']; // } // public function getCosAuth() // { // // 獲取臨時金鑰,計算簽名 // $tempKeys = self::getTempKeys(); // // 返回資料給前端 // header('Content-Type: application/json'); // header('Allow-Control-Allow-Origin: *'); // 這裡修改允許跨域訪問的網站 // header('Allow-Control-Allow-Headers: origin,accept,content-type'); // echo json_encode($tempKeys); // } }

二、javascript上傳圖片部分

首先去騰旭雲下載cos-js-sdk-v5.min.js並引入頁面,這裡只展示實現部分

// 圖片上傳監聽事件
functionuploadConver(_this,event) {

	for(var i = 0;i<event.target.files.length;i++) {
        var files = event.target.files[i];

        if (!files) {
			tipPopup('未選擇上傳檔案',1100,4);
			return;
		}

		files && uploadFile(files, function (err, data) {

			if(data) {
				$("#preImg").html("").append('<img src="'+data.url+'" width="200px"/>');
				//$("#conver").val(data.url);
				console.log(data);
			}else {
				console.log(err);
			}

			//console.log(err || data);
			//document.getElementById('msg').innerText = err ? err : ('上傳成功,ETag=' + data.ETag);
		});
        //uploadFileToOss(file);
        //console.log(file);
    }
}

// 非同步請求上傳簽名
var getAuthorization = function (options, callback) {
        
     var xhr = new XMLHttpRequest();
     xhr.open('GET', url, true);
     xhr.onload = function (e) {
         var AuthData;
         try {
             AuthData = JSON.parse(xhr.responseText)
         } catch (e) {}
         if (AuthData && AuthData.Aut