我在我的PHP脚本(PHP 5.6,Apache 2.2)中间歇性地遇到这个问题:
警告:无法修改标头信息 - 标头已在第 55 行的/path/to/index.php 中发送
此警告没有我在有关此问题的其他问题中看到的"发送者"部分,因此我在违规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
)
(旁注:我在 php.ini 中output_buffering设置为 4096 字节,所以这两个标头中的 63 个字符不应该缓冲并等待更多,而不是过早发送吗?
当我第一次启动包含 Web 服务器的 Docker 容器时,就会出现此问题。之后,它只会(但并非总是)发生在我一段时间内(可能是一两个小时)第一次访问我的网站时,当我调用header()
并setcookie()
登录用户或重定向到登录页面时。
我已经阅读并重新阅读了对一般"标头已发送"错误的回答,并且尽我所能排除了这些可能的原因:
- HTML阻止或调用
print
,echo
等,然后我调用setcookie()
或header()
- 我的 PHP 标签外的空格
- 物料清单
auto_prepend_file
php.ini设置gzip
流编码 - 已安装 zlib,但zlib.output_compression
已关闭- 复制
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
弃用通知,修复对此处描述的问题没有影响。
我看到这个问题是由于过去行结束格式而出现的。您是否要将文件从一个操作系统环境移动到另一个操作系统环境?
有时,隐藏的回车符 (/r) 或其他特殊的空格字符可能会导致这种情况,但在文件中不可见。
它可以是 UTF8 BOM 字符,也可以是错误的换行符、不可打印的字符、错误的 php 关闭标记(我不使用它们,以防止尾行问题)。即使没有这样的问题,即使你尽一切努力防止它,它也可能(并且会)在以后发生。问题可能出在FTP服务器,文本编辑器,错误的PHP配置,编码,错误的CGI配置上。为了防止所有这些,我使用空的输出缓冲区,只需在第一个php文件中开始buffreing
索引.php:
if(version_compare(PHP_VERSION, '7.0.0') >= 0 || ob_get_level() < 1)
ob_start();
HtmlResponce.php:
ob_end_clean();
echo $this->getRenderedContent();
文件响应.php:
ob_end_clean();
readfile($this->content);
在 PHP5 和 PHP7 中,输出缓冲几乎没有区别,输出缓冲也可以在 PHP 中配置.ini并且在 CGI 和 Apache Mod 配置中存在差异。您不应中继"默认"配置。要处理警告消息,请使用 set_error_handler() 您也可以使用 ob_end_clean() 剥离它们
如果你开始新项目,看看Symfony组件,我在我的CMS中使用了很多。这是您防止奇怪的PHP错误的不眠之夜的机会。
在取出一些未使用的遗留代码(包括require_once
调用全是遗留代码的文件)后,此问题不再发生。在我最初观察到的"间歇性"条件下,它可能会复发,但我重现它的方法不再表现出这个问题。
我不知道为什么这似乎有所帮助 - 删除的行完全在<php? ?>
标签内,我检查了已删除的文件是否有标签、BOM 和 CRLF 之外的空格。
我也不知道为什么这个问题是间歇性的;如果它与删除的代码或文件有关,它应该每次都发生。
感谢大家的评论和回答!