如何解决“已经发送的头文件” PHP中出错 [英] How to fix "Headers already sent" error in PHP
问题描述
运行我的脚本时,我收到了几个这样的错误:
警告:无法修改标题信息 - 第23行 /some/file.php 中的输出开始于/some/file.php:12 )
错误信息中提到的行包含),
检查物料清单存在的另一个选择是诉诸 hexeditor 。
在* nix系统上或 recode
)。
对于PHP,特别是 phptags
tag tidier 一>。
它将长期和短期的关闭和打开的标签重写,但也很容易
修复前导和尾随空白,Unicode和UTF-x BOM问题:
phptags --whitespace * .php
使用整个include或project目录。
在?>>
$之后的空白b $ b
如果在
关闭?>
那么这就是写出一些空白或原始文本的地方。
PHP结束标记不会终止此
点处的脚本执行。之后的任何文字/空格字符将被写为页面内容
仍然。
通常建议,特别是新手,尾随?>
应该省略PHP
关闭标签。这避开这些情况的一小部分。
(通常 include()d
脚本是罪魁祸首。)
如果没有错误源
被具体化,它通常是PHP扩展或php.ini设置。
- 偶尔会出现
gzip
流编码设置
或ob_gzhandler
。
- 但它也可以是任何双重加载
extension =
模块
生成隐式PHP启动/警告消息。
>
前面的错误消息
表达式导致警告消息或
通知被打印出来,这也被视为过早输出。
在这种情况下,您需要避开错误
延迟语句执行,或者用例如
isset()
或 @()
-
当以后不妨碍调试时。
无错误消息
如果您有 error_reporting
或 display_errors
每个 php.ini
禁用,
则不会显示警告。但忽略错误不会使问题变为
。
所以当头(Location:...)
默认重定向失败,非常值得
建议探测警告。在调用脚本之前用两个简单的命令
重新启用它们:
error_reporting(E_ALL);
ini_set(display_errors,1);
或 set_error_handler(var_dump);
如果一切都失败了。
说到重定向头文件,您应该经常使用一个像
这样的习惯用于最终的代码路径:
exit(header(Location:/finished.html));
最好甚至是一个实用函数,在<$ c的情况下打印用户消息
$ b
输出缓冲作为解决方法
PHPs 头文件()失败。 输出缓冲
是解决此问题的解决方法。它通常可靠地工作,但不应该用
替换正确的应用程序结构并将输出与控制
逻辑分开。它的实际目的是最大限度地减少对网络服务器的分块传输。 $ b
-
output_buffering =
设置仍然可以提供帮助。
在 php.ini 中添加
或通过 .htaccess
或甚至。user.ini
现代FPM / FastCGI设置。
启用它将允许PHP缓冲输出,而不是立即将它传递到网络服务器
。因此,PHP可以聚合HTTP标头。 它也可以参与调用 -
即使
<?php ob_start(); ?>
启动第一个脚本,空白或
BOM可能会在之前进行洗牌,使其无效。 它可以隐藏空格为HTML输出。但只要应用程序
ob_start();
在调用脚本之上。然而,由于多种原因,这种方法不太可靠:
逻辑尝试发送二进制内容(例如生成的图像),
,缓冲的无关输出就成为问题。 (需要
ob_clean()
作为其他解决方法。)
而且这也不是罕见的事件,很难追踪
。
因此,这两种方法都可能变得不可靠 - 特别是在
开发设置和/或生产服务器之间切换时。这就是为什么输出缓冲是
广泛认为只是一个拐杖/严格的解决方法。
另见基本用法示例
在手册中,以及更多优点和缺点:
但它在其他服务器上工作!?
如果您之前没有收到警告,则输出缓冲
php.ini设置
已更改。它可能在当前/新服务器上未配置。
使用 headers_sent()
检查您总是可以使用 headers_sent()
来探测
是否可以...发送标题。这有助于有条件地打印
信息或应用其他后备逻辑。
if(headers_sent()){
die(重定向失败,请点击此链接:< a href = ...>);
}
else {
exit(header(Location:/user.php));
}
有用的回退解决方法是:
-
HTML
< meta>
标记
应用程序在结构上很难修复,那么允许重定向的简单(但
有点不专业)的方式是注入一个HTML
< meta>
标签。重定向可以通过以下方式实现:
< meta http-equiv =Locationcontent =http:// example。 COM />
或者短暂延迟:
< meta http-equiv =Refreshcontent =2; url = .. / target.html>
这会导致无效的HTML通过
< head>
部分。
大多数浏览器仍然接受它。 href =https://stackoverflow.com/questions/503093/how-can-i-make-a-redirect-page-in-jquery-javascript> JavaScript重定向 - Google提供冗长的类似讨论列表。
- 当然
- Wordpress常见问题解答解释我如何以通用的方式解决报头已发出警告问题?
- A dobe社区: PHP开发:为什么重定向不起作用(头文件已经发送) a>
- Nucleus常见问题解答:已发送网页标题的含义?
- 其中一个更彻底的解释是 HTTP Headers和PHP header()函数 - NicholasSolutions的教程(Internet Archive链接)。
它详细介绍了HTTP,并给出了一些重写脚本的指导。 Unintentional:
- Whitespace before
<?php
or after?>
- The UTF-8 Byte Order Mark specifically
- Previous error messages or notices
- Whitespace before
Intentional:
print
,echo
and other functions producing output- Raw
<html>
sections prior<?php
code.
可用于页面重定向:
< script> location.replace( target.html上); < /脚本>
虽然这通常比 这两种方法但是当真正的HTTP头()< meta>更符合HTML标准<
$ b
调用失败时,可以做出可接受的回退。理想情况下,您总是会将此与用户友好的消息以及
可点击的链接结合起来作为最后的手段。 (例如 http_redirect()
PECL扩展名所代表的功能。)
为什么
setcookie()
和 session_start()
也受到影响
$ b $ setcookie()
和 session_start()
需要发送一个 Set-Cookie:
HTTP标头。
因此适用相同的条件,并且对于过早的输出情况,类似的错误消息将产生
。
(当然,它们还受到在浏览器中禁用cookies,
或甚至是代理问题。会话功能显然也取决于免费的
磁盘空间和其他php.ini设置等。)
其他链接
When running my script, I am getting several errors like this:
Warning: Cannot modify header information - headers already sent by (output started at /some/file.php:12) in /some/file.php on line 23
The lines mentioned in the error messages contain header()
and setcookie()
calls.
What could be the reason for this? And how to fix it?
No output before sending headers!
Functions that send/modify HTTP headers must be invoked before any output is made. summary ⇊ Otherwise the call fails:
Warning: Cannot modify header information - headers already sent (output started at script:line)
Some functions modifying the HTTP header are:
Output can be:
Why does it happen?
To understand why headers must be sent before output it's necessary to look at a typical HTTP response. PHP scripts mainly generate HTML content, but also pass a set of HTTP/CGI headers to the webserver:
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>
The page/output always follows the headers. PHP has to pass the headers to the webserver first. It can only do that once. After the double linebreak it can nevermore amend them.
When PHP receives the first output (print
, echo
, <html>
) it will
flush all collected headers. Afterwards it can send all the output
it wants. But sending further HTTP headers is impossible then.
How can you find out where the premature output occured?
The header()
warning contains all relevant information to
locate the problem cause:
Warning: Cannot modify header information - headers already sent by (output started at /www/usr2345/htdocs/auth.php:52) in /www/usr2345/htdocs/index.php on line 100
Here "line 100" refers to the script where the header()
invocation failed.
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:
Print, echo
Intentional output from
print
andecho
statements will terminate the opportunity to send HTTP headers. The application flow must be restructured to avoid that. Use functions and templating schemes. Ensureheader()
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.Raw HTML areas
Unparsed HTML sections in a
.php
file are direct output as well. Script conditions that will trigger aheader()
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.
- Place form processing code atop scripts.
- Use temporary string variables to defer messages.
- The actual output logic and intermixed HTML output should follow last.
Whitespace before
<?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.
UTF-8 BOM
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.
Correction utilities
There are also automated tools to examine and rewrite text files (
sed
/awk
orrecode
). For PHP specifically there's thephptags
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.
Whitespace after
?>
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 commonlyinclude()d
scripts are the culprit.)Error source mentioned as "Unknown on line 0"
It's typically a PHP extension or php.ini setting if no error source is concretized.
- It's occasionally the
gzip
stream encoding setting or theob_gzhandler
. - But it could also be any doubly loaded
extension=
module generating an implicit PHP startup/warning message.
- It's occasionally the
Preceding error messages
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.
No error message
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);
Or set_error_handler("var_dump");
if all else fails.
Speaking of redirect headers, you should often use an idiom like this for final code paths:
exit(header("Location: /finished.html"));
Preferrably even a utility function, which prints a user message
in case of header()
failures.
Output buffering as workaround
PHPs output buffering is a workaround to alleviate this issue. It often works reliably, but shouldn't substitute for proper application structuring and separating output from control logic. Its actual purpose is minimizing chunked transfers to the webserver.
The
output_buffering=
setting nevertheless can help. Configure it in the php.ini or via .htaccess or even .user.ini on modern FPM/FastCGI setups.
Enabling it will allow PHP to buffer output instead of passing it to the webserver instantly. PHP thus can aggregate HTTP headers.It can likewise be engaged with a call to
ob_start();
atop the invocation script. Which however is less reliable for multiple reasons:Even if
<?php ob_start(); ?>
starts the first script, whitespace or a BOM might get shuffled before, rendering it ineffective.It can conceal whitespace for HTML output. But as soon as the application logic attempts to send binary content (a generated image for example), the buffered extraneous output becomes a problem. (Necessitating
ob_clean()
as furher workaround.)The buffer is limited in size, and can easily overrun when left to defaults. And that's not a rare occurence either, difficult to track down when it happens.
Both approaches therefore may become unreliable - in particular when switching between development setups and/or production servers. Which is why output buffering is widely considered just a crutch / strictly a workaround.
See also the basic usage example in the manual, and for more pros and cons:
- 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"
But it worked on the other server!?
If you didn't get the headers warning before, then the output buffering php.ini setting has changed. It's likely unconfigured on the current/new server.
Checking with headers_sent()
You can always use headers_sent()
to probe if
it's still possible to... send headers. Which is useful to conditionally print
an info or apply other fallback logic.
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
Useful fallback workarounds are:
HTML
<meta>
tagIf your application is structurally hard to fix, then an easy (but somewhat unprofessional) way to allow redirects is injecting a HTML
<meta>
tag. A redirect can be achieved with:<meta http-equiv="Location" content="http://example.com/">
Or with a short delay:
<meta http-equiv="Refresh" content="2; url=../target.html">
This leads to non-valid HTML when utilized past the
<head>
section. Most browsers still accept it.JavaScript redirect
As alternative a JavaScript redirect can be used for page redirects:
<script> location.replace("target.html"); </script>
While this is often more HTML compliant than the
<meta>
workaround, it incurs a reliance on JavaScript-capable clients.
Both approaches however make acceptable fallbacks when genuine HTTP header() calls fail. Ideally you'd always combine this with a user-friendly message and clickable link as last resort. (Which for instance is what the http_redirect() PECL extension does.)
Why setcookie()
and session_start()
are also affected
Both setcookie()
and session_start()
need to send a Set-Cookie:
HTTP header.
The same conditions therefore apply, and similar error messages will be generated
for premature output situations.
(Of course they're furthermore affected by disabled cookies in the browser, or even proxy issues. The session functionality obviously also depends on free disk space and other php.ini settings, etc.)
Further links
- Google provides a lengthy list of similar discussions.
- And of course many specific cases have been covered on Stack Overflow as well.
- The Wordpress FAQ explains How do I solve the Headers already sent warning problem? in a generic manner.
- Adobe Community: PHP development: why redirects don't work (headers already sent)
- Nucleus FAQ: What does "page headers already sent" mean?
- One of the more thorough explanations is HTTP Headers and the PHP header() Function - A tutorial by NicholasSolutions (Internet Archive link). It covers HTTP in detail and gives a few guidelines for rewriting scripts.
这篇关于如何解决“已经发送的头文件” PHP中出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!