2017-03-16 43 views
7

我间歇性地得到这个问题在我的PHP脚本(PHP 5.6,Apache 2.2的):PHP 5.6:headers_sent间歇返回true,空文件名和行0

警告:无法修改标题信息 - 头已经在/path/to/index.php发送上线55

此警告没有,我在这个其他问题已经看到了部分“由派”,所以我只是说这个代码在违规之前header()setcookie()来电:

if (headers_sent($filename, $linenum)){ 
    echo("Output buffer: #" . ob_get_contents() . "#"); 
    echo "Headers already sent in $filename on line $linenum: "; 
    print_r(headers_list()); 
} 

这里发生了问题,当我得到的输出:

Output buffer: ## 
Headers already sent in on line 0: 
Array (
    [0] => X-Powered-By: PHP/5.6.23 
    [1] => Content-type: text/html; charset=UTF-8 
) 

(附注:我已经output_buffering设置在php.ini 4096个字节,所以不应该在这两个标题中的63个字符缓冲并且等待更多,而不是被过早发送?)

这个问题出现在我首次启动一个包含Web服务器的Docker容器。之后,只有(但不是总是)在我第一次访问我的网站(可能是一两个小时)时发生,当我拨打header()setcookie()来登录用户或重定向到登录页。

我看了又看this answer误差一般“已经发送了头”,并且,尽我的能力,我已经排除了这些可能的原因:

  1. HTML块或来电printecho,等我之前我的PHP代码之外调用setcookie()header()
  2. 空白
  3. 的BOM
  4. auto_prepend_file php.ini中设置
  5. gzip流编码 - zlib的安装,但zlib.output_compression是关
  6. 重复extension= php.ini设置

这个答案提到

这是典型的PHP扩展或php.ini中设置,如果没有错误来源具体化。

所以,我现在希望通过我的扩展... get_loaded_extensions给了我这些条目51长度的数组:

Core, date, ereg, libxml, openssl, 
pcre, zlib, filter, hash, Reflection, 
SPL, session, standard, apache2handler, bz2, 
calendar, ctype, curl, dom, exif, 
fileinfo, ftp, gd, gettext, iconv, 
mysqlnd, PDO, Phar, posix, shmop, 
SimpleXML, snmp, soap, sockets, sqlite3, 
sysvmsg, sysvsem, sysvshm, tokenizer, xml, 
xmlwriter, xsl, mysql, mysqli, pdo_mysql, 
pdo_sqlite, wddx, xmlreader, json, zip, mhash 
我不使用所有这些

,所以我打算去通过并删除未使用的,并希望其中一个导致这个问题。

最糟糕的情况下,我会尝试碰撞我的output_buffering值或使用ob_start()ob_end_flush()来开始和结束我的文件。我不知道为什么这会解决它,当我目前的output_buffering价值4096没有,我明白,这个解决方法带来了自己的问题。

我在这里错过了什么 - 是否有其他可能的原因,我需要检查?我应该尝试不同的PHP版本,或者在没有扩展名的纯PHP安装中运行我的代码的子集?

编辑:添加了ob_get_contents()调用和输出,以及有关能够通过旋转新的Docker容器来持续复制此信息的信息。删除了有关我的error_reporting值的信息;更改此仅揭示了always_populate_raw_post_data弃用通知,修复对此处描述的问题没有影响。

+1

请提供您设置的完整PHP文件代码并检查里面的标题。我想这是一个'index.php'?如果包含,则请提供包括索引文件在内的整个包含链源。 –

+1

您是否在入口点脚本的开头调用'ob_start()'?这从你的问题不清楚,但没有'ob_get_contents()'不会工作。另外,尝试使用'var_dump(ob_get_contents())'。我认为这比直接回显值更好,因为它会说明字符串的长度。 –

+0

你是怎么确定修复'always_populate_raw_post_data'这个东西不能解决问题的?这当然是一个原因。另一个说明 - 查看成功加载的扩展将无济于事;很可能会引发相反的错误 - 失败*来加载扩展。如果它表示第0行,那么可以确定它与代码无关,但在PHP本身初始化时会触发某些事件。 – Narf

回答

1

在取出一些未使用的遗留代码(包括require_once调用到所有遗留代码的文件)后,此问题不再发生。它可能在我最初观察到的“间歇性”条件下复发,但是我的再现方法不再出现这个问题。

我不知道为什么这似乎有所帮助 - 删除的行完全位于<php? ?>标签内,我检查删除的文件中标签,BOM和CRLF外部的空白。

我也不知道为什么这个问题是间歇性的;如果它与删除的代码或文件有关,它应该每次都发生。

感谢所有的意见和答案!

1

我已经看到由于过去的行结束格式而出现问题。你是否将文件从一个操作系统环境移动到另一个?

有时隐藏的回车符(/ r)或其他特殊的空白字符可能会导致这种情况,但在文件中不可见。

+0

感谢您的提示;我正在将文件从Windows移动到PHP并返回。然而,我没有找到任何使用这里描述的几种方法的CRLF:http://stackoverflow.com/q/73833/877682 – Aaron

1

它可以是UTF8 BOM字符,或错误的换行符,不可打印的字符,错误的PHP关闭标签(我不使用它们,以防止endline问题)。即使没有这样的问题,即使你想尽一切办法来阻止它,它也可以(也将会)在以后发生。问题可能出在FTP服务器,文本编辑器,错误的PHP配置,编码,错误的cgi配置上。为了避免所有这些我用空的输出缓冲区,刚开始在第一个PHP文件

的index.php buffreing:

if(version_compare(PHP_VERSION, '7.0.0') >= 0 || ob_get_level() < 1) 
    ob_start(); 

HtmlResponce.php:

ob_end_clean(); 
echo $this->getRenderedContent(); 

FileResponce.php:

ob_end_clean(); 
readfile($this->content); 

在php5和php7中输出缓冲有几点区别,也可以输出缓冲可以配置在php.ini中有所不同,并且在cgi和apache mod配置上有所不同。你不应该继续“默认”配置。要处理警告消息,请使用set_error_handler(),如果您开始新项目时看到symfony components,我在CMS中使用了很多这些消息。这是您有机会通过奇怪的PHP错误防止不眠之夜。

+0

正如我的回答中所提到的,我排除了你所描述的常见问题(尽我所能),我想尽可能避免使用'ob_start',因为性能原因。感谢您的建议;当我开始一个新的PHP项目时,我一定会检查一下symfony组件。 – Aaron

+1

在这种情况下没有性能松动。输出前缓冲器关闭。没有双缓冲 - 不增加内存使用。 –

+0

经过一番研究之后,我认为输出缓冲与性能优势相关是错误的。对于巨大的输出(比如超过200KB)来说这是一个坏主意,但这不适用于我的情况。谢谢你让我变直! – Aaron