阿里云短信PHP集成api类

无需安装sdk扩展包,直接引入类即可使用

V3版本请求体&签名机制:自研请求体和签名机制 - 阿里云SDK - 阿里云

模版内容:

php 复制代码
<?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]);
相关推荐
dessler39 分钟前
云计算&虚拟化-kvm创建网桥(bridge)
linux·运维·云计算
落非5 小时前
Ubuntu配置阿里云docker apt源
ubuntu·阿里云·docker
Lysun0015 小时前
云服务器安装mysql8.0(阿里云或者腾讯云都可以)
阿里云·云计算·腾讯云
汤米粥8 小时前
通过PHP创建AWS的CloudFront并绑定证书添加备用域名
服务器·云计算·aws
Z1eaf_complete9 小时前
Docker的基础使用
运维·docker·容器·云计算
Lyqfor9 小时前
云原生学习
java·分布式·学习·阿里云·云原生
大鹅i10 小时前
aws-athena查询语句总结
云计算·aws
汤米粥10 小时前
怎么样绑定域名到AWS(亚马逊云)服务器
服务器·云计算·aws
小安运维日记13 小时前
CKA认证 | Day3 K8s管理应用生命周期(上)
运维·云原生·容器·kubernetes·云计算·k8s
眷怀1 天前
网卡绑定bonding
linux·运维·服务器·网络·云计算