Files
ZangShiQi/vendor/overtrue/easy-sms/src/Gateways/BaiduGateway.php
2026-04-04 17:27:12 +08:00

175 lines
5.8 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* This file is part of the overtrue/easy-sms.
*
* (c) overtrue <i@overtrue.me>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Overtrue\EasySms\Gateways;
use Overtrue\EasySms\Contracts\MessageInterface;
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
use Overtrue\EasySms\Exceptions\GatewayErrorException;
use Overtrue\EasySms\Support\Config;
use Overtrue\EasySms\Traits\HasHttpRequest;
/**
* Class BaiduGateway.
*
* @see https://cloud.baidu.com/doc/SMS/index.html
*/
class BaiduGateway extends Gateway
{
use HasHttpRequest;
const ENDPOINT_HOST = 'smsv3.bj.baidubce.com';
const ENDPOINT_URI = '/api/v3/sendSms';
const BCE_AUTH_VERSION = 'bce-auth-v1';
const DEFAULT_EXPIRATION_IN_SECONDS = 1800; //签名有效期默认1800秒
const SUCCESS_CODE = 1000;
/**
* Send message.
*
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
* @param \Overtrue\EasySms\Support\Config $config
*
* @return array
*
* @throws \Overtrue\EasySms\Exceptions\GatewayErrorException ;
*/
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
{
$params = [
'signatureId' => $config->get('invoke_id'),
'mobile' => $to->getNumber(),
'template' => $message->getTemplate($this),
'contentVar' => $message->getData($this),
];
if (!empty($params['contentVar']['custom'])) {
//用户自定义参数,格式为字符串,状态回调时会回传该值
$params['custom'] = $params['contentVar']['custom'];
unset($params['contentVar']['custom']);
}
if (!empty($params['contentVar']['userExtId'])) {
//通道自定义扩展码,上行回调时会回传该值,其格式为纯数字串。默认为不开通,请求时无需设置该参数。如需开通请联系客服申请
$params['userExtId'] = $params['contentVar']['userExtId'];
unset($params['contentVar']['userExtId']);
}
$datetime = gmdate('Y-m-d\TH:i:s\Z');
$headers = [
'host' => self::ENDPOINT_HOST,
'content-type' => 'application/json',
'x-bce-date' => $datetime,
];
//获得需要签名的数据
$signHeaders = $this->getHeadersToSign($headers, ['host', 'x-bce-date']);
$headers['Authorization'] = $this->generateSign($signHeaders, $datetime, $config);
$result = $this->request('post', self::buildEndpoint($config), ['headers' => $headers, 'json' => $params]);
if (self::SUCCESS_CODE != $result['code']) {
throw new GatewayErrorException($result['message'], $result['code'], $result);
}
return $result;
}
/**
* Build endpoint url.
*
* @param \Overtrue\EasySms\Support\Config $config
*
* @return string
*/
protected function buildEndpoint(Config $config)
{
return 'http://'.$config->get('domain', self::ENDPOINT_HOST).self::ENDPOINT_URI;
}
/**
* Generate Authorization header.
*
* @param array $signHeaders
* @param int $datetime
* @param \Overtrue\EasySms\Support\Config $config
*
* @return string
*/
protected function generateSign(array $signHeaders, $datetime, Config $config)
{
// 生成 authString
$authString = self::BCE_AUTH_VERSION.'/'.$config->get('ak').'/'
.$datetime.'/'.self::DEFAULT_EXPIRATION_IN_SECONDS;
// 使用 sk 和 authString 生成 signKey
$signingKey = hash_hmac('sha256', $authString, $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}";
}
/**
* 生成标准化 http 请求头串.
*
* @param array $headers
*
* @return string
*/
protected function getCanonicalHeaders(array $headers)
{
$headerStrings = [];
foreach ($headers as $name => $value) {
//trim后再encode之后使用':'号连接起来
$headerStrings[] = rawurlencode(strtolower(trim($name))).':'.rawurlencode(trim($value));
}
sort($headerStrings);
return implode("\n", $headerStrings);
}
/**
* 根据 指定的 keys 过滤应该参与签名的 header.
*
* @param array $headers
* @param array $keys
*
* @return array
*/
protected function getHeadersToSign(array $headers, array $keys)
{
return array_intersect_key($headers, array_flip($keys));
}
}