PHP下载中文文件名乱码须用RFC 5987标准:filename*="UTF-8''%E4%B8%AD%E6%96%87.pdf",禁用普通filename;需rawurlencode()处理、清空输出缓冲、设置no-cache头,并按浏览器兼容(如IE用GBK转换)差异化处理。

PHP下载文件时中文名乱码的典型表现
直接在 Content-Disposition 中写 filename="中文.pdf",浏览器可能显示为问号、下划线或截断,甚至触发 500 错误——这不是 PHP 报错,是 HTTP 头字段违反 RFC 标准导致的解析失败。
必须用 filename* 而不是 filename
RFC 5987 明确规定:非 ASCII 字符必须使用 filename*,并以 UTF-8'' 编码前缀声明。浏览器(Chrome/Firefox/Edge)只认这个,filename 字段仅限 ASCII。
实操建议:
- 始终优先设置
filename*,再补一个兼容旧 IE 的filename(纯英文或拼音) -
filename*的值需经rawurlencode()处理,不能用urlencode()(后者把空格转成+,不符合 RFC) - 中文名示例:
filename*=UTF-8''%E4%BD%A0%E5%A5%BD.pdf
header() 顺序和缓存控制很关键
一旦输出过任何内容(包括空格、BOM、echo),header() 就会失败,报 “headers already sent” 错误。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 下载逻辑前加
ob_end_clean()清除已有输出缓冲,比依赖ob_start()更可靠 - 务必设置
Cache-Control: no-cache和Pragma: no-cache,否则部分浏览器(尤其 Safari)可能复用旧响应,导致名字没变但文件内容是缓存的 - 完整头示例:
header('Content-Type: application/octet-stream'); header('Content-Length: ' . filesize($filepath)); header('Content-Disposition: attachment; filename="report.pdf"; filename*=UTF-8\'\''.rawurlencode('报表_2024年10月.pdf')); header('Cache-Control: no-cache'); header('Pragma: no-cache');
Windows 下 IE/Edge 对 filename* 支持不一致
IE11 和旧版 Edge(EdgeHTML)对 filename* 解析有 bug,可能忽略或崩溃;它们只认 filename,且只接受 GBK 编码(不是 UTF-8)。
实操建议:
- 检测 User-Agent 是否含
MSIE或Trident,若是,用iconv('UTF-8', 'GBK', $name)转换后填入filename - 不要试图让 IE 支持
filename*,它根本不按 RFC 实现 - 如果业务允许,直接用英文+时间戳命名(如
report_20241015.pdf),避开所有编码问题



















