php调用语音短信接口前须确认服务商是否支持:语音需单独开通权限、使用含/voice/或/tts/路径的专用接口(如sendvoicecode),传code、playtimes等参数,content-type必须为application/json并json_encode,且用真实手机号测试。

PHP 调用短信平台语音接口前,先确认是否真支持语音短信
绝大多数所谓“短信接口”服务商(如阿里云、腾讯云、容联云、亿美软通)的 SendSms 接口默认只发文本短信;语音短信是独立通道,需单独开通权限、使用不同接口(如 SendVoiceCode 或 sendTtsVoice),且资费更高。没确认就写代码,90% 会返回 "Action not supported" 或 404。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 登录服务商控制台,在「产品中心」或「API 文档」里搜索关键词
voice、tts、call,而不是只看「短信」分类 - 检查 API 文档中接口路径是否含
/voice/或/tts/(例如腾讯云是https://sms.tencentcloudapi.com/tts) - 调用前必须在控制台为该子账号或 API 密钥开启「语音验证码」权限,否则即使参数全对也会被拒绝
语音验证码发送必须传 PlayTimes 和 Code,不能只拼接 URL
和文本短信不同,语音验证码不是把内容塞进 TemplateParam 就行。它依赖 TTS 引擎朗读,所以必须明确告诉平台:验证码数字是什么、播几遍、是否需要按键确认。常见错误是直接复用短信模板参数,导致返回 "InvalidParameter.TemplateParamFormatError"。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
-
Code字段必须是纯数字字符串(如"123456"),不能带字母或符号,长度通常限制在 4–6 位 -
PlayTimes建议设为2(播两遍),避免用户没听清;设为1容易被投诉“听不清” - 部分平台(如容联云)要求额外传
DisplayNumber(显号),即用户看到的来电号码,这个号必须已在平台实名认证并启用语音功能
cURL 发送语音请求时,Content-Type 必须是 application/json,且需手动 json_encode
很多 PHP 示例代码仍用 http_build_query 拼 application/x-www-form-urlencoded,这在语音接口上基本都失败——因为语音接口统一要求 JSON 格式请求体,且字段嵌套更深(比如腾讯云要包在 SendTtsVoiceRequest 对象里)。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)),别漏掉JSON_UNESCAPED_UNICODE,否则中文变\uXXXX导致签名失败 - 必须显式设置头:
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']) - 检查返回值是否为 JSON 字符串,用
json_decode($res, true)解析后,优先判断['Response']['Error']是否存在,而不是只看 HTTP 状态码
测试阶段务必用真实手机号,且注意语音拨打间隔限制
几乎所有语音接口都有防刷策略:同一号码 60 秒内只能触发 1 次,1 小时最多 5 次。用测试号或模拟器打不通,不是代码问题,是平台主动拦截。另外,语音通话需要运营商网络支持,部分虚拟运营商号段(如 170/171)或物联网卡可能无法接通。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 调试时用自己实名的主卡手机号,避免用公司测试号池或小号
- 在代码里加日志记录每次请求的
PhoneNumber、Timestamp、Response,方便排查是否被限频 - 生产环境必须做本地频率控制(如 Redis 记录
voice:138****1234的最近一次时间),不能只依赖服务商限流,否则用户点太快会收到“系统繁忙”提示
语音短信的不可见性比文本高得多——用户没接到电话,你根本收不到回执;接通后没听清,也不会主动告诉你。所有异常分支(超时、无应答、关机)都要有降级方案,比如自动切回短信验证码,而不是卡在那儿等语音响。











