对接华为云的消息&短信 MSGSMS

写在前面

记录对接华为云的消息&短信 (Message & SMS), 以便下次开发快速使用!

代码

我们通常使用短信服务接入web,来实现一些业务验证码,消息通知等功能。
华为云的 消息&短信 MSGSMS 和阿里云的 短信服务 几乎没啥区别。
如果有对接过短信服务那么都不需要了解,直接复制粘贴使用即可!
简单的说就是配置模板,调用接口发送短信。需要注意的是模板参数的定义/格式,通常踩坑的都是参数格式问题。
ENV配置:

# SMS配置
HW_SMS_APP_URL=https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1
HW_SMS_APP_KEY=
HW_SMS_APP_SECRET=
HW_SMS_APP_SENDER=
HW_SMS_APP_CALLBACK=

接口定义:

<?php

namespace App\Service\SMS;

interface ISMS
{

    /**
     * 发送短信
     *
     * @param array $mobiles
     * @param string $templateId
     * @param array $params
     * @return mixed
     */
    public function sendSMS(array $mobiles, string $templateId, array $params);


}

实现类:

<?php

namespace App\Service\SMS;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;

class HuaweiSMS implements ISMS
{

    /**
     *
     * 已创建短信应用:
     *      APP接入地址:https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1
     * @var string
     */
    public $appUrl;

    /**
     * 短信应用:APP_Key
     *      
     * @var string
     */
    public $appKey;

    /**
     * 短信应用:APP_Secret
     *      
     * @var string
     */
    public $appSecret;

    /**
     * 签名通道号
     * @var string
     */
    public $sender;

    /**
     * 短信状态报告接收地址,为空或者不填表示不接收状态报告
     */
    public $statusCallback;


    public function __construct()
    {
        $this->appUrl = env('HW_SMS_APP_URL');
        $this->appKey = env('HW_SMS_APP_KEY');
        $this->appSecret = env('HW_SMS_APP_SECRET');
        $this->sender = env('HW_SMS_APP_SENDER');
        $this->statusCallback = env('HW_SMS_APP_CALLBACK');

    }

    /**
     * 发送短信消息
     * templateParas:选填,使用无变量模板时请赋空值 $templateParas = '';
     * 格式:'["369751"]', 每个变量都必须赋值,且取值不能为空;验证码杜绝首位0,会丢失0
     * 更多模板规范和变量规范:
     *      产品介绍>短信模板须知和短信变量须知:https://support.huaweicloud.com/productdesc-msgsms/sms_templates.html
     *
     * @param array $mobiles |   发送给谁
     * @param string $templateId |   短信模板id
     * @param array $params |   短信模板参数,与模板id绑定
     * @return array
     */
    public function sendSMS(array $mobiles, string $templateId, array $params)
    {
        $receiver = $this->getReceiver($mobiles);
        $templateParas = $params ? json_encode($params, JSON_UNESCAPED_UNICODE) : '';
        $client = new Client();
        try {
            $data = [
                'form_params' => [
                    'from' => $this->sender,
                    'to' => $receiver,
                    'templateId' => $templateId,
                    'templateParas' => $templateParas,
                    'statusCallback' => $this->statusCallback,
                ],
                'headers' => [
                    'Authorization' => 'WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
                    'X-WSSE' => $this->buildWsseHeader()
                ],
                'verify' => false
            ];
            $response = $client->request('POST', $this->appUrl, $data);
            $content = $response->getBody()->getContents();
            Log::info(__METHOD__, json_decode($content, true));
            return ['ok' => true, 'data' => json_decode($content, true)];
        } catch (GuzzleException $e) {
            Log::error($e);
            return ['ok' => false, 'msg' => '发送消息失败!' . $e->getMessage()];
        }
    }

    /**
     * 格式为:+{国家码}{地区码}{终端号码},国内短信:接收号码为国内手机号码时,所填号码可以不带+86,系统默认添加86
     * @param $mobiles
     * @return string
     */
    public function getReceiver($mobiles): string
    {
        $prefix = '+86';
        foreach ($mobiles as $key => $mobile) {
            $mobiles[$key] = $prefix . $mobile;
        }
        return implode(',', $mobiles);
    }

    /**
     * 构造X-WSSE参数值
     *
     * @return string
     */
    public function buildWsseHeader(): string
    {
        $now = date('Y-m-d\TH:i:s\Z');
        $nonce = uniqid(); //Nonce
        $base64 = base64_encode(hash('sha256', ($nonce . $now . $this->appSecret))); //PasswordDigest
        return sprintf("UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"",
            $this->appKey, $base64, $nonce, $now);
    }

}

附录

参考文档:
模板/变量须知:support.huaweicloud.com/productdes...
发送短信API说明:support.huaweicloud.com/api-msgsms...

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!