编码问题:
使用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,Firefox | IE |
---|---|
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系统设置中,将“当前系统区域设置”设置成相应的国家和语言。