单文件PHP实现腾讯云APIv3签名及访问
腾讯云SDK需要导入的代码文件过多,影响项目的可读性和可维护性,于是,决定自己封装一个简单的SDK。此基础类签名算法符合腾讯云APIv3规范,可大大简化脱离官方SDK进行单一产品接口开发的难度。相关的文章推荐:纯shell实现腾讯云APIv3签名及访问。
-
获取受限的
secretId
和secretKey
,请参阅 腾讯云短信-预设策略 -
使用方法可参考180行代码实现全球短信发送功能
/**
* 腾讯云基础类
* @author rehiy
* @url https://www.rehiy.com/post/527/
*/
class QCloudBasic
{
/**
* @var string 接口域名
*/
protected $domain = 'tencentcloudapi.com';
/**
* @var string 接口服务
*/
protected $service = '';
/**
* @var string 接口版本
*/
protected $version = '';
/**
* @var string SecretId
*/
protected $secretId = '';
/**
* @var string SecretKey
*/
protected $secretKey = '';
/**
* 构造函数
* @param array $config
*/
public function __construct($config)
{
$this->domain = $this->service . '.' . $this->domain;
foreach ($config as $key => $value) {
$this->$key = $value;
}
}
/**
* 请求接口
* @param string $region 地域
* @param string $action 操作名称
* @param array $data 请求参数
*/
protected function post($region, $action, $data)
{
$timestamp = time();
$payload = empty($data) ? '{}' : json_encode($data, 320);
$authorization = $this->signature($action, $payload, $timestamp);
$headers = [
"Authorization: {$authorization}",
"Content-Type: application/json; charset=utf-8",
"Host: {$this->domain}",
"X-TC-Action: {$action}",
"X-TC-Timestamp: {$timestamp}",
"X-TC-Version: {$this->version}",
"X-TC-Region: {$region}"
];
return $this->httpRequest('POST', "https://{$this->domain}", $payload, $headers);
}
/**
* 生成签名
* @param string $action 操作名称
* @param string $payload 请求参数
* @param number $timestamp 时间戳
*/
protected function signature($action, $payload, $timestamp)
{
$algorithm = 'TC3-HMAC-SHA256';
$date = gmdate('Y-m-d', $timestamp ?: time());
$canonicalUri = '/';
$canonicalQuery = '';
$canonicalHeaders = implode("\n", [
'content-type:application/json; charset=utf-8',
'host:' . $this->domain,
'x-tc-action:' . strtolower($action),
''
]);
$signedHeaders = 'content-type;host;x-tc-action';
$canonicalRequest = implode("\n", [
'POST',
$canonicalUri,
$canonicalQuery,
$canonicalHeaders,
$signedHeaders,
hash('SHA256', $payload)
]);
$credentialScope = "{$date}/{$this->service}/tc3_request";
$stringToSign = implode("\n", [
$algorithm,
$timestamp,
$credentialScope,
hash('SHA256', $canonicalRequest),
]);
$secretDate = hash_hmac('SHA256', $date, 'TC3' . $this->secretKey, true);
$secretService = hash_hmac('SHA256', $this->service, $secretDate, true);
$secretSigning = hash_hmac('SHA256', 'tc3_request', $secretService, true);
$signature = hash_hmac('SHA256', $stringToSign, $secretSigning);
return implode(', ', [
"{$algorithm} Credential={$this->secretId}/{$credentialScope}",
"SignedHeaders={$signedHeaders}",
"Signature={$signature}"
]);
}
/**
* 发送HTTP请求
* @param string $method 请求方式
* @param string $url 服务器地址
* @param array|string $data 数据
* @param array $header 请求头
*/
protected function httpRequest($method, $url, $data = null, $header = null)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 25);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header ?? []);
if ($data && $method == 'POST') {
if (is_array($data)) {
if (in_array('Content-Type: application/json', $header)) {
$data = json_encode($data, 320);
} else {
$data = http_build_query($data);
}
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
list($body, $errno, $error) = [
curl_exec($ch), curl_errno($ch), curl_error($ch), curl_close($ch)
];
if ($errno != 0) {
throw new \Exception('CURL - ' . $error, $errno);
}
try {
$res = json_decode($body, true);
return $res['Response'] ?? '';
} catch (\Exception $e) {
return false;
}
}
}