如何修复这个破坏文件的PHP下载脚本?

时间:2011-06-13 09:37:08

标签: php download

我有一个强制下载脚本,可以使用PDF和纯文本生成良好的结果,并且对ZIP压缩文件是半正常的(它们在Windows中运行,而不是在Linux中运行)。但是,应用程序文件和图像都会失败。这些构成了我必须处理的绝大多数文件。正如我在这里看到的关于类似主题的建议,压缩所有下载不是一种选择。

将失败的文件下载到其完整大小,并以正确的名称写入磁盘。尝试打开它们会导致错误消息,这种消息因类型而异。将下载的文件与 hexdump 中的原始文件进行比较,我可以看到该脚本在每个下载文件的开头插入以下字符:

ef bb bf

下载的文件会再现原件,直到它停止在指定的大小 - 因此原始的最后6个字符总是丢失。

不幸的是,我对二进制文件的构成方式,这些字符的含义以及脚本插入方式的原因和原因一无所知。

这是原样:

$file = '94.ppt';
$path = $_SERVER['DOCUMENT_ROOT']."/relative/path/";
$full_path = $path.$file;
if ($fd = fopen ($full_path, "r")) {
    $fsize = filesize($full_path);
    $path_parts = pathinfo($full_path);
    $ext = strtolower($path_parts["extension"]);
    switch ($ext) {
        case "pdf":
            header("Content-type: application/pdf");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "txt":
            header("Content-type: text/plain");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "jpg":
            header("Content-type: image/jpeg");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        case "ppt":
            header("Content-Type: application/vnd.ms-powerpoint");
            header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
        break;
        default;
            header("Content-type: application/octet-stream");
            header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
    }
    header("Content-Transfer-Encoding: binary");
    header("Content-length: $fsize");
    header("Cache-control: private");
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
}
fclose ($fd);
exit;

开发系统是Apache 2.2.14(Ubuntu)上的PHP 5.3.2-1。 Apache 2.0.63(某种类型的Linux)上的生产主机是PHP 5.2.9。

3 个答案:

答案 0 :(得分:3)

EF BB BF是标准的UTF-8 byte order mark。有些人reported,当你在脚本中包含的一些PHP文件是UTF-8编码时会发生这种情况;某些版本的PHP通过发送UTF-8字节顺序标记来对此作出反应。上面的链接建议在脚本开头调用ob_start()并在开始推出文件内容之前调用ob_end_clean() - 这样字节顺序标记就会被输出缓冲区捕获。

此外,您只需使用fpassthru将文件传输到输出,而不是循环读取和写入。

答案 1 :(得分:3)

您的PHP脚本文件似乎在UTF-8 with BOM中编码,该文件位于打开<?php分隔符之前的文件的开头。这些字节在实际输出之前发送,从而破坏您的数据。

您只需将其删除并将编辑器配置为不使用BOM表为UTF-8。

答案 2 :(得分:1)

EF BB BF是UTF-8编码Byte Order Mark(BOM)。我怀疑有一些配置选项可以关闭BOM。

编辑:文件编辑器应允许您在以相关字符编码(例如UTF-8)保存文件时关闭BOM。