无需安装sdk扩展包,直接引入类即可使用
V3版本请求体&签名机制:自研请求体和签名机制 - 阿里云SDK - 阿里云
模版内容:
<?php
namespace common\components;
use common\constant\UserConst;
use common\models\bee\SmsReferer;
use common\models\bee\SmsStatistics;
use yii\base\Component;
use yii\helpers\Json;
class AlSms {
public $ALGORITHM = 'ACS3-HMAC-SHA256';
public $AccessKeyId;
public $AccessKeySecret;
const REGISTER_NEW = 'register_new';
const REGISTER_APPROVED = 'register_approved';
const CODE_MAP = [
self::REGISTER_NEW => 'SMS_468995712' //模版code
];
/**
* @see https://help.aliyun.com/zh/sdk/product-overview/v3-request-structure-and-signature?spm=a2c4g.11186623.0.0.3bfd52d6SOjFjU#sectiondiv-zua-ikm-33s
* @title main
*/
public function __construct()
{
date_default_timezone_set('UTC'); // 设置时区为GMT
$this->AccessKeyId = getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'); // 从环境变量中获取RAM用户Access Key ID
$this->AccessKeySecret = getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'); // 从环境变量中获取RAM用户Access Key Secret
$this->ALGORITHM = 'ACS3-HMAC-SHA256'; // 设置加密算法
}
public function main()
{
// RPC接口请求
$request = $this->createRequest('POST', '/', 'ecs.cn-beijing.aliyuncs.com', 'DescribeRegions', '2014-05-26');
$request['queryParam']= ['RegionId' => 'cn-beijing'];
// ROA接口POST请求
// $request = $this->createRequest('POST', '/clusters', 'cs.cn-beijing.aliyuncs.com', 'CreateCluster', '2015-12-15');
// $this->addRequestBody($request, [
// 'name' => 'PhoneNumbers',
// 'region_id' => 'cn-beijing',
// 'cluster_type' => 'ExternalKubernetes',
// 'vpcid' => 'vpc-2zeo42r27y4opXXXXXXXX',
// 'service_cidr' => '172.16.5.0/20',
// 'security_group_id' => 'sg-2zeh5ta2ikljXXXXXXXX',
// "vswitch_ids" => [
// "vsw-2zeuntqtklsk0XXXXXXXX"
// ],
// ]);
// ROA接口GET请求
// canonicalUri如果存在path参数,需要对path参数encode,rawurlencode({path参数})
// $cluster_id = 'cb7cd6b9bde934f6193801878XXXXXXXX';
// $canonicalUri = sprintf("/clusters/%s/resources", rawurlencode($cluster_id));
// $request = $this->createRequest('GET', $canonicalUri, 'cs.cn-beijing.aliyuncs.com', 'DescribeClusterResources', '2015-12-15');
// $request['queryParam'] = [
// 'with_addon_resources' => true,
// ];
$this->getAuthorization($request);
$this->callApi($request);
}
/**
* @title createRequest
*
* @param $httpMethod 请求类型
* @param $canonicalUri
* @param $host 请求地址
* @param $xAcsAction 请求方法
* @param $xAcsVersion 请求版本
*
* @return
* @date 2024/7/17
*/
private function createRequest($httpMethod, $canonicalUri, $host, $xAcsAction, $xAcsVersion)
{
$headers = [
'host' => $host,
'x-acs-action' => $xAcsAction,
'x-acs-version' => $xAcsVersion,
'x-acs-date' => gmdate('Y-m-d\TH:i:s\Z'),
'x-acs-signature-nonce' => bin2hex(random_bytes(16)),
];
return [
'httpMethod' => $httpMethod,
'canonicalUri' => $canonicalUri,
'host' => $host,
'headers' => $headers,
'queryParam' => [],
'body' => null,
];
}
private function addRequestBody(&$request, $bodyData)
{
$request['body'] = json_encode($bodyData, JSON_UNESCAPED_UNICODE);
$request['headers']['content-type'] = 'application/json; charset=utf-8';
}
private function getAuthorization(&$request)
{
$canonicalQueryString = $this->buildCanonicalQueryString($request['queryParam']);
$hashedRequestPayload = hash('sha256', $request['body'] ?? '');
$request['headers']['x-acs-content-sha256'] = $hashedRequestPayload;
$canonicalHeaders = $this->buildCanonicalHeaders($request['headers']);
$signedHeaders = $this->buildSignedHeaders($request['headers']);
$canonicalRequest = implode("\n", [
$request['httpMethod'],
$request['canonicalUri'],
$canonicalQueryString,
$canonicalHeaders,
$signedHeaders,
$hashedRequestPayload,
]);
$hashedCanonicalRequest = hash('sha256', $canonicalRequest);
$stringToSign = $this->ALGORITHM . "\n" . $hashedCanonicalRequest;
$signature = strtolower(bin2hex(hash_hmac('sha256', $stringToSign, $this->AccessKeySecret, true)));
$authorization = $this->ALGORITHM . " Credential=" . $this->AccessKeyId . ",SignedHeaders=" . $signedHeaders . ",Signature=" . $signature;
$request['headers']['Authorization'] = $authorization;
}
private function callApi($request)
{
try {
// 通过cURL发送请求
$url = "https://" . $request['host'] . $request['canonicalUri'];
// 初始化cURL会话
$ch = curl_init();
// 根据请求类型设置cURL选项
switch ($request['httpMethod']) {
case "GET":
break;
case "POST":
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request['body']);
break;
case "DELETE":
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
case "PUT":
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, $request['body']);
break;
default:
echo "Unsupported HTTP method: " . $request['body'];
throw new \Exception("Unsupported HTTP method");
}
// 添加请求参数到URL
if (!empty($request['queryParam'])) {
$url .= '?' . http_build_query($request['queryParam']);
}
// 设置cURL选项
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用SSL证书验证,请注意,这会降低安全性,不应在生产环境中使用(不推荐!!!)
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回而不是输出内容
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->convertHeadersToArray($request['headers'])); // 添加请求头
// 发送请求
$result = curl_exec($ch);
// 检查是否有错误发生
if (curl_errno($ch)) {
echo "Failed to send request: " . curl_error($ch);
}
// 关闭cURL会话
curl_close($ch);
} catch (\Exception $e) {
// echo "Error: " . $e->getMessage();
return $e;
}
return Json::decode($result);
}
private function convertHeadersToArray($headers)
{
$headerArray = [];
foreach ($headers as $key => $value) {
$headerArray[] = $key . ': ' . $value;
}
return $headerArray;
}
private function buildCanonicalQueryString($queryParams)
{
ksort($queryParams);
// Build and encode query parameters
$params = [];
foreach ($queryParams as $k => $v) {
if (null === $v) {
continue;
}
$str = rawurlencode($k);
if ('' !== $v && null !== $v) {
$str .= '=' . rawurlencode($v);
} else {
$str .= '=';
}
$params[] = $str;
}
return implode('&', $params);
}
private function buildCanonicalHeaders($headers)
{
// Sort headers by key and concatenate them
uksort($headers, 'strcasecmp');
$canonicalHeaders = '';
foreach ($headers as $key => $value) {
$canonicalHeaders .= strtolower($key) . ':' . trim($value) . "\n";
}
return $canonicalHeaders;
}
private function buildSignedHeaders($headers)
{
// Build the signed headers string
$signedHeaders = array_keys($headers);
sort($signedHeaders, SORT_STRING | SORT_FLAG_CASE);
return implode(';', array_map('strtolower', $signedHeaders));
}
/**
* 发送短信验证码
* @title sendSms
*/
public function sendSms($act_code,$mobile,$params=[],$code='')
{
$request = $this->createRequest('POST', '/', 'dysmsapi.aliyuncs.com', 'SendSms', '2017-05-25');
$request['queryParam']= [
'PhoneNumbers' => $mobile,
'SignName' => '签名',
'TemplateCode' => self::CODE_MAP[$act_code],
'TemplateParam' => json_encode($params),
];
$this->getAuthorization($request);
$resultArr = $this->callApi($request);
if($resultArr['Code'] != "OK"){
return [
'code'=>0,
'msg'=>$resultArr['Message']
];
}
return [
'code'=>200,
'msg'=>'ok'
];
}
}
$AlSms = new AlSms();
$AlSms->sendSms('register_new',13500002000,['code'=>1234]);