解决 PHP "headers already sent" 错误 您所在的位置:网站首页 zzyzx翻译 解决 PHP "headers already sent" 错误

解决 PHP "headers already sent" 错误

2024-06-12 16:55| 来源: 网络整理| 查看: 265

解决 PHP

 

这篇文章是 stackoverflow 上的一个问题的回答,答案集中了其它答案的想法,并做了归纳,所以翻译过来,以后遇到 "headers already sent" 的错误就可以直接一一排查,或者干脆在代码动手及设计上避免这类问题了。

发送 header 前不要有任何输出

发送或者修改 HTTP 头信息的方法必须在任何输出被输出之前被调用。否则调用将会出错:

Warning: Cannot modify header information - headers already sent (output started at script:line)

这些方法可以修改(modify) HTTP 头信息:

header / header_remove

session_start / session_regenerate_id

setcookie / setrawcookie

输出(output)可以是:

无意的:

 之后的空格

UTF-8 BOM

有意的:

print ,echo 以及其他能产生输出的方法

在  后的空白 

如果错误代码在闭合标签 >? 这一行的前面,那么这就是 >? 后的空格或者原始文本输出导致的问题。PHP 的结束标记并不会在遇到闭合标签时终止执行脚本,任何 ?> 之后的文本或者空格字符都会被当作页面内容输出。  通用的被鼓励的做法,特别是针对新手,是避免在 PHP 文件后加上闭合标签 ?> 。这样就能避免一部分产生这类问题的情况。

错误源提示:"Unknown on line 0" 

如果没有给出具体的错误源,那么这就是典型的 PHP 扩展或者 php.ini 设置的问题:

偶尔是 gzip 编码设置或者是 ob_gzhandler

也有可能是 php.ini 设置里模块加载了两次导致 PHP 产生了启动/警告信息

先前的错误导致输出了错误信息 如果前面的 PHP 语句或者表达式造成了 warning 或者 notice 信息导致输出,这些输出也被认为是过早地输出。  在这种情况下你需要避免错误,推后这些语句的执行,或者抑制这些信息的输出,可以使用 isset() 进行判断,或者使用抑制符 @,前提是它们不会阻止后续的调试。

没有错误信息输出

如果你禁用了 php.ini 里的 error_reporting 或者 display_errors 设置,那么将不会产生 warning 。但是忽略错误并不会让问题消失,头信息仍然不能在过早的输出输出之前发送出去。

所以当 header("Location: ...") 跳转静默地失败时,建议你去查看 warnings 。在脚本的最前面用下面的两条命令重新开启错误报告设置:

error_reporting(E_ALL); ini_set("display_errors", 1);

或者如果其他的设置都失败了那就设置  set_error_handler("var_dump"); 。

至于跳转的 header ,在执行至最后的代码时你应该遵循下面的这种风格:

exit(header("Location: /finished.html"));

最好是提供一个方法,特别是当 header() 执行失败时打印出用户信息。

变通方法:输出缓冲

PHP 的输出缓冲的方法是缓解这种问题的一种变通方法。它运行起来可靠,但是你绝不要使用它来替代你架构良好应用程序结构,从控制逻辑中分离输出。它的真实目的是用来减轻大块数据传输至服务器时的压力。

output_buffering 设置 在 php.ini 或者 .htaccess 或者甚至在最新的 FPM/FastCGI 的 .user.ini 中设置;

同样你可以在脚本的最前面使用 ob_start() 来设置,但是它并没那么可靠:

即使  在第一个脚本里,空格或者 BOM 也有可能在此之前被输出

它可以隐藏 HTML 输出里的空格(将空格放到 buffer 中),但是只要应用程序逻辑企图发送二进制内容(比如生成的图片),缓冲里的无关的输出就会成为问题(这样 ob_clean() 方法就成为下一步的变通方法了)。

缓冲有大小限制,并且在默认配置下很容易超出,并且这种情况并不少见,一旦发生也不太容易追踪。

因此这两个方法变得不可靠了,特别是当你需要更改开发环境或者生产环境的配置的时候。这就是为什么输出缓冲被认为只是一种蹩脚的变通方法。

建议参考官方手册里的基本 使用方法 ,以及它的优缺点:

输出缓冲是什么

为什么使用 output buffering

使用输出缓冲是不好的实践吗?

正确使用 output buffering 解决 “header already sent” 的例子

但是在其他的服务器上是好的?

如果你之前没有收到过头信息的 warning ,那么 php.ini 里的 output_buffering 设置改变了。在现在的/不同的服务器上很有可能没有设置。

使用 headers_sent() 检查

你可以使用 headers_sent 来检查是否可以发送头信息。这种方法可以有效地检查以便输出一个错误信息或是应用其他的逻辑。 不错的回退变通方法有:

HTML tag  如果你的应用程序很难在结构上解决这个问题,有个简单但显得不专业的做法是在 HTML 标签中来跳转网页。可以这样实现:

 

或者加上一个延迟时间

 

JavaScript 跳转 另一个可选的方法就是使用 JavaScript 跳转 来实现网页跳转:

  location.replace("target.html");

这种方式相比较 方法起来更兼容 HTML 标准,它只依赖于可以运行 JavaScript 的客户端。

这两种方式在 HTTP header() 调用失败时都提供了可以接受的回退方式。理想化的处理方式应该是将跳转与其它方式结合,给出对用户友好的辅助信息并且提供一个可点的链接以供后续操作。

为什么它们会被影响

setcookie() 和 session_start() 都需要发送一个 set-cookie: 的 HTTP 头信息。这种情况就和前面输出 header() 的情况类似,所以同样会出现由于过早地输出错误信息导致的错误。

(当然它们受影响也有可能是因为客户端禁止了 cookie 导致的,设置可能是代理的问题。很明显,session 也取决去剩余磁盘空间大小或者 php.ini 里的其它设置)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有