ThinkPHP如何做数据加密_ThinkPHP敏感信息加解密操作【教程】
ThinkPHP 6 的数据加密问题,最近不少团队都碰上了。核心变化就一句话:Crypt 类已经被彻底移除,别再写 `Crypt::encrypt()` 了。现在官方推荐用 `think-helper` 扩展,或者自己用 OpenSSL 手动实现。但别看加密好像只是调个函数,密钥长度怎么定、IV 要

ThinkPHP 6 的 think\facade\Crypt 已废弃,别再用
TP6 默认没有内置加解密组件,Crypt 类在 6.0.0 版本里直接被移除了。如果你还在写 Crypt::encrypt(),运行时会报 Class 'think\facade\Crypt' not found。官方推荐的方案是改用 think-helper 扩展,或者直接用原生的 openssl 自己封装。别抱着老文档不放,迁移必踩坑。
用 think-helper 做 AES 加解密(推荐方案)
think-helper 封装了 OpenSSL,支持 AES-128-CBC 和 AES-256-CBC,密钥和 IV 自动处理,比手写要安全也省事得多。安装很简单:composer require topthink/think-helper。不过有几个注意事项:
- 加密时必须传字符串,不能直接传数组或对象——否则会悄悄转成
"Array"字符串,解密时直接失败。 - 密钥长度必须是 16 字节(AES-128)或 32 字节(AES-256),最好用
md5()或hash('sha256', $key)对原始密钥做规整,否则长度不对 OpenSSL 会报错。 - 示例:
$encrypted = \think\helper\Str::encrypt('user_token_123', 'my_secret_key_2024');返回的是 base64 编码字符串,可以直接存数据库。
手动用 openssl_encrypt 要小心 IV 和填充
绕过扩展直接调 PHP 原生函数,看似灵活,但最容易出错——尤其是在环境切换(PHP 7.4 → 8.2)或迁移服务器时。几个关键点:
- IV 每次必须随机生成,不能硬编码。而且 IV 要和密文一起保存,通常拼成
$iv . $cipher,解密时再切出来。千万别复用同一个 IV。 - AES-CBC 模式要求输入长度是 16 字节的整数倍,所以必须手动做 PKCS#7 填充。TP5 的
Crypt是自动处理好的,自己写很容易漏,解密时返回false都不知道错在哪。 - PHP 8.1+ 已经废弃了
mcrypt,别搜到老教程直接用mcrypt_encrypt,运行就报错。 - 常见的错误现象:
openssl_decrypt返回false。排查思路很明确:检查 IV 是否匹配、密钥长度对不对、解密时有没有正确截出 IV 段。
敏感字段加密后查询怎么处理?
数据库里存的是密文,那就没法直接用 where('phone', '138****') 来查——因为加密结果每次不同(IV 随机),甚至不能用 LIKE 做模糊查询。这个问题比加密本身更棘手。
- 手机号、身份证这类需要查询的字段,有人用“确定性加密”(比如 AES-ECB + 固定 IV),但 ECB 模式本身不安全,只有在低敏感且严格控制的场景下才勉强可用。
- 更稳妥的做法:查询前先把密文解密后缓存起来(比如 Redis 存
phone_hash => id),或者用非对称加密配合索引字段分离——明文存phone_md5专门用来查,密文存phone_enc用来展示。 - ThinkPHP 的模型事件(
sa ving/retrieving)可以统一做加解密,但注意不要误操作到非敏感字段,否则性能和无意义解密都是麻烦。
加密本身没那么复杂,真正考验人的是:密钥怎么管理、IV 怎么传递、查询怎么设计、升级时怎么平滑迁移。这些地方没想清楚,上线后才发现解不开、查不了、换服务器全乱套——那才是真头疼。


































