运行我的脚本时,我收到几个这样的错误:
警告:无法修改 Headers 信息 - 第23行/some/file.php中已经发送的 Headers (在/some/file.php:12处开始输出)
错误消息中提到的行包含header()和setcookie()次调用 .
这可能是什么原因?以及如何解决它?
运行我的脚本时,我收到几个这样的错误:
警告:无法修改 Headers 信息 - 第23行/some/file.php中已经发送的 Headers (在/some/file.php:12处开始输出)
错误消息中提到的行包含header()和setcookie()次调用 .
这可能是什么原因?以及如何解决它?
11 回答
发送 Headers 前没有输出!
必须调用发送/修改HTTP标头的函数 before any output is made . 摘要⇊否则呼叫失败:
修改HTTP标头的一些功能是:
header / header_remove
session_start / session_regenerate_id
setcookie / setrawcookie
输出可以是:
259
<?php
之前或?>
之后的空白特别是UTF-8 Byte Order Mark
以前的错误消息或通知
故意:
print
,echo
等产生输出的功能原始
<html>
部分之前的<?php
代码 .为什么会这样?
要理解为什么必须在输出之前发送标头,必须查看典型的HTTP响应 . PHP脚本主要生成HTML内容,但也将一组HTTP / CGI标头传递给Web服务器:
页面/输出始终跟在 Headers 之后 . PHP必须首先将标头传递给Web服务器 . 它只能这样做一次 . 双线后,它永远不会修改它们 .
当PHP收到第一个输出(
print
,echo
,<html>
)时,它将刷新所有收集的 Headers . 之后它可以发送它想要的所有输出 . 但是,发送更多HTTP标头是不可能的 .如何找出过早输出的位置?
header()
警告包含查找问题原因的所有相关信息:这里"line 100"指的是
header()
调用失败的脚本 .括号内的“输出开始于”注释更为重要 . 它表示先前输出的来源 . 在这个例子中,它是
auth.php
和 line 52 . 那是你必须寻找过早产出的地方 .典型原因:
打印,回声
来自
print
和echo
语句的故意输出将终止发送HTTP标头的机会 . 必须重新构建应用程序流以避免这种情况 . 使用functions和模板方案 . 确保在写出消息之前发生header()
次呼叫 .产生输出的函数包括
print
,echo
,printf
,vprintf
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
readfile
,passthru
,flush
,imagepng
,imagejpeg
其中包括用户定义的函数 .
原始HTML区域
.php
文件中的未分析的HTML部分也是直接输出 . 必须在任何原始<html>
块之前注意将触发header()
调用的脚本条件 .使用模板方案将处理与输出逻辑分开 .
在脚本顶部放置表单处理代码 .
使用临时字符串变量来推迟消息 .
实际输出逻辑和混合HTML输出应该遵循最后一个 .
<?php之前的空白“script.php第1行”警告
如果警告引用行 1 中的输出,则它在打开
<?php
标记之前主要是 whitespace ,文本或HTML .同样,附加脚本或脚本部分也可能出现这种情况:
PHP实际上在关闭标签后会吃掉一个换行符 . 但它不会补偿多个换行符或标签或空格转移到这些空白 .
UTF-8 BOM
仅有线路和空格可能是个问题 . 但是也有"invisible"字符序列可以导致这种情况 . 最着名的是UTF-8 BOM (Byte-Order-Mark),它不是字节序列
EF BB BF
,对于UTF-8编码文档来说是可选的和冗余的 . 然而,PHP必须将其视为原始输出 . 它可能会在输出中显示为字符
(如果客户端将文档解释为Latin-1)或类似的"garbage" .特别是图形编辑器和基于Java的IDE没有注意到它的存在 . 他们没有想象它(由...强制)Unicode标准) . 但是,大多数程序员和控制台编辑器都会:
在那里很容易早期发现问题 . 其他编辑可以在文件/设置菜单中识别它的存在(Windows上的记事本可以识别和remedy the problem),检查BOM存在的另一个选项是求助于 hexeditor . 在* nix系统上hexdump通常是可用的,如果不是图形变体,它简化了审计这些和其他问题:
一个简单的解决方法是将文本编辑器设置为“UTF-8(无BOM)”或类似的命名法 . 通常,新手通常会创建新文件,而只是复制并粘贴以前的代码 .
更正实用程序
还有自动化工具来检查和重写文本文件(sed/awk或
recode
) . 对于PHP,特别是phptags tag tidier . 它将密切和打开的标签重写为长形和短形,还可以轻松修复前导和尾随空格,Unicode和UTF-x BOM问题:在整个包含或项目目录中使用它是明智的 .
空格后?>
如果错误源被提到closing ?>后面那么这就是写出一些空格或原始文本的地方 . PHP结束标记此时不会终止脚本执行 . 之后的任何文本/空格字符仍将作为页面内容写出 .
通常建议,特别是对于新手,应该省略尾随
?>
PHP关闭标签 . 这避免了这些案件中的一小部分 . (通常include()d
脚本是罪魁祸首 . )错误来源提到“第0行未知”
如果没有错误源具体化,它通常是PHP扩展或php.ini设置 .
偶尔
gzip
流编码设置or the ob_gzhandler .但它也可能是任何双重加载的
extension=
模块生成隐式PHP启动/警告消息 .前面的错误消息
如果另一个PHP语句或表达式导致警告消息或通知被打印出来,那么这也会被视为过早输出 .
在这种情况下,您需要避免错误,延迟语句执行或抑制消息,例如isset()或@() - 以后哪一个都不妨碍调试 .
没有错误消息
如果
php.ini
已禁用error_reporting
或display_errors
,则不会显示任何警告 . 但忽略错误会在过早输出后发送 .因此,当
header("Location: ...")
重定向无提示失败时,建议探测警告 . 使用调用脚本顶部的两个简单命令重新启用它们:或
set_error_handler("var_dump");
如果一切都失败了 .说到重定向 Headers ,您应该经常使用这样的成语来表示最终的代码路径:
优选地甚至是实用功能,其在
header()
失败的情况下打印用户消息 .输出缓冲作为变通方法
PHPs output buffering是一种解决此问题的解决方法 . 它通常可靠地工作,但不应取代适当的应用程序结构并将输出与控制逻辑分开 . 它的实际目的是最大限度地减少到网络服务器的分块传输 .
但是output_buffering=设置可以提供帮助 . 在现代FPM / FastCGI设置中,在php.ini或通过.htaccess或甚至.user.ini进行配置 .
启用它将允许PHP缓冲输出,而不是立即将其传递给Web服务器 . 因此,PHP可以聚合HTTP头 .
同样可以调用ob_start();调用脚本 . 然而,由于多种原因,它不太可靠:
即使
<?php ob_start(); ?>
启动第一个脚本,空格或BOM也可能在之前被洗牌,rendering it ineffective .它可以隐藏HTML输出的空白 . 但是,一旦应用程序逻辑尝试发送二进制内容(例如生成的图像),缓冲的无关输出就成了问题 . (需要
ob_clean()
作为更好的解决方法 . )缓冲区的大小有限,并且在保留默认值时很容易溢出 . 而且,当它发生时,这也不是罕见的事情 .
因此,这两种方法都可能变得不可靠 - 特别是在开发设置和/或 生产环境 服务器之间切换时 . 这就是为什么输出缓冲被广泛认为只是一个拐杖/严格的解决方法 .
另请参阅手册中的basic usage example,以获取更多优缺点:
What is output buffering?
Why use output buffering in PHP?
Is using output buffering considered a bad practice?
Use case for output buffering as the correct solution to "headers already sent"
但是在另一台服务器上工作!?
如果之前未收到 Headers 警告,则output buffering php.ini setting已更改 . 它可能在当前/新服务器上未配置 .
使用headers_sent()进行检查
您始终可以使用headers_sent()来探测是否仍然可以...发送标头 . 这对于有条件地打印信息或应用其他回退逻辑很有用 .
有用的后备解决方法是:
HTML <meta>标记
如果您的应用程序在结构上难以修复,那么允许重定向的一种简单(但有点不专业)的方法是注入HTML
<meta>
标记 . 可以通过以下方式实现重定向:或者延迟很短:
当通过
<head>
部分使用时,这会导致无效的HTML . 大多数浏览器仍然接受它 .JavaScript重定向
作为替代方案,JavaScript redirect可用于页面重定向:
虽然这通常比
<meta>
解决方案更符合HTML,但它依赖于支持JavaScript的客户端 .但是,当真正的HTTP header()调用失败时,这两种方法都会产生可接受的回退 . 理想情况下,您总是将此与用户友好的消息和可点击的链接结合起来作为最后的手段 . (例如,http_redirect() PECL扩展的功能 . )
为什么setcookie()和session_start()也会受到影响
setcookie()
和session_start()
都需要发送Set-Cookie:
HTTP标头 . 因此适用相同的条件,并且将针对过早输出情况生成类似的错误消息 .(当然,它们还受到浏览器中禁用的cookie的影响,甚至是代理问题 . 会话功能显然还取决于可用磁盘空间和其他php.ini设置等)
更多链接
Google提供lengthy list of similar discussions .
当然many specific cases也包含在Stack Overflow上 .
Wordpress常见问题以通用方式解释How do I solve the Headers already sent warning problem? .
Adobe社区:PHP development: why redirects don't work (headers already sent)
Nucleus常见问题:What does "page headers already sent" mean?
更彻底的解释之一是HTTP Headers and the PHP header() Function - A tutorial by NicholasSolutions(互联网档案链接) . 它详细介绍了HTTP,并提供了一些重写脚本的指南 .
在发送HTTP标头(使用setcookie或header)之前发送任何内容时会触发此错误消息 . 在HTTP标头之前输出内容的常见原因是:
为了避免这种情况,只需忽略
?>
- 无论如何都不需要 .Byte order marks在php文件的开头 . 用十六进制编辑器检查你的php文件,看看是否是这种情况 . 它们应该以字节
3F 3C
开头 . 您可以安全地从文件的开头删除BOMEF BB BF
.显式输出,例如调用
echo
,printf
,readfile
,passthru
,<?
之前的代码等 .如果设置了display_errors php.ini属性,则由php输出警告 . 而不是崩溃程序员的错误,PHP默默地修复错误并发出警告 . 虽然您可以修改display_errors或error_reporting配置,但您应该修复此问题 .
常见的原因是访问数组的未定义元素(例如
$_POST['input']
,不使用empty或isset来测试输入是否已设置),或使用未定义的常量而不是字符串文字(如$_POST[input]
,请注意缺少的引号) .打开output buffering会使问题消失;调用ob_start之后的所有输出都缓冲在内存中,直到释放缓冲区,例如与ob_end_flush .
但是,虽然输出缓冲避免了这些问题,但您应该确定应用程序在HTTP标头之前输出HTTP主体的原因 . 这就像接听电话,讨论你的一天和天气,然后告诉来电者他的号码错了 .
我之前多次遇到此错误 . 我确信所有PHP程序员至少一次出现此错误 . 要解决此错误,您可以根据您的问题级别解决使用解决方案:
Possible Solution 1:
您可能在之前或之后(在文件末尾?>之后)留下了空格,即
大多数情况下,这应该可以解决您的问题 . 请检查与文件相关的所有文件
require
.Note: 有时像gedit(默认的linux编辑器)这样的EDITOR(IDE)在保存保存文件上添加一个空白行 . 这不应该发生 . 如果你使用的是linux . 您可以使用VI编辑器删除?>之后的空格/行页面末尾 .
如果这不是你的情况,那么你可以使用ob_start进行输出缓冲,如下所示:
Possible Solution 2:
这将打开输出缓冲,并在页面缓冲后创建 Headers .
而不是下面的行
写
要么
它肯定会解决你的问题 . 我遇到了同样的问题,但我通过以上述方式编写 Headers 位置解决了 .
你做
在设置cookie之前,这是不允许的 . 您不能在 Headers 之前发送任何输出,甚至不能发送空白行 .
正是因为这条线:
在发送 Headers 之前,您不应该 print/echo .
常见问题:
(复制自:source)
====================
1) header(.......); 命令之前不应有任何输出(即 echo.. 或HTML代码) .
2) 在
<?php
之前和?>
标记之后删除任何 white-space (或 newline ) .3) GOLDEN RULE! - 检查那个php文件(以及,如果你
include
其他文件)是否有 UTF8 without BOM 编码(而不仅仅是 UTF-8 ) . 这在许多情况下都是问题(因为 UTF8 编码文件在php文件的开头有一些特殊字符,你的文本编辑器没有显示)!!!!!!!!!!!4)
header(...);
之后你必须使用exit;
5) 始终使用301或302参考:
6) Turn on error reporting, and find the error. 您的错误可能是由无效的功能引起的 . 当您打开错误报告时,您应该始终首先修复最顶层的错误 . 例如,它可能是"Warning: date_default_timezone_get(): It is not safe to rely on the system's timezone settings." - 然后再向下你可能会看到"headers not sent"错误 . 修复最顶层(第一个)错误后,重新加载页面 . 如果仍有错误,请再次修复最顶层的错误 .
7) 如果以上都没有帮助,使用JAVSCRIPT重定向(但是,非强烈推荐的方法),可能是自定义案例中的最后一次机会......:
一个简单的提示:脚本中的一个简单空格(或不可见的特殊字符),就在第一个
<?php
标记之前,可能会导致这种情况!特别是当你在一个团队中工作,有人正在使用"weak" IDE或者在文件中乱用奇怪的文本编辑器时 .我见过这些东西;)
另一个不好的做法可以调用这个尚未说明的问题 .
请参阅以下代码段:
事情还可以,对吧?
如果“a_important_file.php”是这样的:
这不行吗?为什么?因为已经生成了新行 .
现在,虽然这不是一种常见的情况,如果您使用的MVC框架在将内容切换到控制器之前加载了大量文件,那该怎么办呢?这不是一种罕见的情况 . 为此做好准备 .
来自PSR-2 2.2 :
All PHP files MUST use the Unix LF (linefeed) line ending.
All PHP files MUST end with a single blank line.
The closing ?> tag MUST be omitted from files containing only php
相信我,遵循这些标准可以为你节省大量的时间:)
有时当开发进程有WIN工作站和LINUX系统(托管)时,在代码中你没有看到相关行之前的任何输出,它可能是文件的格式化和缺乏Unix LF(换行)行结束 .
我们通常做的是为了快速解决这个问题,重命名文件并在LINUX系统上创建一个新文件而不是重命名文件,然后将内容复制到该文件中 . 很多时候这解决了这个问题,因为在WIN中创建的一些文件一旦移动到托管就会导致此问题 .
此修复程序是我们通过FTP管理的网站的简单修复,有时可以节省我们的新团队成员一段时间 .
通常,当我们在回显或打印后发送 Headers 时会出现此错误 . 如果在特定页面上出现此错误,请确保在调用
start_session()
之前页面没有回显任何内容 .不可预知的错误示例:
还有一个例子:
结论:在调用
session_start()
或header()
函数之前不要输出任何字符,甚至不是空格或换行符