PHP使用header下载时文件名中文乱码解决

一般情况下, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件。

但是, 这样做, 就没办法做一些统计, 权限检查等的工作。于是, 很多时候, 我们采用让PHP来做转发, 为用户提供文件下载。

$file = "/tmp/english.tar.gz";
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header("Content-Length: ". filesize($file));
readfile($file);

但是这个有一个问题,就是如果文件是中文名的话,有的用户可能下载后的文件名是乱码。

按照RFC2231的定义, 多语言编码的Content-Disposition应该这么定义:

1.filename后面的等号之前要加 *

2.filename的值用单引号分成三段,分别是字符集(utf8)、语言(空)和rawurlencode过的文件名

3.最好加上双引号,否则文件名中空格后面的部分在Firefox中显示不出来

$file = "/tmp/中文名.tar.gz";

$filename = basename($file);

header("Content-type: application/octet-stream");

//处理中文文件名
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = rawurlencode($filename);
if (preg_match("/MSIE/", $ua)) {
 header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
 header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
} else {
 header('Content-Disposition: attachment; filename="' . $filename . '"');
}

header("Content-Length: ". filesize($file));
readfile($file);

我在IE11下测试后,发现IE的版本显示已经不是原来的MSIE这样的格式了,如MSIE 9.0。IE11的是这样的:rv:11.0。所以你需要对上面的代码中第一个if条件做简单的修改,如下。

if (preg_match("/MSIE/", $ua) or preg_match("/rv:/", $ua))

发表评论

电子邮件地址不会被公开。 必填项已用*标注