Repository navigation
测试发现百度云已经不支持了? #4
Copy link
Copy link
Open
Description
Activity
简单的改成V3支持方法:
1、config\autoload\sms.php增加v3的配置,ak、sk我放在了env中设置,也可以直接写,但是不要提交到托管平台避免泄露
// ……其他配置 'baidu_cloud_v3' => [ 'driver' => \cms\sms\drivers\BaiduCloudV3Driver::class, 'config' => [ 'ak' => env('SMS_BAIDU_CLOUD_V3_AK', ''), 'sk' => env('SMS_BAIDU_CLOUD_V3_SK', ''), 'signature_id' => env('SMS_BAIDU_CLOUD_V3_SIGN', ''), //公用的短信签名 ], ],2、创建百度云短信v3的驱动,内容跟原驱动一模一样,只是把接口地址,参数修改了,也可以做在配置中,我这里直接写到代码中了,因为一般不会换,换了就意味着版本升级,之前的代码肯定不能用(文件位置随便放,能够加载就行)
<?php declare(strict_types=1); namespace cms\sms\drivers; use HyperfExt\Sms\Contracts\SmsableInterface; use HyperfExt\Sms\Drivers\AbstractDriver; use HyperfExt\Sms\Exceptions\DriverErrorException; class BaiduCloudV3Driver extends AbstractDriver { protected const ENDPOINT_HOST = 'smsv3.bj.baidubce.com'; protected const ENDPOINT_URI = '/api/v3/sendSms'; protected const BCE_AUTH_VERSION = 'bce-auth-v1'; protected const DEFAULT_EXPIRATION_IN_SECONDS = 1800; //签名有效期默认1800秒 protected const SUCCESS_CODE = 1000; public function send(SmsableInterface $smsable): array { $params = [ // 手机号码 'mobile' => $smsable->to->getNationalNumber(), // 短信模板 'template' => $smsable->template, // 签名 'signatureId' => $smsable->signature ?: $this->config->get('signature_id'), // 模板变量 'contentVar' => $smsable->data, // 自定义参数,暂不支持 // 'custom' => '', // 自定义扩展码,暂不支持 // 'userExtId' => '', ]; $datetime = gmdate('Y-m-d\TH:i:s\Z'); $headers = [ 'host' => self::ENDPOINT_HOST, 'content-type' => 'application/json', 'x-bce-date' => $datetime, // 'x-bce-content-sha256' => hash('sha256', json_encode($params)), ]; //获得需要签名的数据 $signHeaders = $this->getHeadersToSign($headers, ['host', 'x-bce-date']); $headers['Authorization'] = $this->generateSign($signHeaders, $datetime); $response = $this->client->postJson($this->buildEndpoint(), $params, $headers); $result = $response->toArray(); if ($result['code'] != self::SUCCESS_CODE) { throw new DriverErrorException($result['message'], $result['code'], $response); } return $result; } protected function buildEndpoint(): string { return 'http://' . $this->config->get('domain', self::ENDPOINT_HOST) . self::ENDPOINT_URI; } protected function generateSign(array $signHeaders, string $datetime): string { // 生成 authString $authString = self::BCE_AUTH_VERSION . '/' . $this->config->get('ak') . '/' . $datetime . '/' . self::DEFAULT_EXPIRATION_IN_SECONDS; // 使用 sk 和 authString 生成 signKey $signingKey = hash_hmac('sha256', $authString, $this->config->get('sk')); // 生成标准化 URI // 根据 RFC 3986,除了:1.大小写英文字符 2.阿拉伯数字 3.点'.'、波浪线'~'、减号'-'以及下划线'_' 以外都要编码 $canonicalURI = str_replace('%2F', '/', rawurlencode(self::ENDPOINT_URI)); // 生成标准化 QueryString $canonicalQueryString = ''; // 此 api 不需要此项。返回空字符串 // 整理 headersToSign,以 ';' 号连接 $signedHeaders = empty($signHeaders) ? '' : strtolower(trim(implode(';', array_keys($signHeaders)))); // 生成标准化 header $canonicalHeader = $this->getCanonicalHeaders($signHeaders); // 组成标准请求串 $canonicalRequest = "POST\n{$canonicalURI}\n{$canonicalQueryString}\n{$canonicalHeader}"; // 使用 signKey 和标准请求串完成签名 $signature = hash_hmac('sha256', $canonicalRequest, $signingKey); // 组成最终签名串 return "{$authString}/{$signedHeaders}/{$signature}"; } protected function getCanonicalHeaders(array $headers): string { $headerStrings = []; foreach ($headers as $name => $value) { //trim后再encode,之后使用':'号连接起来 $headerStrings[] = rawurlencode(strtolower(trim($name))) . ':' . rawurlencode(trim($value)); } sort($headerStrings); return implode("\n", $headerStrings); } protected function getHeadersToSign(array $headers, array $keys): array { return array_intersect_key($headers, array_flip($keys)); } }3、使用方式与文档中的示例一致,不过经实测发现,百度云的短信就算是普通营销短信,模板变量也必须要传?随便传一个都可以,不传要报错
控制器中示例:
<?php declare(strict_types=1); namespace cms\sms\api_controller; use cms\sms\service\VerificationCodeService; use Hyperf\HttpServer\Annotation\AutoController; use HyperfExt\Sms\Sms; /** * Class TestController * @package cms\sms\api_controller * @AutoController(prefix="api/sms/test") */ class TestController extends CommonController { public function t001() { $a = Sms::sender('baidu_cloud_v3')->to('1898047xxxx', '86')->send(new VerificationCodeService()); var_dump($a); return 'ok'; } }消息类中示例(这里要注意,使用gen:sms命令生成的代码默认使用了队列,根据自己情况来):
<?php declare(strict_types=1); /** * This file is part of hyperf-ext/sms. * * @link https://github.com/hyperf-ext/sms * @contact eric@zhu.email * @license https://github.com/hyperf-ext/sms/blob/master/LICENSE */ namespace cms\sms\service; // use HyperfExt\Contract\ShouldQueue; use HyperfExt\Sms\Contracts\SenderInterface; use HyperfExt\Sms\Smsable; class VerificationCodeService extends Smsable { /** * Create a new SMS message instance. */ public function __construct() { // } /** * Build the SMS message. */ public function build(SenderInterface $sender): void { // 不带签名使用配置 // $this->template('sms-tmpl-TuEOTX86xxxx')->with(['name' => 'awen']); // 带签名 $this->template('sms-tmpl-ZHFXcnxxx')->with(['name' => 'awen'])->signature('sms-sign-RmFfnu564xxx'); // 不带签名,模板没有变量也要传变量? // $this->template('sms-tmpl-AIgLRm0xxx')->with('now', ''); } }后续想要实现的功能:
1、需要支持数据库配置,多模板,多签名,多服务商
有一个hyperf的代码学习仓库:Hyperf学习Reacted by 屋班兔
Metadata
Metadata
Assignees
Labels
No labels
简单测试了一下百度云的短信好像不支持了,看了一下驱动源码,用了很老的接口,百度云已经更新至V3了,可能还是可以用,我的测试方法没对
然后我感觉如果要实现动态配置实现多平台,多签名,多模板用这类的集合组件可能不是一个很好的选择