[完]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系统设置中,将“当前系统区域设置”设置成相应的国家和语言。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果你想要在你的 PHP 应用程序中下载文件,你可以使用 PHP 的函数 `readfile()` 来读取文件内容并将其发送到浏览器。你也可以使用 `header()` 函数来设置 HTTP 头信息,以指示浏览器将文件作为下载进行处理。 下面是一个简单的例子,展示了如何使用 PHP 下载文件: ```php <?php // 设置 HTTP 头,指示浏览器将文件作为下载进行处理 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="file.txt"'); // 读取文件内容并将其发送到浏览器 readfile('file.txt'); ?> ``` 在这个例子中,我们将文件类型设置为 `application/octet-stream`,这表示文件是一个二进制流,浏览器应该将其作为下载进行处理。我们还使用了 `Content-Disposition` 头来指定文件名,这样浏览器就会弹出“保存文件”对话框,让用户选择保存文件的位置。最后,我们使用 `readfile()` 函数读取文件内容并将其发送到浏览器。 请注意,在使用 `header()` 函数设置 HTTP 头之前,不能有任何输出(包括空白字符)。否则,将会出现“头信息已发送”错误。 ### 回答2: 在 PHP 中,可以通过使用 `file_put_contents` 函数将文件保存到服务器本地。首先,需要确保服务器具有写入权限。以下是一个示例代码: ```php <?php if(isset($_POST['file_url'])){ $file_url = $_POST['file_url']; // 获取要下载文件 URL $filename = basename($file_url); // 获取文件名 $save_path = '/path/to/save/'.$filename; // 保存路径,根据实际情况进行修改 if(file_put_contents($save_path, file_get_contents($file_url))){ echo "文件下载成功!"; } else{ echo "文件下载失败!"; } } ?> ``` 在上述示例中,我们通过 `file_get_contents` 函数读取文件内容,然后使用 `file_put_contents` 函数将文件内容保存到指定的路径。要下载文件,我们需要使用表单或其他方法将文件 URL 传递给上述代码进行处理。 注意,如果要下载文件很大,这种方式可能会占用大量的服务器内存。为了避免这种情况,可以考虑使用 PHP 的 `stream_copy_to_stream` 函数,它可以在保存之前将文件内容逐个字节地复制到目标文件中。 当然,这只是基本的示例,实际应用中可能需要进行错误处理、文件验证等等。 ### 回答3: 在PHP中,我们可以使用以下代码在应用程序中下载文件: ```php <?php $file = '路径/到/文件/文件名.ext'; // 要下载文件路径 if (file_exists($file)) { // 设置响应头以强制下载文件 header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($file)); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); readfile($file); exit; } else { echo '该文件不存在!'; } ?> ``` 上述代码中,首先我们指定要下载文件路径。接下来,我们检查该文件是否存在。如果文件存在,我们通过设置响应头来告诉浏览器强制下载文件。然后,我们使用 `readfile()` 函数将文件内容输出到浏览器。 请注意,你需要将 `路径/到/文件/文件名.ext` 替换为实际的文件路径和文件名。 如果文件不存在,我们将输出一条错误消息。 希望这个回答对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值