CodeIgniter 不支持直接文件加密,仅能加密内存中读取的文件内容;因加密类面向小数据设计,大文件会超内存限制且不支持分块加密,须上传后读取、加密存库、解密输出,密钥需动态管理。

CodeIgniter 本身不提供文件级加密能力,它只负责应用层数据加解密;所谓“文件加密”,实际是把文件内容读入内存后加密存储,或解密后写回临时文件——直接加密磁盘上某个 report.pdf 或 config.json 是行不通的,也不该由框架干。
为什么不能直接加密整个文件?
CI 的 Encryption 类设计目标是保护数据库字段、session 数据、cookie 值等「结构化小数据」,不是为大文件流式加解密优化的。你调用 $this->encryption->encrypt($file_content) 时,PHP 必须把整个文件载入内存,100MB 的日志文件会直接触发 memory_limit 报错。OpenSSL 驱动也不支持分块 IV 同步,手动切片加密会导致解密失败。
- 加密类底层依赖
openssl_encrypt(),它要求完整明文一次性传入 - 数据库字段加密时已膨胀 2.6 倍,文件再这么搞,
TEXT字段根本存不下 - 没有文件元信息(如原始文件名、MIME 类型)封装机制,解密后只剩裸字节
真正可行的“敏感文件加密”路径
把文件当「值」处理,而不是「资源」:上传 → 读取内容 → 加密 → 存数据库或加密文件系统 → 解密 → 输出响应。关键在控制权是否还在 PHP 应用内。
- 用户上传身份证扫描件:
$_FILES['id_card']['tmp_name']→file_get_contents()→$this->encryption->encrypt()→ 存进users.id_card_encrypted(字段类型必须是LONGTEXT或BLOB) - 导出加密报表:查数据库密文字段 →
$this->encryption->decrypt()→file_put_contents('export-temp.pdf', $decrypted_bytes)→readfile()→unlink() - 绝对不要做:
exec('openssl enc -aes-256-cbc -in config.json -out config.json.enc')—— 这绕过 CI 安全上下文,密钥管理失控,且无法审计
加密密钥必须和文件生命周期解耦
文件可能跨年留存,而密钥一旦写死就不能改——所以 $config['encryption_key'] 不能来自配置文件硬编码,得从环境变量或 KMS(密钥管理服务)动态加载,否则换服务器或重装环境就全废。
- Linux 下通过
putenv('CI_ENCRYPTION_KEY=' . file_get_contents('/etc/secrets/ci-key.bin'))注入二进制密钥(注意:不是 hex 字符串) - CI 4.x 可在
app/Config/Encryption.php中覆盖$key属性:public $key = getenv('CI_ENCRYPTION_KEY') ?: ''; - 别用
base64_encode(file_get_contents())存密钥——这等于明文,HMAC 验证照样失败
解密失败时先盯住这三处
90% 的“解密返回空”问题和算法无关,纯粹是数据流转断点:
-
var_dump($row->encrypted_file)看值是不是NULL或FALSE—— 数据库没读出来,后面全白搭 - 确认字段类型是
LONGTEXT(MySQL)或BYTEA(PostgreSQL),VARCHAR(255)会静默截断 - 检查
$this->encryption->decrypt()输入是不是字符串:如果从 JSON API 接收,json_decode($input, true)后变成数组,传进去就报strlen() expects parameter 1 to be string
文件加密的本质是「把 IO 操作拉进应用可信边界」,而不是给磁盘加个锁。所有中间态(临时文件、内存缓冲、数据库字段)都必须按加密数据规格设计,否则安全链从第一个字节就读错了。


















