微信小程式/網站 上傳圖片到騰訊雲COS
阿新 • • 發佈:2019-02-01
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