php文件加密应使用openssl_encrypt/decrypt配合aes-256-cbc,密钥需sha256二进制化,iv每次随机生成并随密文存储,密文须base64编码,严禁硬编码密钥或复用iv。

PHP 文件内容加密用 openssl_encrypt,别碰 mcrypt
PHP 7.2+ 已彻底移除 mcrypt 扩展,硬启用会报 Call to undefined function mcrypt_encrypt()。现在标准做法是 openssl_encrypt + openssl_decrypt,配合 AES-128-CBC 或 AES-256-CBC(推荐后者)。密钥必须是固定长度(如 32 字节对应 AES-256),不能直接用字符串当密钥——得用 hash('sha256', $raw_key, true) 转成二进制密钥。
常见错误:用 md5($key) 当密钥(长度够但不可控)、IV 复用(同一个 IV 加密多个文件会导致模式泄露)、没 base64 编码密文就写入文件(二进制内容会损坏或截断)。
- IV 必须每次随机生成,且和密文一起保存(比如前 16 字节),解密时原样取出
- 加密后务必
base64_encode()再写入文件;解密前先base64_decode() - 不要把密钥写死在代码里,更不要拼接进文件路径或日志
读取加密文件并解密的三步:读、解、验
读取时不能假设文件一定存在或格式正确。典型失败场景:文件被截断、base64 解码失败、openssl_decrypt 返回 false(此时 openssl_error_string() 可查具体原因,比如密钥错、IV 长度不对、填充异常)。
- 先用
file_get_contents()读全文件,再base64_decode(),失败则终止 - 拆出前 16 字节为 IV,剩余为密文;IV 长度必须严格等于
openssl_cipher_iv_length('AES-256-CBC') - 解密后建议校验明文结构(比如 JSON 是否能
json_decode($plain, true)成功),防密钥误用导致乱码被当成有效数据
写入加密文件时最容易漏掉的两个细节
一是没处理 padding。AES-CBC 要求明文长度是块大小(16 字节)的整数倍,openssl_encrypt 默认用 PKCS#7 填充,但如果你手动截断或拼接内容,可能破坏填充结构;二是权限控制。加密不是访问控制——文件仍可被读,只是内容不可读。如果 PHP 进程有权限读写,攻击者拿到文件+密钥(比如从配置中泄露)就能解密。
立即学习“PHP免费学习笔记(深入)”;
- 写入前确保目录可写、磁盘空间足够,否则
file_put_contents()静默失败 - 加密后的文件后缀别用
.php或.inc,避免 Web 服务器意外解析执行 - 敏感文件写入后建议
chmod(0600, $path)限制权限,尤其在共享主机环境
为什么不用 password_hash 或 hash_hmac 做文件加密
password_hash 是单向哈希,不可逆,只适合存密码;hash_hmac 是消息认证码,用于验证完整性,不提供机密性。文件加密必须满足「可逆」+「抗窃听」,只有对称加密函数满足。有人试过用 openssl_encrypt 的 OPENSSL_RAW_DATA 标志省去 base64,结果文件里出现 \0 字符,导致部分函数(如 file()、explode())提前截断——这种二进制边界问题,调试起来比密钥错误还隐蔽。
真正麻烦的从来不是加解密函数调用本身,而是密钥生命周期管理、IV 安全分发、以及加密后文件如何被其他系统安全消费——这些环节一旦松动,前面所有加密都形同虚设。











