TP6短信验证码实现需绕开隐藏陷阱,核心是生成→存储→发送→校验四步闭环:存储禁用Session,改用手机号绑定缓存键;发送优先用EasySms扩展并从环境变量读密钥;校验前检查Session初始化、跨域问题及验证码是否已消耗;统一处理大小写与空格。

TP6 接口短信验证码的实现,关键不在“写不写得出代码”,而在于绕开那些上线就崩、测试总失败的隐藏陷阱。核心是四步闭环:生成 → 存储 → 发送 → 校验,但每一步都有典型断点。
存储别碰 Session,用手机号+缓存键绑定
很多人一上来就写 session('sms_code', $code),结果换浏览器失效、多手机号切换串号、5分钟过期却存24小时——全是 Session 的锅。
- 改用缓存键明确绑定手机号:
cache('sms_code_' . $mobile, $code, 300)(单位秒) - 发送前先检查是否已有未过期记录:
if (cache('sms_code_' . $mobile) !== null) return fail('请勿频繁请求') - 校验时也按同一 key 读取,彻底和 Session 解耦,前后端分离、多子域、小程序都稳
发送别手写 curl,优先用 EasySms 扩展
直接调阿里云或云片的 API,自己拼 curl 容易翻车:SSL 验证失败、没重试、密钥硬编码、异常没捕获……看似省事,实则埋雷。
- 装社区维护的稳定包:
composer require overtrue/easy-sms - 密钥从环境变量读:
env('ALIYUN_ACCESS_KEY_SECRET'),绝不出现在控制器里 - 配置收口在
config/sms.php,发送失败 catch 异常并记日志,方便排查网络抖动或配额超限
校验失败?先查这三件事
90% 的 captcha_check() 返回 false,不是逻辑错,而是底层支撑断了。
-
Session 没真正启动:TP6 默认注释了
\think\middleware\SessionInit::class,必须在app/middleware.php中取消注释 -
前后端域名不一致:比如网页在
www.example.com,接口走api.example.com,跨子域导致 session_id 完全不同 -
验证码已被消耗:校验成功后自动清除,JS 按钮没禁用、用户刷新重填旧值,都会失败;调试时可加
dump(session('sms_code'))看是否存在
大小写与空格要统一处理
用户输入带空格、前端传大写、后端比对小写,一来一回就校验失败。这不是 bug,是疏忽。
- 接收参数时立刻 trim + strtolower:
$input = strtolower(trim($this->request->param('code'))) - 缓存里存的 code 也保持小写,避免大小写混用引发不一致
- 前后端约定好格式,接口文档写清楚:仅接受6位纯数字,不支持字母或符号

















