codeigniter 2 中文文件名上传乱码源于 windows 下 $_files['name'] 为 gbk 编码而 ci2 全程按 utf-8 处理,需在 set_filename() 和 move_uploaded_file() 中双向 iconv 转码,并确保 iconv 扩展启用及 default_charset 配置正确。

CodeIgniter 2 在 Windows 开发、Linux 部署时,中文文件名上传后变成乱码(如“测试.pdf”存为“娴嬭瘯.pdf”),根本不是框架不支持中文,而是 $_FILES['userfile']['name'] 在 Windows+IE/Edge 下默认是 GBK 编码字节流,而 CI2 的 Upload 类全程按 UTF-8 处理路径拼接和文件操作,导致 file_exists() 和 move_uploaded_file() 内部字节比对失败。
Upload 类 set_filename() 必须双向转码
只改一处会出问题:检查是否存在同名文件要用目标编码(GBK),但后续逻辑(比如返回 $this->upload->data('file_name'))仍需 UTF-8。不能跳过任一环节。
- 定位到
system/libraries/Upload.php中的set_filename()方法,在生成$filename后、调用file_exists()前插入:$filename = iconv('UTF-8', 'GB2312//IGNORE', $filename); - 在
file_exists($path . $filename)判断之后、赋值给$this->file_name之前,再转回:$filename = iconv('GB2312', 'UTF-8', $filename); - 如果启用了
$config['encrypt_name'] = TRUE,跳过上述转换——哈希逻辑依赖原始字节,强行转码会破坏一致性
do_upload() 中 move_uploaded_file() 路径必须同步编码
move_uploaded_file() 是系统级调用,Windows 文件系统只认 GBK 路径字节;Linux 一般认 UTF-8,但跨平台部署时建议统一处理,否则上传成功却找不到文件。
- 找到
do_upload()方法里类似@move_uploaded_file($this->file_temp, $this->upload_path . $this->file_name)这一行 - 把目标路径包裹进
iconv():@move_uploaded_file($this->file_temp, iconv('UTF-8', 'GB2312//IGNORE', $this->upload_path . $this->file_name)) -
//IGNORE很关键:遇到无法映射的字符(比如某些生僻字)直接丢弃,避免整个上传因单个字符失败 - 若确定只跑 Linux 且
locale是zh_CN.UTF-8,可省略此步;但 CI2 项目常需兼容 Windows 服务器,建议保留
更稳妥的替代方案:前端标准化 + 后端映射
硬改核心类风险高,升级 CI3/CI4 又成本大。生产环境推荐绕过编码博弈,用业务层控制命名逻辑。
- 前端上传前用 JS 对
File.name做标准化:encodeURIComponent(file.name)或生成唯一 ID + 保留原始名存 DB - 后端接收时,
$config['file_name']设为英文名(如md5(time().rand()).pdf),同时把原始中文名存进数据库字段或 session - 下载时通过 ID 查原始名,用
Content-Disposition: attachment; filename*=UTF-8''...告诉浏览器解码方式 - 这样既规避了
$_FILES编码不可控问题,又保持了用户感知的中文体验
真正容易被忽略的是:iconv() 在部分 Linux 环境下可能未启用,得先确认 extension=iconv.so 已加载;另外,Windows 服务器上 PHP 的 default_charset 若设为 GBK,反而会让 UTF-8 字符串被二次编码——这些细节不排查,光改 Upload 类也没用。











