- 后端
- Web框架
【免费下载链接】symfony
The Symfony PHP framework
本篇指南以 Symfony 官方仓库中 LightSms Notifier Bridge 的 README 为骨架,系统讲解如何在 Symfony Notifier 中接入 LightSms 短信服务。文章会覆盖 DSN 的完整写法与参数含义、传输层的请求构造、签名算法、错误码对照以及测试验证方式,读者读完可以独立配置并在项目中发送带签名的 LightSms 短信。
一、LightSms Bridge 是什么
LightSms 是立陶宛的一家短信网关服务商,提供国际短信发送能力。Symfony 官方在src/Symfony/Component/Notifier/Bridge/LightSms/目录下维护了一个 Notifier Bridge,把 LightSms 的 HTTP 发送接口封装为 Symfony Notifier 的标准传输层(Transport)。
该 Bridge 的核心组成非常精简:
- LightSmsTransport.php:传输实现,负责构造请求、生成签名、解析响应;
- LightSmsTransportFactory.php:传输工厂,负责从 DSN 解析出登录名、Token、发送方号码等参数;
- Tests/LightSmsTransportTest.php 与 Tests/LightSmsTransportFactoryTest.php:对传输层与工厂层的单元测试。
从 composer.json 可以看到,该包名为symfony/light-sms-notifier,类型为symfony-notifier-bridge,运行要求 PHP >= 8.4.1,依赖symfony/http-client(^7.4|^8.0)与symfony/notifier(^8.2)。根据 CHANGELOG.md 的记录,该 Bridge 自 Symfony 5.3 引入,6.2 起支持使用SmsMessage->from覆盖默认发送方,8.2 起新增sslDSN 选项。
二、DSN 配置:完整写法与参数说明
原文档给出的 DSN 示例为:
LIGHTSMS_DSN=lightsms://LOGIN:TOKEN@default?from=PHONE其中三个关键占位符的含义如下:
| 占位符 | 含义 | 说明 |
|---|---|---|
LOGIN | LightSms 账户登录名 | 在 LightSms 账户的客户端 API 页面可见 |
TOKEN | 账户 Token | 同样显示在账户信息中,用于请求签名 |
PHONE | LightSms 发送方手机号 | 需为已在 LightSms 注册并审核通过的发送号码(sender) |
账户信息在 LightSms 官网的客户端 API 栏目(路径/external/client/api/)中查看。
2.1 各组成部分的解析逻辑
结合 LightSmsTransportFactory::create() 的源码,DSN 的解析规则如下:
scheme必须是lightsms,否则工厂会抛出UnsupportedSchemeException;- 用户信息部分拆分为
LOGIN与TOKEN:login来自 DSN 的 user 段,token来自 password 段; from是必填选项,通过$dsn->getRequiredOption('from')读取,缺失时 DSN 解析失败(测试中的unsupportedSchemeProvider明确覆盖了“缺少 from”的情况);host为default时会被视为空值,最终回落为传输类内置的默认主机www.lightsms.com(见LightSmsTransport::HOST常量);其他值可自定义网关主机;port与ssl为可选配置:ssl选项通过基类 AbstractTransportFactory::getSsl() 解析为布尔值,用于控制走 HTTPS 还是明文 HTTP。
2.2 在框架项目中使用
在基于 Symfony Framework 的项目中,将 DSN 写入环境变量文件.env:
LIGHTSMS_DSN=lightsms://my_login:my_token@default?from=8613800138000Notifier 组件会通过TransportFactoryInterface机制自动识别lightsmsscheme 并实例化对应传输。从工厂测试 LightSmsTransportFactoryTest.php 可以看出,lightsms://login:token@default?from=37061234567会被判定为受支持的 DSN,而其他 scheme(如somethingElse://...)则被拒绝。
三、发送短信:从 SmsMessage 到网关请求
LightSms 传输层只接受SmsMessage类型的消息。在 LightSmsTransport::supports() 中,只对SmsMessage返回true;若向该传输传入ChatMessage等其它消息类型,doSend()会抛出UnsupportedMessageTypeException——这一点在测试的supportedMessagesProvider/unsupportedMessagesProvider中均有覆盖。
3.1 构造 SmsMessage
use Symfony\Component\Notifier\Message\SmsMessage; $sms = new SmsMessage('+37061234567', 'Hello from Symfony Notifier!'); // 可选:指定发送方号码,覆盖 DSN 中的 from $sms->from('37061234567');从 SmsMessage 的构造函数可以看到,其参数依次为phone、subject、from与options,其中from默认为空字符串。传输层在发送时遵循 CHANGELOG 6.2 引入的规则:若SmsMessage已设置from,则优先使用消息自身的发送方;否则回落为 DSN 中的from(见 doSend() 中的 sender 取值)。
3.2 底层请求的构造
doSend()是真正的发送逻辑,位于 LightSmsTransport.php。发送过程可以归纳为四步:
- 组装请求数据:包含
login、phone、sender、text与timestamp。其中phone会经过escapePhoneNumber()处理,把国际号码中的+前缀替换为00(例如+37061234567变为0037061234567),这是 LightSms 网关对国际号码的格式要求;text取自SmsMessage的 subject。 - 生成签名:调用
generateSignature()计算 MD5 签名(见下文)。 - 发起 HTTP 请求:请求端点格式为
{scheme}://{host}/external/get/send.php,使用 HTTP GET 方法,上述数据全部放在 query 字符串中。 - 校验并解析响应:网络异常或非 200 状态码都会抛出
TransportException;响应 JSON 中携带错误码,只有错误码为 0 才视为成功。
3.3 签名算法(核心机制)
LightSms 要求每次请求附带signature参数,用于服务端校验请求合法性。签名生成逻辑位于 generateSignature():
- 对除
signature外的全部请求参数按键名做ksort升序排序; - 取出所有值并按排序顺序拼接成一个连续字符串;
- 在该字符串末尾追加账户 Token(即 DSN 中的
TOKEN); - 对最终字符串计算
md5,结果即为签名值。
正因为签名覆盖了timestamp(当前 Unix 时间戳),请求具备时效性,Token 泄露后也无法被无限重放。发送方号码、文本内容、接收号码等任一字段变化都会导致签名不同。
四、响应解析与错误码
请求发送后,传输层将响应解析为数组,并按下述优先级提取错误码(doSend() 中第 126 行):
- 顶层
error字段; - 空键
''下的error字段; - 以接收号码
$phone为键的分组中的error字段。
错误码为0表示发送成功,此时会构造SentMessage,并在响应中存在id_sms字段时,把该值设置为消息 ID,便于后续对账查询。错误码非 0 时抛出TransportException,并附带人类可读的错误说明。
LightSmsTransport 中定义了完整的错误码映射表,常见的包括:
| 错误码 | 含义 |
|---|---|
| 1 | Missing Signature(缺少签名) |
| 4 | Phone number not specified(未指定手机号) |
| 6 | Invalid signature(签名无效) |
| 7 | Invalid login(登录名无效) |
| 9 | Sender name not registered(发送方未注册) |
| 10 | Sender name not approved(发送方未审核通过) |
| 11 | There are forbidden words in the text(文本含禁用词) |
| 12 | Error in SMS sending(短信发送出错) |
| 13 | Phone number is in the blacklist(号码在黑名单) |
| 14 | More than 50 numbers in the request(单次请求超过 50 个号码) |
| 16 | Invalid phone number(手机号无效) |
| 32 / 35 | Not enough money(余额不足) |
| 999 | Unknown Error(未知错误) |
未知错误码统一映射为999对应的 “Unknown Error” 文案。
五、测试与验证
该 Bridge 自带两层单元测试,是理解其行为契约的捷径:
- LightSmsTransportTest.php 验证:默认传输的字符串表示为
lightsms://www.lightsms.com?from=from;仅支持SmsMessage,拒绝ChatMessage与DummyMessage。 - LightSmsTransportFactoryTest.php 验证:合法 DSN 可成功创建传输;
lightsms之外的 scheme 不受支持;缺少登录名或 Token 的 DSN 会被判定为不完整(IncompleteDsnException)。
这些测试也提示了集成排错的方向:若工厂层报错,优先检查 DSN 是否完整(LOGIN:TOKEN与from);若传输层报错,则对照错误码表检查签名、发送方审核状态或余额。
六、小结与排错清单
接入 LightSms Notifier Bridge 的完整路径是:composer require symfony/light-sms-notifier(对应 composer.json 中的包名)→ 在环境变量中配置LIGHTSMS_DSN→ 构造SmsMessage并通过 Notifier 发送。
常见排错清单:
- 签名无效(错误码 6):确认 DSN 中的
TOKEN与账户实际 Token 完全一致,注意签名算法要求参数先排序再拼接; - 发送方未审核(错误码 10):确认 DSN 的
from号码已在 LightSms 完成注册与审核,或改用SmsMessage::from()指定已审核号码; - 手机号无效(错误码 16):确认号码格式,传输层会自动把
+转成00,号码本身需符合国际格式; - 明文 HTTP(非 8.2+ 的默认行为):默认走 HTTPS,如需明文请求可显式配置
ssl=0(该选项自 Symfony 8.2 起支持,见 CHANGELOG.md)。
对传输层更深入的实现细节,可直接阅读 LightSmsTransport.php 与 LightSmsTransportFactory.php,两份文件合计不足两百行,是学习 Symfony Notifier 自定义传输桥接的最佳样例之一。
- 后端
- Web框架
【免费下载链接】symfony
The Symfony PHP framework
相关推荐
QuickRecorder 教程:5 分钟用好这款不足 10MB 的 macOS 录屏工具,免虚拟声卡内录系统音
QuickRecorder 教程:5 分钟用好这款不足 10MB 的 macOS 录屏工具,免虚拟声卡内录系统音 QuickRecorder 是一款轻量 mac
后端Web框架Dagger TypeScript SDK 中 FunctionCallArgValueID 类型别名解析:对象唯一标识符的声明与实现
Dagger TypeScript SDK 中 FunctionCallArgValueID 类型别名解析:对象唯一标识符的声明与实现 FunctionCall
后端Web框架Symfony Notifier 集成 Bandwidth:DSN 配置、SmsMessage 发送与 BandwidthOptions 完整实战指南
Symfony Notifier 集成 Bandwidth:DSN 配置、SmsMessage 发送与 BandwidthOptions 完整实战指南 Symf
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考