引言:“你已经向屏幕输出了内容,我无法操作了”
\n如果你曾经在自己的网站上看到过白屏,上面显示着令人恐惧的消息 Warning: Cannot modify header information - headers already sent,那么你并不孤单。这也许是初学者(以及不仅仅是初学者)PHP 开发者中最常见的错误之一。在 Stack Overflow 上,这个问题获得了数十万次浏览,而全球范围内错误代码的副本数量更是以 TB 计。
但好消息是,“Headers already sent” 错误并非诅咒,而只是 PHP 给出的一个严格提醒:“嘿,你已经开始发送 HTML 代码了,现在却想修改 HTTP 标头。这是不允许的!”
\n在本文中,我们将详细分析 为什么 PHP 中会出现 headers already sent 错误,如何找到它,以及最重要的是,如何一劳永逸地修复它。开始吧!
\n\n1. 什么是 HTTP 标头,为什么它们“已经发送”?
\n在深入代码之前,让我们用通俗易懂的方式了解一下“幕后”发生了什么。当 PHP 脚本执行时,它首先向浏览器发送 HTTP 标头 (header)。这些标头包含元信息:内容类型 (Content-Type)、Cookie (Set-Cookie)、重定向 (Location)、响应状态码 (200, 404, 301) 等等。
只有在 所有 标头发送之后,才开始发送文档的主体——即你在页面上看到的 HTML。PHP 只允许在发送第一个字节的内容之前修改标头。
\n一旦你向屏幕输出了任何内容(通过 echo、print、var_dump,甚至只是在 <?php 之前有一个空格),PHP 就会认为标头已经发送。在此之后任何调用 header()、setcookie() 或 session_start() 的尝试都会导致致命错误。
1.1. 错误的经典示例
\n<?php\necho "你好,世界!";\n// 哎呀!我们已经输出了内容。\nheader("Location: https://example.com");\n// Warning: Cannot modify header information - headers already sent\n?>\n在这个例子中,echo 将文本发送到了文档主体。之后,PHP 无法覆盖标头来进行重定向。这完全合乎逻辑。
2. 导致 "Headers already sent" 的五大原因
\n该错误不仅可能由显式的 echo 引起。以下是即使是有经验的开发者也会遇到的最常见场景:
- \n
<?php之前的空格或空行 — 最常见的“bug”。如果文件中在开始标签之前至少有一个空格,它就会被发送到输出中。 \n - 不可见的 BOM(字节顺序标记)字符 — 文件以 UTF-8 with BOM 编码保存。前 3 个字节 (EF BB BF) 被视为输出。 \n
- 来自包含文件的输出 — 在
config.php文件中,?>之后有多余的空格。 \n - 错误和警告 — 如果 PHP 输出了一个警告(例如,关于使用未定义的变量),这也会被视为发送内容。 \n
- 在 header() 之前的
print、printf、var_dump函数 — 任何输出函数都会破坏标头。 \n
3. 如何找到问题根源:3 种方法
\n在修复之前,需要找到“多余”输出来自哪里。使用以下方法之一。
\n\n3.1. 开启所有错误显示
\n在脚本开头(任何输出之前)添加:
\n<?php\nerror_reporting(E_ALL);\nini_set('display_errors', 1);\n?>\nPHP 通常会显示发生输出的确切行号。查找类似 Output started at /path/to/file.php:12 的消息。
3.2. 使用 error_get_last() 函数
\n可以捕获最后一个错误