我有一个强制下载脚本,它能在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。
您的PHP脚本文件似乎是用UTF-8编码的,BOM位于文件开头的<?php
分隔符之前。这些字节是在实际输出之前发送的,因此会损坏数据。
您只需要删除它,并将编辑器配置为不使用UTF-8的BOM。
EF BB BF
是标准的UTF-8字节顺序标记。有些人报告说,当脚本中包含的一些PHP文件是UTF-8编码的时,就会发生这种情况;PHP的某些版本对此作出反应,发送UTF-8字节顺序标记。上面的链接建议在脚本开始时调用ob_start()
,在开始推出文件内容之前调用ob_end_clean()
——这样字节顺序标记就会被捕获到输出缓冲区中。
此外,您可以简单地使用fpassthru
将文件管道传输到输出,而不是在循环中读取和写入。
EF BB BF
是UTF-8编码的字节顺序标记(BOM)。我怀疑有一些配置选项可以关闭BOM。
编辑:文件编辑器应允许您在以相关字符编码(如UTF-8)保存文件时关闭BOM。