ThinkPHP中需用openssl_decrypt配合base64_decode后的session_key和iv,采用AES-128-CBC与OPENSSL_NO_PADDING手动去除PKCS#7填充来解密encryptedData;关键点包括code实时换取session_key、严格base64编解码、避免参数被URL/JSON转义、不复用session_key。

ThinkPHP里怎么解密微信小程序传来的encryptedData
微信小程序调用 getPhoneNumber 后,前端会把加密的手机号数据(encryptedData、iv、code)发到后端,ThinkPHP 本身不内置微信 AES-128-CBC 解密逻辑,得自己补全——关键是别直接用 PHP 原生 openssl_decrypt 硬套,容易因填充方式或 key 处理出错。
实操要点:
-
code必须立刻拿去微信接口换session_key,不能缓存或复用,过期时间约 5 分钟 -
session_key是 32 字节 base64 字符串,解密前要base64_decode成原始二进制,不是直接当字符串用 - AES 模式固定为
CBC,填充必须是 PKCS#7(PHP 7.1+ 的openssl_decrypt默认支持,但低版本需手动补位) - 微信的
iv也是 base64 编码,同样要先base64_decode
示例片段(ThinkPHP 6 控制器中):
use think\facade\Log;
<p>$encryptedData = $this->request->post('encryptedData');
$iv = $this->request->post('iv');
$code = $this->request->post('code');</p><p>// 1. 换 session_key
$res = json_decode(file_get_contents("<a href="https://www.php.cn/link/e16b7c6134db5e15a521ec10fd405ddf">https://www.php.cn/link/e16b7c6134db5e15a521ec10fd405ddf</a>"), true);
if (empty($res['session_key'])) {
return json(['msg' => 'code无效或已使用']);
}
$sessionKey = base64_decode($res['session_key']);
$ivDecoded = base64_decode($iv);</p><p>// 2. 解密
$decrypted = openssl_decrypt($encryptedData, 'AES-128-CBC', $sessionKey, OPENSSL_ZERO_PADDING, $ivDecoded);
// 注意:微信返回数据是标准 PKCS#7 填充,OPENSSL_ZERO_PADDING 会导致失败,应改用 OPENSSL_PKCS1_PADDING?不对——实际要手动去除 PKCS#7 填充
// 正确做法是用 OPENSSL_NO_PADDING + 手动去填充
$decrypted = openssl_decrypt($encryptedData, 'AES-128-CBC', $sessionKey, OPENSSL_NO_PADDING, $ivDecoded);
$padLen = ord($decrypted[strlen($decrypted) - 1]);
$decrypted = substr($decrypted, 0, -$padLen);</p>
为什么解出来是乱码或空字符串
这不是 ThinkPHP 的锅,是微信加密数据结构和 PHP 解密参数没对齐。最常踩的三个坑:
-
encryptedData传过来时被 URL 解码或 JSON 自动转义过,比如+变成空格、/被吃掉——必须原样接收,建议前端用encodeURIComponent包一层,后端用urldecode还原 - 误把
session_key当作明文 key 直接传给openssl_decrypt,漏了base64_decode,导致 key 长度不对(44 字节 base64 → 32 字节二进制) - 没校验解密后 JSON 结构,微信返回的是含
phoneNumber、purePhoneNumber、countryCode的对象,但解密失败时可能返回空或非法 JSON,直接json_decode会静默失败
ThinkPHP Session 和微信 session_key 别混用
名字都叫 session,但完全无关:think\facade\Session 是框架的服务器端会话存储,而微信的 session_key 是加解密用的一次性密钥。有人试图把 session_key 存进 ThinkPHP Session 里复用,这是危险操作——它本就不该持久化,且多个用户共用一个 key 会导致解密错乱。
- 每次请求都应独立完成「code → session_key → 解密」全流程
- 如果业务需要绑定用户,应在解密成功后,用解出的
openId(从解密结果里取)关联本地账号,而不是靠 session_key - 别在控制器里写死 APPID / SECRET,走配置文件或环境变量,避免泄露
PHP 版本和 OpenSSL 扩展的隐性影响
PHP 7.1 以下默认不支持 OPENSSL_PKCS1_PADDING 对应 AES,而微信要求 PKCS#7 填充;PHP 8.1+ 则对空 IV 或错误 padding 更敏感,报错更直接。OpenSSL 扩展必须启用,且不能是阉割版(比如 Alpine Linux 的 php81-opcache 包可能不含 openssl)。
- 检查是否启用:
extension_loaded('openssl'),不是openssl函数存在就代表可用 - 用
openssl_get_cipher_methods()确认aes-128-cbc在列表里 - 测试时用已知有效的
encryptedData+iv+code组合,避免前端调试干扰判断
真正卡住的地方,往往不是算法写错,而是 base64 编解码环节少了一次 decode,或者前端传参时悄悄做了 trim 或转义。解密这一步,宁可多打几行日志看中间值,也别猜。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










