PHP 5.6: headers_sent 间歇 returns 真,空文件名,第 0 行
PHP 5.6: headers_sent intermittently returns true, empty file name, and line 0
我的 PHP 脚本(PHP 5.6,Apache 2.2)间歇性地遇到这个问题:
Warning: Cannot modify header information - headers already sent in /path/to/index.php on line 55
此警告没有我在其他相关问题中看到的 "sent by" 部分,因此我在有问题的 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 字节,所以这两个 headers 中的 63 个字符不应该被缓冲并等待更多,而不是过早发送?)
这个问题是在我第一次启动包含网络服务器的 Docker 容器时出现的。之后,它只会(但不是 总是 )在我一段时间内(可能一两个小时)第一次访问我的网站时发生,当我调用 header()
和setcookie()
登录用户或重定向到登录页面。
我已经反复阅读 this answer 到一般 "Headers already sent" 错误,而且,我已尽我所能排除了这些可能的原因:
- HTML 在我调用
setcookie()
或 header()
之前阻止或调用 print
、echo
等
- 我的 PHP 标签外的空格
- 物料清单
auto_prepend_file
php.ini 设置
gzip
流编码 - 安装了 zlib,但 zlib.output_compression
已关闭
- 重复
extension=
php.ini 设置
那个答案提到
It's typically a PHP extension or php.ini setting if no error source is concretized.
所以,我现在正在查看我的扩展...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
我没有使用所有这些,所以我打算仔细检查并删除未使用的,希望其中一个是导致问题的原因。
Worst-case 场景,我会尝试将我的 output_buffering
值或使用 ob_start()
和 ob_end_flush()
到我的文件的开头和结尾。我不知道为什么当我当前的 output_buffering
值 4096 没有解决这个问题时,我知道这个解决方法有它自己的问题。
我在这里遗漏了什么——我需要检查其他可能的原因吗?我应该尝试不同的 PHP 版本,还是 运行 我的代码子集在没有扩展的干净 PHP 安装上?
编辑:添加了 ob_get_contents()
调用和输出,以及关于能够通过启动新的 Docker 容器来持续重现它的信息。删除了关于我的 error_reporting
值的信息;改变这个只会发现一个 always_populate_raw_post_data
弃用通知,修复它对这里描述的问题没有影响。
我以前见过由于行结束格式引起的问题。您要将文件从一个操作系统环境移动到另一个操作系统环境吗?
有时隐藏的回车符 return (/r) 或其他特殊的白色-space 字符会导致此问题但在文件中不可见。
它可以是 UTF8 BOM 字符,或者错误的换行符、不可打印的字符、错误的 php 关闭标记(我不使用它们,以防止结束行问题)。即使没有这样的问题,即使您尽一切努力防止它发生,它也可能(并且将会)发生。问题可能与 FTP 服务器、文本编辑器、错误的 PHP 配置、编码、错误的 cgi 配置有关。为了防止所有这些我使用空输出缓冲区,只需在第一个 php 文件
中开始缓冲
index.php:
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 配置中有差异.您不应该依赖 "default" 配置。要处理警告消息,请使用 set_error_handler() 您也将使用 ob_end_clean()
删除它们
如果您开始新项目,请查看 symfony components,我在我的 CMS 中使用了很多。这是您避免因奇怪的 PHP 错误而失眠的机会。
删除一些未使用的遗留代码后——包括 require_once
对一个全部是遗留代码的文件的调用——此问题不再发生。它可能会在我最初观察到的 "intermittent" 条件下重复出现,但我的重现它的方法不再出现此问题。
我不知道为什么这似乎有帮助 - 删除的行完全在 <php? ?>
标签内,我检查了删除的文件是否有标签、BOM 和 CRLF 之外的空白。
我也不知道为什么这个问题时断时续;如果它与删除的代码或文件有关,它应该每次都发生。
感谢大家的评论和回答!
我的 PHP 脚本(PHP 5.6,Apache 2.2)间歇性地遇到这个问题:
Warning: Cannot modify header information - headers already sent in /path/to/index.php on line 55
此警告没有我在其他相关问题中看到的 "sent by" 部分,因此我在有问题的 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 字节,所以这两个 headers 中的 63 个字符不应该被缓冲并等待更多,而不是过早发送?)
这个问题是在我第一次启动包含网络服务器的 Docker 容器时出现的。之后,它只会(但不是 总是 )在我一段时间内(可能一两个小时)第一次访问我的网站时发生,当我调用 header()
和setcookie()
登录用户或重定向到登录页面。
我已经反复阅读 this answer 到一般 "Headers already sent" 错误,而且,我已尽我所能排除了这些可能的原因:
- HTML 在我调用
setcookie()
或header()
之前阻止或调用 - 我的 PHP 标签外的空格
- 物料清单
auto_prepend_file
php.ini 设置gzip
流编码 - 安装了 zlib,但zlib.output_compression
已关闭- 重复
extension=
php.ini 设置
print
、echo
等
那个答案提到
It's typically a PHP extension or php.ini setting if no error source is concretized.
所以,我现在正在查看我的扩展...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
我没有使用所有这些,所以我打算仔细检查并删除未使用的,希望其中一个是导致问题的原因。
Worst-case 场景,我会尝试将我的 output_buffering
值或使用 ob_start()
和 ob_end_flush()
到我的文件的开头和结尾。我不知道为什么当我当前的 output_buffering
值 4096 没有解决这个问题时,我知道这个解决方法有它自己的问题。
我在这里遗漏了什么——我需要检查其他可能的原因吗?我应该尝试不同的 PHP 版本,还是 运行 我的代码子集在没有扩展的干净 PHP 安装上?
编辑:添加了 ob_get_contents()
调用和输出,以及关于能够通过启动新的 Docker 容器来持续重现它的信息。删除了关于我的 error_reporting
值的信息;改变这个只会发现一个 always_populate_raw_post_data
弃用通知,修复它对这里描述的问题没有影响。
我以前见过由于行结束格式引起的问题。您要将文件从一个操作系统环境移动到另一个操作系统环境吗?
有时隐藏的回车符 return (/r) 或其他特殊的白色-space 字符会导致此问题但在文件中不可见。
它可以是 UTF8 BOM 字符,或者错误的换行符、不可打印的字符、错误的 php 关闭标记(我不使用它们,以防止结束行问题)。即使没有这样的问题,即使您尽一切努力防止它发生,它也可能(并且将会)发生。问题可能与 FTP 服务器、文本编辑器、错误的 PHP 配置、编码、错误的 cgi 配置有关。为了防止所有这些我使用空输出缓冲区,只需在第一个 php 文件
中开始缓冲index.php:
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 配置中有差异.您不应该依赖 "default" 配置。要处理警告消息,请使用 set_error_handler() 您也将使用 ob_end_clean()
删除它们如果您开始新项目,请查看 symfony components,我在我的 CMS 中使用了很多。这是您避免因奇怪的 PHP 错误而失眠的机会。
删除一些未使用的遗留代码后——包括 require_once
对一个全部是遗留代码的文件的调用——此问题不再发生。它可能会在我最初观察到的 "intermittent" 条件下重复出现,但我的重现它的方法不再出现此问题。
我不知道为什么这似乎有帮助 - 删除的行完全在 <php? ?>
标签内,我检查了删除的文件是否有标签、BOM 和 CRLF 之外的空白。
我也不知道为什么这个问题时断时续;如果它与删除的代码或文件有关,它应该每次都发生。
感谢大家的评论和回答!