提问人: 提问时间:11/7/2011 最后编辑:17 revs, 9 users 59%Moses89 更新时间:10/8/2023 访问量:1951899
如何修复PHP中的“标头已发送”错误
How to fix "Headers already sent" error in PHP
问:
运行脚本时,我收到几个错误,如下所示:
警告:无法修改标头信息 - 第 23 行 /some/file.php 中的标头已由(输出从 /some/file.php:12 开始)发送
错误消息中提到的行包含 header(
) 和 setcookie()
调用。
这可能是什么原因?以及如何解决它?
答:
php 标签之外可能存在空格。
your 和 tags 之间的空行将发送到客户端。?>
<?php
当发送第一个标头时,它会导致首先发送标头。
一旦发生这种情况,您将无法再修改标头。
删除那些不必要的标签,将它们全部放在一个大块中。<?php
第 45-47 行:
?>
<?php
这是发送几个换行符作为输出,因此标头已经调度。只需删除这 3 行(毕竟它都是一个大的 PHP 块,无需结束 PHP 解析然后重新开始),以及第 60-62 行的类似块,它就会起作用。
请注意,您收到的错误消息实际上为您提供了很多信息,以帮助您自己找到它:
警告:无法修改标头 information - 已发送的标头 (输出开始于 C:\xampp\htdocs\speedycms\deleteclient.php:47) 在 C:\xampp\htdocs\speedycms\deleteclient.php 中 上线 106
两个粗体部分告诉您在标头之前发送输出的项目在哪里(第 47 行),以及在输出之后尝试发送标头的项目在哪里(第 106 行)。
在启动会话之前,脚本有意外输出时,通常会发生这种情况。使用您当前的代码,您可以尝试使用输出缓冲来解决它。
尝试在脚本的最顶部和文档的最末尾添加对函数的调用。ob_start();
ob_end_flush();
检查文档编码。
我也有同样的问题。我在 Windows XP 上使用 Notepad++ 和 WampServer 在本地运行 Apache 进行开发,一切都很好。上传到在Unix上使用Apache的托管服务提供商后,我收到了此错误。我没有额外的PHP标签,也没有结束标签后额外行的空格。
对我来说,这是由文本文档的编码引起的。我在Notepad++中使用了“在没有BOM的情况下转换为UTF-8”选项(在编码选项卡下)并重新加载到Web服务器。问题已修复,无需代码/编辑更改。
在发送 HTTP 标头(使用 setcookie
或 header
)之前发送任何内容时,会触发此错误消息。在 HTTP 标头之前输出内容的常见原因是:
意外空格,通常位于文件的开头或结尾,如下所示:
<?php // Note the space before "<?php" ?>
为了避免这种情况,只需省略关闭 - 无论如何都不需要。?>
- php 文件开头的字节顺序标记。使用十六进制编辑器检查您的 php 文件,看看是否是这种情况。它们应该以字节 开头。您可以安全地从文件开头删除 BOM。
3F 3C
EF BB BF
- 显式输出,例如调用 、 、 、 、 代码 before 等。
echo
printf
readfile
passthru
<?
- 如果设置了
display_errors php.ini
属性,则由 php 输出的警告。php 不会因程序员错误而崩溃,而是静默修复错误并发出警告。虽然您可以修改display_errors
或error_reporting配置,但您应该解决问题。
常见原因是访问数组的未定义元素(例如不使用空
或isset
来测试是否设置了输入),或者使用未定义的常量而不是字符串文字(如 中,请注意缺少的引号)。$_POST['input']
$_POST[input]
打开输出缓冲应该可以使问题消失;调用 ob_start
后的所有输出都缓冲在内存中,直到您释放缓冲区,例如使用 ob_end_flush
。
但是,虽然输出缓冲可以避免这些问题,但您确实应该确定为什么应用程序在 HTTP 标头之前输出 HTTP 正文。这就像接一个电话,讨论你的一天和天气,然后告诉来电者他拿错了号码。
是吗
printf ("Hi %s,</br />", $name);
在设置 cookie 之前,这是不允许的。您不能在标头之前发送任何输出,甚至不能发送空行。
正是因为这样一句话:
printf ("Hi %s,</br />", $name);
在发送标题之前,不应打印/回显任何内容。
发送标头之前没有输出!
在进行任何输出之前,必须调用发送/修改 HTTP 标头的函数。 否则,调用将失败:summary ⇊
警告:无法修改标头信息 - 标头已发送(输出从 script:line 开始)
修改 HTTP 标头的一些函数包括:
输出可以是:
无心的:
- 前后空格
<?php
?>
- UTF-8 字节顺序标记
- 以前的错误消息或通知
- 前后空格
故意:
print
和其他产生输出的函数echo
- 原始部分先前的代码。
<html>
<?php
为什么会这样?
要了解为什么必须在输出之前发送标头,有必要 以查看典型的 HTTP 响应。PHP 脚本主要生成 HTML 内容,但也传递一个 Web 服务器的 HTTP/CGI 标头集:
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 收到第一个输出 (, , ) 时,它将刷新所有收集的标头。之后,它可以发送所有输出
它想要。但是,发送更多的 HTTP 标头是不可能的。print
echo
<html>
你怎么能找出过早输出发生的位置?
该警告包含所有相关信息
找到问题原因:header()
警告:无法修改标头信息 - 标头已由 (输出从 /www/usr2345/htdocs/auth.php:52) 发送 /www/usr2345/htdocs/index.php 上线 100
这里的“第 100 行”是指调用失败的脚本。header()
括号内的“输出开始于”注释更重要。
它以先前输出的来源为单位。在此示例中,它是第 52
行。这就是您必须寻找过早输出的地方。auth.php
典型原因:
打印、回声
有意输出的 和 语句将终止发送 HTTP 标头的机会。为了避免这种情况,必须对应用程序流进行重组。使用函数和模板方案。确保呼叫先于消息发生 被写出来了。
print
echo
header()
产生输出的函数包括
print
, , ,echo
printf
vprintf
trigger_error
, , , ,ob_flush
ob_end_flush
var_dump
print_r
readfile
, , , ,passthru
flush
imagepng
imagejpeg
除其他外,还有用户定义的函数。原始 HTML 区域
文件中未解析的 HTML 部分也是直接输出。 必须注意将触发调用的脚本条件 在任何原始块之前。
.php
header()
<html>
<!DOCTYPE html> <?php // Too late for headers already.
使用模板方案将处理与输出逻辑分开。
- 将表单处理代码放在脚本之上。
- 使用临时字符串变量延迟消息。
- 实际输出逻辑和混合 HTML 输出应排在最后。
“script.php 第 1 行”警告前的空格
<?php
如果警告指的是内联输出
1
,则主要是 在开始标记之前引导空格、文本或 HTML。<?php
<?php # There's a SINGLE space/newline before <? - Which already seals it.
同样,对于附加的脚本或脚本部分,也可能发生这种情况:
?> <?php
PHP 实际上在关闭标记后占用了一个换行符。但事实并非如此 补偿移动到此类间隙中的多个换行符或制表符或空格。
UTF-8 BOM
换行符和空格本身就是一个问题。但也有“看不见” 可能导致此问题的字符序列。最著名的是 UTF-8 BOM(字节顺序标记),大多数文本编辑器都不显示它。它是字节序列,对于UTF-8编码的文档来说,它是可选的和冗余的。但是,PHP 必须将其视为原始输出。它可能显示为输出中的字符(如果客户端将文档解释为 Latin-1)或类似的“垃圾”。
EF BB BF

特别是图形编辑器和基于 Java 的 IDE 忽略了它 存在。他们不会将其可视化(Unicode 标准强制要求)。 然而,大多数程序员和控制台编辑器会这样做:
在那里,很容易及早发现问题。其他编辑可能会识别 它存在于文件/设置菜单中(Windows 上的 Notepad++ 可以识别和解决问题), 检查 BOM 是否存在的另一种选择是求助于十六进制编辑器。 在 *nix 系统上,
hexdump
通常可用, 如果不是简化审计这些问题和其他问题的图形变体:一个简单的解决方法是将文本编辑器设置为将文件另存为“UTF-8(无 BOM)” 或与此类命名法相似。通常,新手会求助于创建新文件,然后将以前的代码复制并粘贴回去。
更正实用程序
还有用于检查和重写文本文件的自动化工具 (
sed
/awk
或 )。 特别是对于 PHP,有phptags
标签 tidier。 它将关闭和打开的标签重写为长格式和短格式,但也很容易 修复了前导和尾随空格、Unicode 和 UTF-x BOM 问题:recode
phptags --whitespace *.php
在整个包含目录或项目目录上使用是安全的。
后面的空格
?>
如果错误源被提及为结束
?>
后面,那么这就是写出一些空格或原始文本的地方。 此时,PHP 结束标记不会终止脚本执行。之后的任何文本/空格字符都将作为页面内容写出 还。通常建议,特别是对于新手,尾随 PHP 应省略关闭标记。这避免了这些案例的一小部分。 (通常脚本是罪魁祸首。
?>
include()d
错误源显示为“第 0 行未知”
如果没有错误源,它通常是 PHP 扩展或 php.ini 设置 是具体化的。
- 有时是流编码设置或
ob_gzhandler
。gzip
- 但它也可以是任何双负载模块
生成隐式 PHP 启动/警告消息。
extension=
- 有时是流编码设置或
前面的错误消息
如果另一个 PHP 语句或表达式导致警告消息或 注意被打印出来,这也算作过早输出。
在这种情况下,您需要避免错误, 延迟语句执行,或用例如
isset(
) 或@()
来抑制消息 - 当其中任何一个不妨碍以后的调试时。
无错误消息
如果您拥有或禁用了每 ,
则不会显示任何警告。但是忽略错误不会使问题消失
離開。过早输出后仍无法发送标头。error_reporting
display_errors
php.ini
因此,当重定向静默失败时,它非常
建议探查警告。使用两个简单的命令重新启用它们
在调用脚本之上:header("Location: ...")
error_reporting(E_ALL);
ini_set("display_errors", 1);
或者,如果所有其他方法都失败了。set_error_handler("var_dump");
说到重定向标头,您应该经常使用类似 这对于最终代码路径:
exit(header("Location: /finished.html"));
最好是实用程序函数,它打印用户消息
以防万一。header()
输出缓冲作为解决方法
PHP 输出缓冲是缓解此问题的解决方法。它通常可靠地工作,但不应该 替代适当的应用程序结构并将输出与控制分离 逻辑。它的实际目的是最大限度地减少到 Web 服务器的分块传输。
然而,
output_buffering=
设置可能会有所帮助。 在php.ini中或通过.htaccess甚至.user.ini配置它 现代 FPM/FastCGI 设置。
启用它将允许 PHP 缓冲输出,而不是立即将其传递给 Web 服务器。因此,PHP 可以聚合 HTTP 标头。同样,它也可以与调用脚本顶部的
ob_start();
调用。然而,由于多种原因,这不太可靠:
因此,这两种方法都可能变得不可靠 - 尤其是在 开发设置和/或生产服务器。这就是输出缓冲 被广泛认为只是一根拐杖/严格来说是一种解决方法。
另请参阅手册中的基本使用示例,以及更多优缺点:
但它在另一台服务器上工作!?
如果您之前没有收到标头警告,则输出缓冲 php.ini 设置已更改。它可能在当前/新服务器上未配置。
检查headers_sent()
如果出现以下情况,您始终可以使用 headers_sent()
来探测
还是有可能...发送标头。这对于有条件地打印很有用
info 或应用其他回退逻辑。
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
有用的回退解决方法包括:
HTML 标签
<meta>
如果您的应用程序在结构上难以修复,那么一个简单的(但 有点不专业)允许重定向的方法是注入 HTML 标签。可以通过以下方式实现重定向:
<meta>
<meta http-equiv="Location" content="http://example.com/">
或者有短暂的延迟:
<meta http-equiv="Refresh" content="2; url=../target.html">
这会导致在超过该部分使用时出现无效的 HTML。 大多数浏览器仍然接受它。
<head>
JavaScript 重定向
作为替代方案,JavaScript 重定向可用于页面重定向:
<script> location.replace("target.html"); </script>
虽然这通常比解决方法更符合 HTML, 它会导致对支持 JavaScript 的客户端的依赖。
<meta>
然而,当真正的 HTTP header() 调用失败。理想情况下,您始终将其与用户友好的消息和 可点击的链接是最后的手段。(例如,这就是 http_redirect() PECL 扩展的作用。
为什么和也受到影响setcookie()
session_start()
两者都需要发送 HTTP 标头。
因此,相同的条件适用,并且将生成类似的错误消息
用于过早输出的情况。setcookie()
session_start()
Set-Cookie:
(当然,它们还会受到浏览器中禁用的 cookie 的影响 甚至是代理问题。会话功能显然也依赖于免费 磁盘空间和其他 php.ini 设置等)
更多链接
- 谷歌提供了一长串类似的讨论。
- 当然,Stack Overflow 上也涵盖了许多具体案例。
- WordPress FAQ 以通用方式解释了如何解决 Headers already sent 警告问题?
- Adobe 社区:PHP 开发:为什么重定向不起作用(标头已发送)
- Nucleus FAQ: “page headers already sent” 是什么意思?
- 其中一个更彻底的解释是 HTTP 标头和 PHP header() 函数 - NicholasSolutions 的教程(Internet Archive 链接)。 它详细介绍了 HTTP,并提供了一些重写脚本的指南。
评论
?>
$file = $line = null; headers_sent($file, $line); die("$file:$line");
ignore_user_abort=On
一个简单的提示:脚本中一个简单的空格(或不可见的特殊字符),就在第一个标签之前,可能会导致这种情况!
特别是当你在一个团队中工作时,有人正在使用一个“弱”的IDE,或者用奇怪的文本编辑器弄乱了文件。<?php
我;)看到了这些事情
我以前遇到过很多次这个错误,我敢肯定所有PHP程序员以前都至少遇到过一次这个错误。
可能的解决方案 1
此错误可能是由文件开始之前或文件结束之后的空格引起的。这些空白区域不应该在这里。
例如)
<!-- THERE SHOULD BE NO BLANK SPACES HERE -->
<?php
echo "your code here";
?>
<!-- THERE SHOULD BE NO BLANK SPACES HERE -->
检查与导致此错误的文件关联的所有文件。
注意:有时 EDITOR(IDE) 如 gedit
(默认的 Linux 编辑器)会在保存文件上添加一个空行。这不应该发生。如果您使用的是 Linux。您可以使用VI编辑器删除页面末尾?>
后面的空格/行。
可能的解决方案 2:如果不是这种情况,请使用 ob_start 输出缓冲:
<?php
ob_start();
// code
ob_end_flush();
?>
这将打开输出缓冲,并在页面缓冲后创建标题。
评论
ob_start()
只是隐藏了问题;不要用它来解决这个特定的问题。
ob_start()
它不是“隐藏”问题,而是解决问题。
<?
而不是下面的行
//header("Location:".ADMIN_URL."/index.php");
写
echo "<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>";
或
?><script><?php echo "location.href = '".ADMIN_URL."/index.php?msg=$msg';";?></script><?php
它一定会解决你的问题。 我遇到了同样的问题,但我通过以上述方式编写标题位置解决了。
另一个不好的做法可能会引发这个问题,但这个问题还没有说明。
请参阅以下代码片段:
<?php
include('a_important_file.php'); //really really really bad practise
header("Location:A location");
?>
一切都还好,对吧?
如果“a_important_file.php”是这样的:
<?php
//some php code
//another line of php code
//no line above is generating any output
?>
----------This is the end of the an_important_file-------------------
这行不通吗?为什么?因为已经生成了新行。
现在,虽然这不是一个常见的场景,但如果你使用的是MVC框架,它在将东西移交给你的控制器之前加载了大量文件,该怎么办?这种情况并不少见。为此做好准备。
- 所有 PHP 文件都必须使用
Unix LF(换行符)行尾
。 - 所有 PHP 文件必须以
一个空行
结尾。 - 仅包含
php
的文件必须省略
结束 ?> 标记
相信我,遵循这些标准可以为您节省大量时间:)
评论
?>
CR LF
LF
CR LF
?>
<?php
?>
通常,当我们在回显或打印后发送标头时,会出现此错误。如果此错误出现在特定页面上,请确保该页面没有回显任何内容,然后再调用 。start_session()
不可预知的错误示例:
<?php //a white-space before <?php also send for output and arise error
session_start();
session_regenerate_id();
//your page content
再举一个例子:
<?php
includes 'functions.php';
?> <!-- This new line will also arise error -->
<?php
session_start();
session_regenerate_id();
//your page content
结论:在调用或函数之前不要输出任何字符,甚至不要输出空格或换行符session_start()
header()
常见问题:
1) header(.......);
命令之前不应有任何输出(即 echo..
或 HTML 代码)。
2)删除标签前后的任何空格(或换行符)。<?php
?>
3) 黄金法则! - 检查该 php 文件(以及其他文件)是否具有没有 BOM 编码的 UTF8(而不仅仅是 UTF-8)。这在许多情况下都是有问题的(因为 UTF8 编码的文件在 php 文件的开头有一些特殊字符,您的文本编辑器不会显示)!!!!!!!!!!include
4)必须使用后header(...);
exit;
5) 始终使用 301 或 302 参考:
header("location: http://example.com", true, 301 ); exit;
6) 打开错误报告,并查找错误。您的错误可能是由功能不起作用引起的。打开错误报告时,应始终首先修复最上面的错误。例如,它可能是“警告:date_default_timezone_get():依赖系统的时区设置是不安全的”——然后再往下看,您可能会看到“标头未发送”错误。修复最顶层(第1个)错误后,重新加载页面。如果仍有错误,请再次修复最上面的错误。
7)如果以上方法均无济于事,请使用JAVSCRIPT重定向(但是,强烈建议不要使用该方法),在自定义情况下可能是最后的机会...:
echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
评论
301
302
有时,当开发过程同时具有 WIN 工作站和 LINUX 系统(托管)并且在代码中看不到相关行之前的任何输出时,这可能是文件的格式化和缺少 Unix LF(换行)行尾。
为了快速解决这个问题,我们通常做的是重命名文件,然后在 LINUX 系统上创建一个新文件而不是重命名的文件,然后将内容复制到其中。很多时候,这解决了这个问题,因为在WIN中创建的某些文件一旦移动到主机就会导致此问题。
对于我们通过FTP管理的站点来说,此修复程序是一个简单的修复程序,有时可以为我们的新团队成员节省一些时间。
评论
ob_start
ob_end_clean()
ob_get_contents()
ob_end_clean()
UTF-8
UTF-8 (Without BOM)
~~~~~~~~~~~