直接用阿里云官方PHP SDK最稳妥,因自行硬塞SmsDemo.php会导致类加载失败、密钥硬编码泄露、无异常捕获、验证码生成不规范等问题;正确做法是Composer安装SDK、配置分离、缓存存储、严格校验模板变量与响应。

直接用阿里云官方 PHP SDK 最稳妥,别自己拼 HTTP 请求或硬塞 SmsDemo.php 到控制器里——那不是对接,是埋雷。
为什么不能直接丢 SmsDemo.php 进控制器
很多教程让你把阿里云下载的 SmsDemo.php 放进控制器、改命名空间、删示例代码。这会导致几个实际问题:
-
SmsDemo.php依赖的aliyun-php-sdk-core和aliyun-php-sdk-dysmsapi没走 Composer 自动加载,容易报Class not found - 硬编码
accessKeyId/accessKeySecret在业务文件里,一不小心就提交到 Git,密钥立刻失效 - 没有异常捕获和重试逻辑,网络抖动或限流时直接崩,前端卡在“发送中”
- 验证码生成用
rand(0, 999999)+str_pad,但没做前导零校验,比如生成123会变000123,而用户可能输123导致校验失败
正确接入步骤:SDK + 配置分离 + 缓存存储
ThinkPHP5.1 原生支持 Composer,必须利用好:
- 执行
composer require alibabacloud/sdk(推荐)或composer require aliyun-openapi-php-sdk(兼容老项目) - 把
accessKeyId、accessKeySecret、SignName、TemplateCode全部写进config/sms.php,而不是任何控制器或模型里 - 验证码生成改用
random_int(100000, 999999),避免rand()可预测性问题 - 存储必须用缓存(
Cache::set()),过期时间设为 300 秒,key 格式建议sms_code_{$phone},不要用 Cookie 或 Session——后者跨设备、易被清空
调用时注意模板变量和返回值解析
阿里云模板里写的 ${code},传参时必须用关联数组:['code' => '123456'],不是 ['Code' => '123456'] 或 ['CODE' => '123456'],大小写敏感且键名必须和模板里 ${xxx} 的 xxx 完全一致。
立即学习“PHP免费学习笔记(深入)”;
调用后别只看 $response->getCode() === 'OK',还要检查 $response->getMessage() 是否为 'OK',因为部分错误(如签名未审核通过)会返回 Code=OK 但 Message='Invalid SignName'。
示例关键片段:
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ServerException;
try {
$code = random_int(100000, 999999);
Cache::set('sms_code_' . $phone, $code, 300);
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
->version('2017-05-25')
->action('SendSms')
->method('POST')
->options([
'query' => [
'PhoneNumbers' => $phone,
'SignName' => config('sms.sign_name'),
'TemplateCode' => config('sms.template_code'),
'TemplateParam'=> json_encode(['code' => (string)$code], JSON_UNESCAPED_UNICODE),
],
])
->request();
if ($result->getStatusCode() == 200 && $result->toArray()['Message'] === 'OK') {
return true;
}
} catch (ServerException $e) {
// 记录 $e->getErrorMessage(),别吞掉
}
验证码校验环节最容易漏掉的点
用户提交验证码后,校验逻辑常被简化成 “取缓存比对”,但真实场景要多三步:
- 先查缓存是否存在,不存在直接返回“验证码已过期”——别等比对失败才说错
- 比对成功后,立刻
Cache::rm('sms_code_' . $phone),防止重放攻击 - 如果用户连续输错 3 次,应临时锁定该手机号 15 分钟(用另一个缓存 key 控制),否则暴力枚举成本极低
复杂点不在发,而在收——发出去只要一次 HTTP 调用,收回来要扛住并发、防刷、防重放、防过期、防密钥泄露。每个环节漏一个,整个验证链就断了。



















