运行我的脚本时,我收到几个这样的错误:
警告:不能更改头信息 - 头已经发出( 输出开始 / some/file.php:12)在/some/file.php 在线 23
错误消息中提到的行包含header()
和setcookie()
调用。
这可能是什么原因?以及如何解决它?
必须在进行任何输出之前调用发送 / 修改 HTTP 标头的函数。 摘要⇊否则呼叫失败:
警告:无法修改标头信息 - 已发送的标头(输出从脚本开始:行 )
修改 HTTP 标头的一些功能是:
输出可以是:
意外:
<?php
之前或之后的空格?>
故意的:
print
, echo
和其他产生输出的功能<html>
部分之前的<?php
代码。 要理解为什么必须在输出之前发送标头,必须查看典型的HTTP响应。 PHP 脚本主要生成 HTML 内容,但也将一组 HTTP / CGI 标头传递给 Web 服务器:
HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>
页面 / 输出始终跟在标题之后。 PHP 必须首先将标头传递给 Web 服务器。它只能这样做一次。双线后,它永远不会修改它们。
当 PHP 收到第一个输出( print
, echo
, <html>
)时,它将刷新所有收集的标题。之后它可以发送它想要的所有输出。但是,发送更多 HTTP 标头是不可能的。
header()
警告包含查找问题原因的所有相关信息:
警告:无法修改标题信息 - 已在第 100 行的 / us/usr2345/htdocs/index.php 中发送的标题(输出从 / www / usr2345 / htdocs / auth.php:52 开始 )
这里 “第 100 行” 指的是header()
调用失败的脚本。
The "output started at" note within the parenthesis is more significant.
It denominates the source of previous output. In this example it's auth.php
and line 52
. That's where you had to look for premature output.
Typical causes:
Intentional output from print
and echo
statements will terminate
the opportunity to send HTTP headers. The application flow must
be restructured to avoid that. Use functions
and templating schemes. Ensure header()
calls occur before messages
are written out.
Functions that produce output include
print
, echo
, printf
, vprintf
trigger_error
, ob_flush
, ob_end_flush
, var_dump
, print_r
readfile
, passthru
, flush
, imagepng
, imagejpeg
among others and user-defined functions.
Unparsed HTML sections in a .php
file are direct output as well.
Script conditions that will trigger a header()
call must be noted
before any raw <html>
blocks.
<!DOCTYPE html>
<?php
// Too late for headers already.
Use a templating scheme to separate processing from output logic.
<?php
for "script.php line 1" warningsIf the warning refers to output in line 1
, then it's mostly
leading whitespace, text or HTML before the opening <?php
token.
<?php
# There's a SINGLE space/newline before <? - Which already seals it.
Similarly it can occur for appended scripts or script sections:
?>
<?php
PHP actually eats up a single linebreak after close tags. But it won't compensate multiple newlines or tabs or spaces shifted into such gaps.
Linebreaks and spaces alone can be a problem. But there are also "invisible"
character sequences which can cause this. Most famously the
UTF-8 BOM (Byte-Order-Mark)
which isn't displayed by most text editors. It's the byte sequence EF BB BF
, which
is optional and redundant for UTF-8 encoded documents. PHP however has to treat
it as raw output. It may show up as the characters 
in the output (if the client
interprets the document as Latin-1) or similar "garbage".
In particular graphical editors and Java based IDEs are oblivious to its presence. They don't visualize it (obliged by the Unicode standard). Most programmer and console editors however do:
There it's easy to recognize the problem early on. Other editors may identify
its presence in a file/settings menu (Notepad++ on Windows can identify and
remedy the problem),
Another option to inspect the BOMs presence is resorting to an hexeditor.
On *nix systems hexdump
is usually available,
if not a graphical variant which simplifies auditing these and other issues:
An easy fix is to set the text editor to save files as "UTF-8 (no BOM)" or similar such nomenclature. Often newcomers otherwise resort to creating new files and just copy&pasting the previous code back in.
There are also automated tools to examine and rewrite text files
(sed
/awk
or recode
).
For PHP specifically there's the phptags
tag tidier.
It rewrites close and open tags into long and short forms, but also easily
fixes leading and trailing whitespace, Unicode and UTF-x BOM issues:
phptags --whitespace *.php
It's sane to use on a whole include or project directory.
?>
If the error source is mentioned as behind the
closing ?>
then this is where some whitespace or raw text got written out.
The PHP end marker does not terminate script executation at this
point. Any text/space characters after it will be written out as page content
still.
It's commonly advised, in particular to newcomers, that trailing ?>
PHP
close tags should be omitted. This eschews a small portion of these cases.
(Quite commonly include()d
scripts are the culprit.)
It's typically a PHP extension or php.ini setting if no error source is concretized.
gzip
stream encoding setting
or the ob_gzhandler
.extension=
module
generating an implicit PHP startup/warning message.If another PHP statement or expression causes a warning message or notice being printeded out, that also counts as premature output.
In this case you need to eschew the error,
delay the statement execution, or suppress the message with e.g.
isset()
or @()
-
when either doesn't obstruct debugging later on.
If you have error_reporting
or display_errors
disabled per php.ini
,
then no warning will show up. But ignoring errors won't make the problem go
away. Headers still can't be sent after premature output.
So when header("Location: ...")
redirects silently fail it's very
advisable to probe for warnings. Reenable them with two simple commands
atop the invocation script:
error_reporting(E_ALL);
ini_set("display_errors", 1);
或者set_error_handler("var_dump");
如果一切都失败了。
说到重定向标题,您应该经常使用这样的成语来表示最终的代码路径:
exit(header("Location: /finished.html"));
甚至优选甚至是实用程序功能,其在header()
失败的情况下打印用户消息。
PHPs 输出缓冲是一种解决此问题的解决方法。它通常可靠地工作,但不应取代适当的应用程序结构并将输出与控制逻辑分开。它的实际目的是最大限度地减少到网络服务器的分块传输。
然而, output_buffering=
设置可以提供帮助。在现代 FPM / FastCGI 设置中,在php.ini 中配置它,或者通过.htaccess或甚至.user.ini配置它。
启用它将允许 PHP 缓冲输出,而不是立即将其传递给 Web 服务器。因此,PHP 可以聚合 HTTP 头。
同样可以调用ob_start();
在调用脚本之上。然而,由于多种原因,它不太可靠:
因此,这两种方法都可能变得不可靠 - 特别是在开发设置和 / 或生产服务器之间切换时。这就是为什么输出缓冲被广泛认为只是一个拐杖 / 严格的解决方法。
另请参阅手册中的基本用法示例 ,以及更多优缺点:
如果您之前没有收到标题警告,则输出缓冲 php.ini 设置已更改。它可能在当前 / 新服务器上未配置。
headers_sent()
检查您始终可以使用headers_sent()
来探测是否仍然可以... 发送标头。这对于有条件地打印信息或应用其他回退逻辑很有用。
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
有用的后备解决方法是:
<meta>
标记如果您的应用程序在结构上很难修复,那么允许重定向的一种简单(但有点不专业)的方法是注入 HTML <meta>
标记。可以通过以下方式实现重定向:
<meta http-equiv="Location" content="http://example.com/">
或者延迟很短:
<meta http-equiv="Refresh" content="2; url=../target.html">
当通过<head>
部分使用时,这会导致无效的 HTML。大多数浏览器仍然接受它。
作为替代方案, JavaScript 重定向可用于页面重定向:
<script> location.replace("target.html"); </script>
虽然这通常比<meta>
解决方法更符合 HTML,但它依赖于支持 JavaScript 的客户端。
但是,当真正的 HTTP header()调用失败时,这两种方法都会产生可接受的回退。理想情况下,您总是将此与用户友好的消息和可点击的链接结合起来作为最后的手段。 (例如, http_redirect() PECL 扩展的功能。)
setcookie()
和session_start()
也会受到影响 setcookie()
和session_start()
需要发送Set-Cookie:
HTTP 头。因此适用相同的条件,并且将针对过早输出情况生成类似的错误消息。
(当然,它们还受到浏览器中禁用的 cookie 的影响,甚至是代理问题。会话功能显然还取决于可用磁盘空间和其他 php.ini 设置等)
在发送 HTTP 标头(使用setcookie
或header
)之前发送任何内容时会触发此错误消息。在 HTTP 标头之前输出内容的常见原因是:
意外的空格,通常在文件的开头或结尾,如下所示:
<?php
// Note the space before "<?php"
?>
为了避免这种情况,只需忽略关闭?>
- 无论如何都不需要它。
3F 3C
。您可以从文件的开头安全地删除 BOM EF BB BF
。 echo
, printf
, readfile
, passthru
,代码<?
等等display_errors
php.ini 属性,则由 php 输出警告。而不是崩溃程序员的错误,PHP 默默地修复错误并发出警告。虽然您可以修改display_errors
或error_reporting配置,但您应该修复此问题。 $_POST['input']
而不使用empty
或isset
来测试输入是否已设置),或使用未定义的常量而不是字符串文字(如$_POST[input]
,注意缺少的引号)。 打开输出缓冲应该会使问题消失; 调用ob_start
之后的所有输出都缓冲在内存中,直到释放缓冲区为止,例如使用ob_end_flush
。
但是,虽然输出缓冲避免了这些问题,但您应该确定应用程序在 HTTP 标头之前输出 HTTP 主体的原因。这就像接听电话,讨论你的一天和天气,然后告诉来电者他的号码错了。
我之前多次遇到此错误。我确信所有 PHP 程序员至少一次出现此错误。要解决此错误,您可以根据您的问题级别解决使用解决方案:
可能解决方案 1:
您可能在之前或之后(在文件末尾?> 之后)留下了空格
THERE SHOULD BE NO BLANK SPACES HERE
<?php
echo "your code here";
?>
DO CHECK FOR BLANK SPACES HERE AS WELL; THIS LINE (blank line) SHOULD NOT EXIST.
大多数情况下,这应该可以解决您的问题。请检查与您require
文件关联的所有文件。
注意: 有时像 gedit(默认的 linux 编辑器)这样的 EDITOR(IDE)在保存保存文件上添加一个空白行。这不应该发生。如果你使用的是 linux。您可以使用 VI 编辑器删除页面末尾?> 后的空格 / 行。
如果这不是你的情况,那么你可以使用ob_start进行输出缓冲,如下所示:
可能的方案 2:
<?php
ob_start();
// code
ob_end_flush();
?>
这将打开输出缓冲,并在页面缓冲后创建标题。