PHP流开头不需要的空白字符


Unwanted blank characters at beginning of PHP stream

我使用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。这意味着这似乎是在读取<?或将其写入流时发生的。

根据上面的评论,我的猜测是:

  1. 自动输出缓冲已启用
  2. 某些文件正在发送输出,可能是打开标记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,0xBF0、display_errors和CCD_12设置。