不能直接调用sendsms()发验证码,因php无内置短信功能,须通过阿里云/腾讯云等第三方http接口,按规范传template_id、phone_number、sign_name及严格匹配占位符的json格式template_param。

能发,但不是直接调用某个叫“验证码接口”的东西——你得用短信服务商提供的通用 HTTP 接口,自己拼参数、加签名、控制频率和模板。
为什么不能直接用 sendSms() 发验证码
PHP 本身没有内置短信功能,所有发送都依赖第三方服务商(如阿里云、腾讯云、容联云、亿美软通)。这些平台不提供“验证码专用函数”,只开放标准的短信发送 API,你必须按规则提交:template_id、phone_number、sign_name 和 template_param(即验证码数字)。
- 常见错误现象:
InvalidTemplateParam—— 模板里写的是{code},但你传了{"verify_code":"123456"},实际要传{"code":"123456"} - 使用场景:注册、登录、修改手机号,每次都要走同一套 HTTP 请求逻辑,只是
template_id和template_param不同 - 参数差异:
template_param必须是 JSON 字符串(不是 PHP 数组),且键名严格匹配模板中定义的占位符
阿里云/腾讯云 SDK 发短信时最常踩的坑
官方 SDK 看起来省事,但默认行为容易埋雷:
-
sendSms()默认不校验手机号格式,"138abcd1234"也能发出去(服务商侧返回失败),建议自己用preg_match('/^1[3-9]\d{9}$/', $phone)过滤 - 阿里云要求
SignName必须已审核通过,本地测试时填错一个字(比如“某某科技”写成“某科技”)就报SignatureDoesNotMatch - 腾讯云 SDK 的
SmsClient::SendSms()返回数组结构不稳定,$res['SendStatusSet'][0]['Code']才是真正状态码,别直接看$res['Code'] - 没做请求限流:同一号码 60 秒内重复调用,大概率被服务商拒绝,得自己加
file_get_contents('/tmp/sms_138xxxxxxx.lock')或 Redis 锁
不用 SDK,纯 cURL 发验证码更可控
尤其适合轻量项目或调试阶段,避开 SDK 版本兼容、自动重试等干扰项:
立即学习“PHP免费学习笔记(深入)”;
- 必须带
Content-Type: application/json,否则阿里云返回MissingParameter - 签名字符串生成顺序不能错:把
AccessKeyId、AccessKeySecret、Timestamp、SignatureMethod按字典序拼接后 HMAC-SHA256 加密 - 示例关键字段(阿里云):
{"RegionId":"cn-hangzhou","PhoneNumbers":"138xxxxxxxx","SignName":"你的备案签名","TemplateCode":"SMS_123456789","TemplateParam":"{\"code\":\"889900\"}"} - 腾讯云则用 GET + 签名拼在 URL 上,
Nonce和Timestamp必须每次不同,否则报AuthFailure.SignatureFailure
真正卡住人的,往往不是怎么发,而是模板审核不通过、签名没备案、IP 被限频、或者验证码值没从 session/Redis 里正确读出来就塞进 template_param。这些地方不打日志,问题就藏得特别深。











