找我们接短信的客户里,PHP 网站占了不少:老官网、商城、会员系统,很多是几年前外包做的,现在要加一个注册验证码,或者下单后给客户发一条通知。代码不复杂,可我们帮人排查过的问题,很多跟“发送”本身无关,而是出在环境、超时和回调这些边角上。
这篇只讲 PHP 网站接入短信接口的思路,不绑定任何平台。各家文档的参数名会不一样,逻辑大同小异。
接短信接口前,先把三样东西备齐
动手写代码之前,先去短信平台后台把这几样准备好:
- 账号凭证:一般是一个 AppKey 加一个密钥,密钥只放服务器,绝不能写进前端 JS。
- 已审核的签名和模板:注册验证码一个模板,订单通知一个模板,分开申请。模板里的变量位置要提前想好,比如订单号、取货时间。
- 接口地址和文档:确认是正式环境地址,测试地址和正式地址混用是很常见的低级错误。
签名和模板没审下来就开始联调,只会看到一堆“模板不存在”的报错,白耽误工夫。
配置单独放,别写死在业务代码里
PHP 老项目最常见的写法,是在注册页面里直接拼一段 curl,密钥明文写在中间。后面换平台、改密钥,得满项目搜。
比较稳的做法是建一个单独的配置文件,放在网站根目录之外,或者至少不能被浏览器直接访问。再写一个短信发送的函数或类,业务代码只调用它,传手机号、模板编号和变量。以后短信接口要换,只改这一处。
PHP短信接口的调用写法
大多数短信接口是 HTTP 接口,用 PHP 自带的 curl 扩展就够了。流程用伪代码表示大概是这样:
params = { appkey, template_id, mobile, vars, timestamp, nonce }
params.sign = hash(按文档排序后的参数串 + secret)
resp = curl_post(api_url, json(params),
connect_timeout = 3s, timeout = 5s)
if resp 无法解析: 记日志, 交给重试
else 记录 resp.msg_id 和状态
签名对不上,多半是这几个原因
签名报错是联调阶段的头号问题。我们碰到最多的情况:参数排序和文档不一致;中文变量在拼串前后编码不一样;时间戳用了毫秒,文档要的是秒;服务器时区没设,时间差太大被平台拒绝。PHP 里 json 编码默认会把中文转成 \u 形式,如果平台按原文计算签名,这里也要处理一下。
curl 的几个坑
老服务器上 curl 访问 HTTPS 接口经常报证书错误,网上很多帖子教你把证书校验关掉,这一步不要照做,正确做法是更新服务器的 CA 证书包。另外一定要设置连接超时和总超时,不设的话,平台偶尔慢一下,用户点“获取验证码”的页面就一直转圈,PHP 进程也被占住。
注册验证码和订单通知,处理方式不一样
两类短信走的是同一个短信接口,但对失败的容忍度完全不同。
注册验证码要的是快。用户在页面上等着,超时之后最多重试一次,再不行就提示“稍后再试”,别在后台反复发,否则用户可能同时收到好几条验证码,反而更糊涂。验证码本身要存进 session 或缓存,设置有效期,校验一次就作废。
订单通知可以慢一点,但不能丢。这类短信更适合先写进数据库的待发表,再由定时任务去发:失败了隔一段时间重试,重试几次仍失败就标记出来人工处理。虚拟主机没有定时任务权限的话,可以考虑换到能跑 cron 的服务器,这也是很多老网站该升级的信号。
回调地址:拿到真实的发送结果
接口返回成功,只代表平台收下了这条短信,不代表用户手机已经收到。真实结果要靠状态回调。
PHP 这边写一个接收回调的页面就行,要点有三个:先按文档验签,防止别人伪造请求;用平台给的消息编号去更新数据库,同一条回执可能推送多次,所以要做去重;处理完尽快按平台要求返回成功标识,复杂逻辑放到后面异步跑,别让平台等超时。
上线前的自查
正式上线前,建议用自己和同事的手机,把注册、找回密码、下单通知各走一遍,顺便看看短信内容在不同手机上的显示是否正常。注册页面别忘了加图形验证或频率限制,防止被人恶意刷短信接口,这部分我们在另一篇防刷文章里专门讲过。
结论
PHP 网站接入短信接口,难点不在 curl 那几行代码,而在配置管理、签名细节、超时重试和回调处理。验证码求快,订单通知求稳,两种场景分开设计,后期维护会省心很多。如果你的网站是我们做的,或者想在现有 PHP 网站上加短信功能,可以直接打 18720919319 找蔚岚科技的技术同事聊聊,我们可以先看看你现在的代码结构再给建议。
常见问题
虚拟主机能用PHP调用短信接口吗?
一般可以,只要主机开了 curl 扩展并允许访问外网。问题在于很多虚拟主机不能跑定时任务,订单通知的重试就不好做,量大了建议换服务器。
网站短信接口的密钥放哪里比较安全?
放在服务器端的配置文件里,并且这个文件不能通过网址直接访问。前端页面只请求自己网站的后端,由后端去调用短信接口。
用户说没收到验证码,怎么查?
先看自己的发送日志有没有请求记录和消息编号,再看回调状态。日志里没有请求,是网站这边的问题;有请求但状态失败,再拿消息编号去问平台。
PHP老版本还能接吗?
能接,curl 和 json 函数老版本都有。但太老的 PHP 往往配的是过期的证书和扩展,安全上也有隐患,借这个机会升级一下比较稳妥。
订单通知短信需要用户同意吗?
订单、物流这类和交易直接相关的通知属于业务通知,用户下单时通常已经知情。但别借订单通知的模板夹带促销内容,营销短信要单独申请模板并带退订方式。