我使用PHP重定向来自我的网站的下载,基本上是读取远程流并从我的网站回显它(这是我在需要下载以绕过防火墙时快速开发的实用程序)。
上次我检查了一下,效果还不错。昨天我想添加一个功能,发现返回的流前面有4个空白字符。我不明白这些是从哪里来的。无论发生什么,下载的文件总是以开头(4个空格,用Notepad++中的"查看不可见字符"模式确保),否则不会更改。
[编辑]回答一条评论:这些空格是原始文件的部分,而不是部分。为了测试这种行为,我下载了原始文件(用于简单测试的JPG),然后通过代理下载,并将两者进行了区分。4字节的差异,可以通过删除代理文件的前四个字符来解决。当然,在我解决差异之前,代理的文件是不可用的。
[Edit2]这些字符看起来也不是BOM。记住,有4个。维基百科告诉我们UTF-8 BOM将是3字节长:
BOM的UTF-8表示形式是字节序列

。将文本误解为ISO-8859-1或CP1252的文本编辑器或web浏览器将为此显示字符download
。
现在我想不出我在代码中所做的任何更改可以解释这种新行为。也许是PHP的更新?我在这台服务器上还没有phpinfo(今晚会得到一个),但这是在最新的Ubuntu 14.04上运行的。
我想我必须修改代码才能解决它。只是我不知道怎么做。也许有人会有线索可以试一下?
以下是代码:
function download($url, $filename, $mimetype) {
/* prepare filename */
// [prepare $filename]
// mess with the headers to bypass the proxy
header('Content-Type: ' . $mimetype['mime']);
header("Content-Disposition: attachment; filename=$filename");
// and now the file content
IOUtils::readfile($url);
}
借据:
<?php
/**
* Static utilities for IO.
*
* @author Cyrille Chopelet
*/
class IOUtils {
/**
* Copies the content of the file as a stream into the response stream.
* <p>
* This could seem to be a useless override for the PHP readfile function,
* but this is bufferized so that available memory is not overflowed
* when reading a large file.
*
* @param string $path the URI to the file
*/
public static function readfile($path) {
$handle = fopen($path, 'rb');
while (!feof($handle)) {
echo fread($handle, 8192);
ob_flush();
}
fclose($handle);
}
}
?>
在调用header
函数之前不进行任何输出。否则,这显然会失败,因为一旦输出启动,就不能调用$handle
。这意味着这似乎是在读取<?
或将其写入流时发生的。
根据上面的评论,我的猜测是:
- 自动输出缓冲已启用
- 某些文件正在发送输出,可能是打开标记
header()
之前的空白字符
由于输出缓冲,对header()
的调用不会失败。要查找输出的发送位置,请尝试在调用error_reporting
之前使用以下代码刷新所有活动的输出缓冲区
while (@ob_end_flush())
;
如果启用了警告,您应该会看到类似的内容:
Warning: Cannot modify header information - headers already sent by (output started at path/to/file.php:1)
如果没有看到任何警告,请检查您的0xEF,0xBB,0xBF
0、display_errors
和CCD_12设置。