ThinkPHP如何实现敏感数据的高效加密与解密操作?
- 内容介绍
- 文章标签
- 相关推荐
本文共计740个文字,预计阅读时间需要3分钟。
TP6默认不包含内置加密组件,Crypt 类在6.0.0版本中已被移除。继续使用 Crypt::encrypt() 会导致错误:
用 think-helper 做 AES 加解密(推荐方案)
它封装了 OpenSSL,支持 AES-128-CBC / AES-256-CBC,密钥和 IV 自动处理,比手撸更安全、兼容性更好。
- 安装:
composer require topthink/think-helper - 加密时必须传入字符串,不能直接加密数组或对象 —— 否则会静默转成
Array字符串导致解密失败 - 密钥长度必须为 16 或 32 字节(对应 AES-128 / AES-256),用
md5()或hash('sha256', $key)对原始密钥做规整 - 示例:
$encrypted = \think\helper\Str::encrypt('user_token_123', 'my_secret_key_2024');返回的是 base64 编码字符串,可直接存数据库
手动用 openssl_encrypt 要小心 IV 和填充
绕过扩展直接调用 PHP 原生函数看似灵活,但极易出错,尤其在跨环境(如 PHP 7.4 → 8.2)或换服务器时。
- IV 必须每次随机生成,且和密文一起保存(比如拼成
$iv.$cipher),不能硬编码或复用 - AES-CBC 模式要求输入长度是块大小(16 字节)的整数倍,需手动 PKCS#7 填充 —— TP5 的
Crypt自动做了,自己写容易漏 - PHP 8.1+ 已废弃
mcrypt,别搜到老教程还用mcrypt_encrypt,运行就报错 - 错误现象:
openssl_decrypt returns false,大概率是 IV 不匹配、密钥长度不对,或解密时没截出正确的 IV 段
敏感字段加密后查询怎么处理?
数据库里存的是密文,意味着无法直接用 where('phone', '138****') 查询 —— 加密结果每次不同(因 IV 随机),也不能用 LIKE 模糊查。
立即学习“PHP免费学习笔记(深入)”;
- 手机号、身份证这类需查询的字段,建议用「确定性加密」(如 AES-ECB + 固定 IV),但 ECB 不安全,仅限低敏且严格控制场景
- 更稳妥的做法:查前先解密缓存(如 Redis 存
phone_hash => id),或用非对称加密 + 索引字段分离(如明文存phone_md5用于查,密文存phone_enc用于展示) - TP 的模型事件(
saving/retrieving)可以统一加解密,但注意避免对非敏感字段误操作
本文共计740个文字,预计阅读时间需要3分钟。
TP6默认不包含内置加密组件,Crypt 类在6.0.0版本中已被移除。继续使用 Crypt::encrypt() 会导致错误:
用 think-helper 做 AES 加解密(推荐方案)
它封装了 OpenSSL,支持 AES-128-CBC / AES-256-CBC,密钥和 IV 自动处理,比手撸更安全、兼容性更好。
- 安装:
composer require topthink/think-helper - 加密时必须传入字符串,不能直接加密数组或对象 —— 否则会静默转成
Array字符串导致解密失败 - 密钥长度必须为 16 或 32 字节(对应 AES-128 / AES-256),用
md5()或hash('sha256', $key)对原始密钥做规整 - 示例:
$encrypted = \think\helper\Str::encrypt('user_token_123', 'my_secret_key_2024');返回的是 base64 编码字符串,可直接存数据库
手动用 openssl_encrypt 要小心 IV 和填充
绕过扩展直接调用 PHP 原生函数看似灵活,但极易出错,尤其在跨环境(如 PHP 7.4 → 8.2)或换服务器时。
- IV 必须每次随机生成,且和密文一起保存(比如拼成
$iv.$cipher),不能硬编码或复用 - AES-CBC 模式要求输入长度是块大小(16 字节)的整数倍,需手动 PKCS#7 填充 —— TP5 的
Crypt自动做了,自己写容易漏 - PHP 8.1+ 已废弃
mcrypt,别搜到老教程还用mcrypt_encrypt,运行就报错 - 错误现象:
openssl_decrypt returns false,大概率是 IV 不匹配、密钥长度不对,或解密时没截出正确的 IV 段
敏感字段加密后查询怎么处理?
数据库里存的是密文,意味着无法直接用 where('phone', '138****') 查询 —— 加密结果每次不同(因 IV 随机),也不能用 LIKE 模糊查。
立即学习“PHP免费学习笔记(深入)”;
- 手机号、身份证这类需查询的字段,建议用「确定性加密」(如 AES-ECB + 固定 IV),但 ECB 不安全,仅限低敏且严格控制场景
- 更稳妥的做法:查前先解密缓存(如 Redis 存
phone_hash => id),或用非对称加密 + 索引字段分离(如明文存phone_md5用于查,密文存phone_enc用于展示) - TP 的模型事件(
saving/retrieving)可以统一加解密,但注意避免对非敏感字段误操作

