thinkphp多语言短信需从语言包动态取模板并替换变量,不可硬编码或运行时翻译;占位符必须为{key}格式;需过滤用户输入防xss;异步队列中须显式传递并重置语言;语言包键名须严格一致。

ThinkPHP 多语言短信不是靠“自动翻译内容”实现的,而是靠在发送前把短信模板字符串从语言包中动态取出来,再填充变量。直接拼接中文字符串再用 lang() 去套,不起作用。
短信内容必须从语言包里取,不能硬编码或运行时转译
很多人误以为只要开启了多语言,lang('sms.verify') 就能在发短信时自动按当前语言返回对应文本——这没错,但前提是:你得把短信正文本身写进语言包,而不是只写个提示语或错误消息。
- 错误做法:
$content = '您的验证码是'.$code;,再试图用lang()包一层 - 正确做法:语言包里定义带占位符的完整句子,例如
'sms.verify' => '您的验证码是{code},5分钟内有效。' - 发送时调用
lang('sms.verify', ['code' => $code]),ThinkPHP 会自动替换{code} - 注意:占位符语法必须是
{key},不是:code或$code,否则不生效
短信模板变量插值要防 XSS,尤其用户输入参与拼接时
如果短信内容里混入了用户可控字段(比如昵称、订单号),直接丢进 lang() 可能导致 HTML 实体未转义、特殊字符截断或服务端解析失败。
- 腾讯云/阿里云 SDK 对短信内容有长度和字符集限制,含 \0、\r\n、控制字符大概率被静默截断或报错
407 - 建议对所有变量做白名单过滤:
strip_tags($name)+mb_substr($name, 0, 12, 'utf-8') - 不要用
htmlspecialchars(),它会把中文变成实体,短信里显示为乱码 - 若需保留简单格式(如换行),用
str_replace(["\n", "\r"], '', $input)更稳妥
发送逻辑里别依赖当前请求语言,显式传 lang 参数
短信常走队列异步发送,而队列任务执行时没有 HTTP 上下文,lang() 默认读的是 default_lang 或 session 中的语言标识,很可能不是用户注册/下单时选的那个。
- 在投递队列时,把当前语言代码一并存进去:
['lang' => app('lang')->getLangSet(), 'mobile' => $mobile, 'code' => $code] - 消费者中先
app('lang')->setLangSet($data['lang']),再调用lang('sms.verify', [...]) - 不推荐用 Cookie 或 Session,它们在线程/进程间不可见;也不要用
config('app.default_lang')硬切,会覆盖全局 - 如果你用的是
think-queue,记得在job类的fire()开头加语言重置逻辑
真正容易被忽略的是语言包键名一致性——lang/zh-cn/sms.php 和 lang/en-us/sms.php 必须有完全相同的 key 列表,缺一个,lang() 就 fallback 到空字符串或默认值,线上可能发出去空白短信都不知道为什么。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











