[完]PHP文件下载 下载GET值中含有中文字符的文件,保存中文文件名,文件不能打开,遇到的编码问题

编码问题

  • 使用Windows Server 2008英文版作为服务器,文件系统中文件名存储的编码与Windows“当前系统区域设置”相关。(例如:中文默认为GB2312,俄文为西里尔文Windows[windows-1251])

  • 文本编辑器采用的编码。

    • Windows Notepad默认的文字编码是ANSI。
    • Notepad++,可以通过“格式 | 转为UTF-8无BOM编码格式”,将编码转化为UTF-8无BOM格式。采用服务器的语言版本不一样时,有所差别,英文Windows 2008服务器时,PHP文件格式设为“UTF-8编码”,这样下载的文件才能正确打开。
  • 打开下载的文件出现问题。

    • 使用中文Windows 2008服务器时,PHP文件编码格式设为“UTF-8无BOM编码”
    • 使用英文Windows 2008 服务器时,PHP文件格式设为“UTF-8编码”
  • Web服务器采用Apache。默认编码为UTF-8,GET值的编码也是UTF-8。

# 设置PHP页采用的编码,如果使用Windows自带的Notepad编码,且不在首行设置编码,那么默认采用的是ANSI编码
header("Content-Type: text/html; charset=UTF-8");
$getFile = $_GET['f'];
echo 'GET filename: ' . $getFile . '<br/>';
# 将get中获取的filename转换成os认识的filename,这样file_exists()才认,才能下载相应文件。
$osFile = iconv('utf-8','GB2312', $getFile);
echo 'OS filename: ' . $osFile . '<br/>';
if( file_exists($osFile) ) {
    echo 'exist';
} else {
    echo 'not exist';
}

  http://192.168.1.102/test.php?f=中文.txt的执行结果

GET filename: 中文.txt
OS filename: ����.txt
exist 

  如果去掉上述代码的header("Content-Type: text/html; charset=UTF-8");,采用Notepad,但是另存为编码“UTF-8”的文件,执行结果和上面一样。如果采用Notepad默认ANSI编码,执行结果则是:

GET filename: 涓枃.txt
OS filename: 中文.txt
exist 
  • basename($pFileName):对含有中文字符的文件名无效,解决方法:
end(explode('/',$pFileName));
  • file_exists($fileName):对解析中文文件名有问题。主要是编码问题,只有将文件名转换为Windows服务器“当前系统区域设置”中语言采用的默认语言编码才行。
  • IE浏览器中,即使页面默认选择是UTF-8,链接中中文字符串依然使用GB2312编码,看下面代码在不同浏览器中执行var_dump()函数的结果
header("Content-Type: text/html; charset=UTF-8");
$getFile = $_GET['f'];

echo 'var_dump getFile: ';
var_dump($getFile);
echo '<br/>';

  PHP页面代码如上,使用http://192.168.1.102/test1.php?f=中文,访问页面。在不同浏览器中结果。

360,Chrome,FirefoxIE
var_dump getFile: string(6) "中文"var_dump getFile: string(4) "����"

使用一种为每个文件创建一个数字目录,去目录下搜索文件并下载,绕过GET传中文文件名。规避了各种编码问题。但是如果不注意Windows中“当前系统区域设置”的话,由中文服务器换到英文服务器上,会出现问题,需要将“当前系统区域设置”设置到“中文(简体,中国)”。

程序代码

下面代码可在360,Chrome和Firefox正常使用,但在IE下存在问题。

<?php
header("Content-Type: text/html; charset=UTF-8");
$getFile = $_GET['f'];
# 将浏览器传入的UTF-8编码的文件名,转换成Windows服务器认的GB2312编码,然后才能下载相关文件
$osFile = iconv('UTF-8','GB2312', $getFile);
downfile('./d/'.$osFile);

function downfile($osFile) {   
    if(file_exists($osFile)) {
        # basename() 消除文件路径,只保留文件名,对于中文出现问题,应该就是编码问题,
        # 处理好编码问题,应该可以使用basename()函数
        # $saveName = basename($osFile);
        $saveName = end(explode('/', $osFile)); 
        # 将Windows服务器认的GB2312编码,转换成浏览器认的UTF-8编码
        $saveName = iconv('GB2312', 'UTF-8', $saveName);     
        header("Content-Type: application/octet-stream");
        header("Accept-Ranges: bytes");
        # 计算文件大小,使用Windows服务器认的GB2312编码
        header("Accept-Length: ".filesize($osFile));
        # 在浏览器端保存文件,使用浏览器认的UTF-8编码
        header("Content-Disposition: attachment; filename=\"{$saveName}\"");
        # 读取文件,使用Windows服务器认的GB2312编码
        readfile($osFile);
    } else {
        echo "The file is not exist!";
    }
}
?>

下面代码可在IE,Chrome和Firefox正常使用,但在360下存在问题。

<?php
header("Content-Type: text/html; charset=UTF-8");
$getFile = $_GET['f'];
# 将浏览器传入的UTF-8编码的文件名,转换成Windows服务器认的GB2312编码,然后才能下载相关文件
$osFile = iconv('UTF-8','GB2312', $getFile);
$osPathFile = './d/'.$osFile;

$browser = $_SERVER['HTTP_USER_AGENT'];
# 如果是IE的话
if( strpos($browser, "Trident") > -1 || strpos($browser, "MSIE") > -1) {
    # 获取保存文件名
    $saveFile = $getFile;
    downFileIE( $osPathFile, $saveFile);
    # mb_convert_encoding与iconv功能类似,但是它是将第一个参数的原来编码放在最后一个参数位置,需要转变的编码是第二个参数
} else {
    downFile($osPathFile);
}

function downFile($osPathFile) {   
    if(file_exists($osPathFile)) {
        # basename() 消除文件路径,只保留文件名,对于中文出现问题,应该就是编码问题,
        # 处理好编码问题,应该可以使用basename()函数
        # $saveName = basename($osFile);
        $saveName = end(explode('/', $osPathFile)); 
        # 将Windows服务器认的GB2312编码,转换成浏览器认的UTF-8编码
        $saveName = iconv('GB2312', 'UTF-8', $saveName);    

        header("Content-Type: application/octet-stream");
        header("Accept-Ranges: bytes");
        # 计算文件大小,使用Windows服务器认的GB2312编码
        header("Accept-Length: ".filesize($osPathFile));
        # 在浏览器端保存文件,使用浏览器认的UTF-8编码
        header("Content-Disposition: attachment; filename=\"{$saveName}\"");
        # 读取文件,使用Windows服务器认的GB2312编码
        readfile( $osPathFile);
    } else {
        echo "The file is not exist!";
    }
}

function downFileIE($osPathFile, $saveFile) {   
    if(file_exists($osPathFile)) {
        header("Content-Type: application/octet-stream");
        header("Accept-Ranges: bytes");
        # 计算文件大小,使用Windows服务器认的GB2312编码
        header("Accept-Length: ".filesize($osFile));
        # 在浏览器端保存文件,使用浏览器认的UTF-8编码
        header("Content-Disposition: attachment; filename=\"{$saveFile}\"");
        # 读取文件,使用Windows服务器认的GB2312编码
        readfile('./d/'.$saveFile);
    } else {
        echo "The file is not exist!";
    }
}
?>

如果服务器保存的是其他国家语言的文本,可以统一将程序中GB2312编码,转换相应国家的语言编码,注意在Windows系统设置中,将“当前系统区域设置”设置成相应的国家和语言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值