PHP中openssl_encrypt必须配对使用openssl_decrypt,加密结果需base64_encode后存储传输,解密前须base64_decode;AES-256-CBC要求32字节二进制密钥(用hash('sha256',$key,true)生成)、随机IV并绑定密文。

PHP 用 openssl_encrypt 加密字符串时必须配对使用 openssl_decrypt
PHP 原生不推荐再用 mcrypt(已废弃),openssl_encrypt 是当前标准做法。但加密结果不是“直接可读字符串”,默认输出是二进制,直接 echo 会乱码或截断——必须用 base64_encode 编码后才能安全存储或传输。
常见错误:只加密不 base64 编码,或解密前忘了 base64_decode,导致 openssl_decrypt 返回 false。
-
$cipher = 'AES-256-CBC'是较稳妥的选择;避免用 ECB 模式(不安全) - 密钥长度必须匹配算法要求:
AES-256需要 32 字节密钥,不足则需hash('sha256', $key, true)补齐 - IV(初始化向量)必须随机生成、且和密文一起保存,解密时原样传入;不能硬编码或复用
完整可运行的 AES-256-CBC 加解密示例
以下代码能直接复制测试,注意替换 $password 和处理异常:
为什么不要用 md5 或 sha1 直接当密钥
它们输出是 32/40 字符十六进制字符串(即 64/80 字节),而 AES-256 要求的是 32 字节二进制密钥。直接传入会导致 openssl 函数静默失败或返回 false。
立即学习“PHP免费学习笔记(深入)”;
- 正确做法:用
hash('sha256', $key, true)的第三个参数true强制返回原始二进制 - 错误写法:
md5($key)→ 得到 32 字符字符串,长度是 32 字符 ≠ 32 字节(UTF-8 下中文等字符占多字节) - 如果密钥来自用户输入,建议加盐(如
hash_hmac('sha256', $password, $salt, true))提升抗暴力能力
加密后字符串长度不稳定?这是正常现象
AES-CBC 是分组密码,明文会被填充(PKCS#7),所以即使只加密一个字符,输出长度也至少是 16 字节(IV)+ 16 字节(密文块)。base64 编码后还会膨胀约 33%。不要试图“压缩”结果或截断——解密必然失败。
实际部署时容易忽略两点:
- 数据库字段类型要用
TEXT或足够长的VARCHAR(比如 512 字符以上),不能设成VARCHAR(32) - 前后端传输时,确保 URL 或表单字段不因特殊字符(如
+、/、=)被篡改;必要时用strtr($b64, '+/', '-_')做 URL 安全 base64
IV 和密文绑定、密钥派生方式、编码格式这三者只要有一处不一致,解密就彻底失败——没有中间状态。











