codeigniter 不支持文件级加密,应采用访问控制与字段加密结合方案:敏感文件通过 .htaccess 禁止直访并由控制器代理下载;数据库敏感字段用 encryption 类加密,密钥须为 32 字节二进制且从环境变量加载。

CodeIgniter 本身不提供文件级加密能力,所谓“文件加密”在 CI 生态里基本是误解或误用——你真正需要的,是「敏感文件访问控制」和「字段级数据加密」两件事,它们解决的是完全不同的风险面。
为什么不能对整个文件(如 PDF、LOG)用 CI 的 encryption 类加密?
CI 的 encrypt() 和 decrypt() 是为字符串设计的,不是为二进制文件流。直接传入 file_get_contents('report.pdf') 可能触发内存溢出、编码损坏或 base64 膨胀失控(PDF 原本几 MB,加密后可能翻倍且无法流式读取)。
- 加密结果是 base64 字符串,不是可执行/可渲染的原始文件格式
- 解密后需手动写回磁盘或输出 header,中间多一重 I/O 和内存压力
- 没有内置分块处理机制,大文件极易超时或 OOM
- CI 加密类不支持自定义 IV 或 cipher mode 控制,无法对接标准文件加密工具链(如 OpenSSL 命令行)
真正该做的:用 .htaccess + 控制器代理拦截敏感文件访问
把日志、报表、私有附件等放在 public/logs/ 或 public/reports/ 下,但禁止 Web 服务器直出——这是最轻量也最有效的“文件加密等效方案”。
- 在
public/logs/.htaccess中写:<files> Deny From All </files>
- 在控制器里写下载逻辑,例如:
Logs_controller::download($filename) - 方法内先做权限校验:
if (!$this->auth->is_admin()) { show_403(); } - 再用
readfile(FCPATH . 'public/logs/' . $filename)输出,并配好Content-Type和Content-Disposition - 关键点:路径必须用
FCPATH拼接,不能拼 URL;$filename必须白名单过滤或哈希映射,严禁直接透传$_GET['f']
数据库字段加密必须用 encryption 类,但密钥配置错就全废
身份证号、手机号、银行卡号这类字段,才适合走 CI 内置加密流程。但只要 $config['encryption_key'] 不对,decrypt() 就永远返回空字符串——不是报错,是静默失败。
- 密钥必须是 32 字节二进制数据,不能是明文字符串:
$config['encryption_key'] = hex2bin('a1b2c3...'); - 生成方式只能是本地跑一次:
php -r "echo bin2hex(openssl_random_pseudo_bytes(32));",然后手动填进config.php - 字段类型必须是
TEXT或MEDIUMTEXT,VARCHAR(255)存不下——"123" 加密后约 136 字符,还带 padding - CI 3.x 加载方式是
$this->load->library('encryption'),调$this->encryption->encrypt($id_card);CI 4.x 改用service('encrypter')->encrypt($id_card) - 别在模型里重复加载库,也别在构造函数里提前 load——
encrypt()依赖完整 CI 初始化,否则会报Call to a member function encrypt() on null
加密算法和驱动不可控,别试图“选 AES-GCM”或“固定 IV”
CI 3.x 自动探测 mcrypt→openssl→crypt,PHP 7.2+ 实际只剩 OpenSSL 可用;CI 4.x 默认 AES-256-CTR+SHA512,但改配置要继承 Config\Encryption 类,且改了旧数据就再也解不开。
- 所有版本都强制随机 IV,每次
encrypt()输出不同——这是正确行为,不是 bug - 想实现确定性加密(比如用于索引)?CI 不支持,得换 libsodium 或自己封装
openssl_encrypt() - 检查 OpenSSL 是否启用:
php -m | grep openssl,没输出就装扩展,光配 CI 没用 - 不要在生产环境用
$this->encryption->create_key(32)动态生成密钥——它只该在开发机跑一次
最常被忽略的一点:加密不是万能锁。密钥一旦硬编码在 config.php,又和数据库同服务器,那加密字段和明文其实安全水位差不多。真要防拖库,密钥得从环境变量或 KMS 服务读取,而 CI 默认不支持——这层必须自己补。











