youvision / think-easysms
ThinkPHP 8 短信发送组件,基于 overtrue/easy-sms 实现多网关短信发送
Requires
- php: >=8.0
- overtrue/easy-sms: ^3.2
- topthink/framework: ^8.0
Requires (Dev)
- phpunit/phpunit: ^9.6 || ^10.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
面向 ThinkPHP 的开源工程索引:组件、框架、服务与发布工具,按能力组织,持续整理。 仓库地址:https://github.com/indiboy-create/ThinkPHP-PanGu/ 在线站点:https://indiboy-create.github.io/ThinkPHP-PanGu/
think-easysms
基于 overtrue/easy-sms 的 ThinkPHP 8 短信发送组件。
- 一套写法兼容阿里云、腾讯云、华为云、云片、Submail、容联云通讯等 30+ 服务商
- 按顺序或轮询自动切换网关,失败自动尝试下一个
- 支持自定义网关、自定义短信消息类、国际短信
- 与 ThinkPHP 容器、门面、依赖注入无缝集成
环境要求
- PHP >= 8.0
- ThinkPHP >= 8.0
- overtrue/easy-sms ^3.2
安装
composer require youvision/think-easysms
ThinkPHP 8 项目的 composer.json 通常已配置以下脚本,安装完成后会自动发现服务并发布配置:
"scripts": { "post-autoload-dump": [ "@php think service:discover", "@php think vendor:publish" ] }
若没有自动执行,可手动运行:
php think service:discover php think vendor:publish
执行后项目根目录会生成 config/easysms.php。
配置
编辑 config/easysms.php,至少配置一个可用网关,并将默认网关改为该网关:
return [ 'timeout' => 5.0, 'default' => [ 'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class, 'gateways' => ['aliyun'], ], 'gateways' => [ 'aliyun' => [ 'access_key_id' => env('EASYSMS_ALIYUN_ACCESS_KEY_ID'), 'access_key_secret' => env('EASYSMS_ALIYUN_ACCESS_KEY_SECRET'), 'sign_name' => env('EASYSMS_ALIYUN_SIGN_NAME'), ], ], ];
配置项说明:
| 配置项 | 说明 |
|---|---|
timeout |
HTTP 请求超时时间,单位秒,可被单个网关的 timeout 覆盖 |
options |
所有网关共享的 Guzzle 请求选项,如代理、证书、请求头 |
default.strategy |
网关选择策略,OrderStrategy 顺序尝试,RoundRobinStrategy 轮询 |
default.gateways |
默认网关列表,数组顺序即尝试顺序 |
gateways |
各服务商凭证,仅需配置实际使用的网关 |
extend |
自定义网关,值为网关类名或工厂闭包 |
默认网关为
errorlog,短信内容会写入runtime/easysms.log,不会真正发送,便于本地调试。生产环境请务必修改。
快速开始
使用门面
use Youvision\ThinkEasySms\Sms; $result = Sms::send('13800138000', [ 'content' => '您的验证码为:6379,5 分钟内有效。', 'template' => 'SMS_001', 'data' => ['code' => 6379], ]);
依赖注入
use Youvision\ThinkEasySms\EasySms; class Login { public function __construct(protected EasySms $sms) { } public function sendCode(string $phone, int $code): array { return $this->sms->send($phone, [ 'content' => "您的验证码为:{$code}", 'template' => 'SMS_001', 'data' => ['code' => $code], ]); } }
也可以注入底层客户端:
use Overtrue\EasySms\EasySms as EasySmsClient; public function __construct(protected EasySmsClient $client) { }
短信内容
由于同一条短信可能通过不同网关发送,组件抽象了三个通用属性:
content:短信正文,适用于云片等按内容发送的平台template:模板 ID,适用于按模板发送的平台data:模板变量,适用于按模板发送的平台
Sms::send('13800138000', [ 'content' => '您的验证码为:6379', 'template' => 'SMS_001', 'data' => ['code' => 6379], ]);
content、template、data 都支持闭包,可根据网关动态返回不同内容:
Sms::send('13800138000', [ 'template' => function ($gateway) { return $gateway->getName() === 'aliyun' ? 'SMS_ALIYUN_001' : 'SMS_001'; }, 'data' => ['code' => 6379], ]);
指定网关
单条短信可以覆盖默认网关配置:
Sms::send('13800138000', $message, ['qcloud', 'aliyun']);
也可以直接发送字符串内容:
Sms::send('13800138000', '您的验证码为:6379');
返回值与异常
发送成功时返回每个网关的结果数组:
[
'aliyun' => [
'gateway' => 'aliyun',
'status' => 'success',
'template' => 'SMS_001',
'result' => [/* 服务商原始返回值 */],
],
]
所有网关均失败时抛出 Overtrue\EasySms\Exceptions\NoGatewayAvailableException:
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException; try { Sms::send('13800138000', $message); } catch (NoGatewayAvailableException $e) { $e->getResults(); // 所有网关的发送结果 $e->getExceptions(); // 所有异常 $e->getLastException(); // 最后一个异常 }
自定义网关
通过配置注册
实现 Overtrue\EasySms\Contracts\GatewayInterface,然后在配置中注册:
// config/easysms.php 'extend' => [ 'mygateway' => \app\sms\MyGateway::class, ],
将 mygateway 加入 default.gateways 即可使用。
运行时注册
use Youvision\ThinkEasySms\Sms; Sms::extend('mygateway', function (array $config) { return new \app\sms\MyGateway($config); }); Sms::send('13800138000', $message, ['mygateway']);
国际短信
use Overtrue\EasySms\PhoneNumber; use Youvision\ThinkEasySms\Sms; $number = new PhoneNumber(13188888888, 31); Sms::send($number, [ 'content' => 'Your verification code is 6379', 'template' => 'SMS_001', 'data' => ['code' => 6379], ]);
自定义短信消息
针对固定业务场景,可继承 Overtrue\EasySms\Message,实现一处定义、多处调用:
use Overtrue\EasySms\Contracts\GatewayInterface; use Overtrue\EasySms\Message; use Overtrue\EasySms\Strategies\OrderStrategy; class OrderPaidMessage extends Message { protected string $strategy = OrderStrategy::class; protected array $gateways = ['aliyun', 'qcloud']; public function __construct(protected string $orderNo) { } public function getContent(?GatewayInterface $gateway = null): ?string { return "您的订单 {$this->orderNo} 已完成付款"; } public function getTemplate(?GatewayInterface $gateway = null): ?string { return 'SMS_003'; } public function getData(?GatewayInterface $gateway = null): array { return ['order_no' => $this->orderNo]; } }
Sms::send('13800138000', new OrderPaidMessage('202601010001'));
常用网关配置示例
腾讯云
短信使用 template + data,data 按模板占位顺序传值:
'qcloud' => [ 'sdk_app_id' => env('EASYSMS_QCLOUD_SDK_APP_ID'), 'secret_id' => env('EASYSMS_QCLOUD_SECRET_ID'), 'secret_key' => env('EASYSMS_QCLOUD_SECRET_KEY'), 'sign_name' => env('EASYSMS_QCLOUD_SIGN_NAME'), ],
Sms::send('13800138000', [ 'template' => 101234, 'data' => ['6379', '5'], ]);
华为云
'huawei' => [ 'endpoint' => env('EASYSMS_HUAWEI_ENDPOINT'), 'app_key' => env('EASYSMS_HUAWEI_APP_KEY'), 'app_secret' => env('EASYSMS_HUAWEI_APP_SECRET'), 'from' => [ 'default' => env('EASYSMS_HUAWEI_FROM'), 'custom' => 'csms12345', ], ],
Sms::send('13800138000', [ 'template' => 'SMS_001', 'data' => ['6379', 'from' => 'custom'], ]);
云片
短信使用 content:
'yunpian' => [ 'api_key' => env('EASYSMS_YUNPIAN_API_KEY'), 'signature' => '【默认签名】', ],
调试网关
'errorlog' => [ 'file' => runtime_path() . 'easysms.log', ],
更多网关及其参数见 easy-sms 官方文档。
测试
composer install vendor/bin/phpunit
License
MIT