mcrypt扩展在PHP 8.2中已彻底移除,函数完全不可用;PHP 7.1起弃用、7.2默认禁用、8.0删除源码、8.2无痕,手动编译或PECL安装均失败,因内核已剥离该功能。

mcrypt 扩展在 PHP 8.2 中已彻底移除,不是“报错”而是“根本找不到函数”,mcrypt_encrypt、mcrypt_decrypt、mcrypt_create_iv 等全部不可用。
为什么 mcrypt_encrypt 直接报 Fatal error: Uncaught Error: Call to undefined function
PHP 7.1 开始标记为 deprecated,7.2 起默认不启用,8.0 正式删除源码,8.2 完全无痕。即使你手动编译 mcrypt 扩展,也无法通过 PHP 的扩展加载机制注册函数——它已被从内核剥离。这不是配置问题,是架构级移除。
- 别试
pecl install mcrypt:PHP 8+ 的 pecl 已下架该包,强行编译会失败或触发符号冲突 - 别依赖“系统自带 mcrypt”:Linux 发行版的 libmcrypt 库存在,但 PHP 不再链接它
- 错误信息典型是:
Fatal error: Uncaught Error: Call to undefined function mcrypt_encrypt()
openssl_encrypt 替换时最常踩的三个坑
直接把 mcrypt_encrypt(MCRYPT_RIJNDAEL_128, ...) 换成 openssl_encrypt('AES-128-CBC', ...) 大概率解密失败,原因不在算法名,而在填充和编码行为差异。
-
填充方式不同:mcrypt 默认用
"\0"(NUL)补位;OpenSSL 默认用 PKCS#7。若原数据长度刚好是块长倍数(如 16 字节),mcrypt 不补,OpenSSL 会额外补 16 个0x10字节 → 解密后多出乱码 -
输出格式默认不同:mcrypt 返回原始二进制;
openssl_encrypt默认返回 base64 编码字符串(等价于传了OPENSSL_BASE64)。若旧系统存的是 raw 密文,新代码必须加OPENSSL_RAW_DATA选项 -
IV 长度校验更严:mcrypt 对 IV 长度容忍度高(如 AES-CBC 要 16 字节,给 15 字节也能跑);OpenSSL 严格校验,
openssl_cipher_iv_length('AES-128-CBC')必须返回 16,否则抛error:0607F08A
如何让 OpenSSL 加解密结果与 Mcrypt 完全一致
核心是两件事:统一填充逻辑 + 统一输出格式。不能靠“默认行为”,必须显式控制。
立即学习“PHP免费学习笔记(深入)”;
- 加密前手动补 NUL:对明文
$data,执行$padded = $data . str_repeat("\0", 16 - (strlen($data) % 16 ?: 16)) - 加密时禁用 OpenSSL 自动填充:
openssl_encrypt($padded, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv) - 解密后手动去 NUL:
rtrim($decrypted, "\0")(注意不是trim,避免误删原文末尾的 \0) - 密钥长度必须合规:AES-128 要 16 字节,不足补、超长截。可用
$key = substr(hash('sha256', $key, true), 0, 16)
迁移后仍解密失败?优先检查这三处
90% 的残留问题都卡在这几个细节上,和算法本身无关。
-
$iv是否用了相同来源?mcrypt 常用mcrypt_create_iv(..., MCRYPT_RAND),OpenSSL 应用openssl_random_pseudo_bytes()或random_bytes(),不能复用字符串 IV(如硬编码十六进制字符串)而不做 hex2bin - base64 编解码是否多套了一层?旧代码可能
base64_encode(mcrypt_encrypt(...)),新代码若又base64_encode(openssl_encrypt(...))就变成双重编码 - 字符编码是否一致?
mb_strlen($data, '8bit')和strlen($data)在含中文时结果不同,补位字节数会错
真正麻烦的不是函数替换,而是历史数据兼容——那些用 mcrypt 加密存在数据库里的密文,必须用完全相同的填充+编码逻辑还原。一旦上线,就再没机会“试错”。



















