问题:如何修复PHP中的"标头已发送"错误

运行脚本时,出现如下错误:

警告:无法修改标头信息-已由 /some/file.php 中的从/some/file.php:12 开始的输出发送的标头strong>第23行

错误消息中提到的行包含 header() setcookie() 调用。

这可能是什么原因?以及如何解决?

标签:php,header

回答1:

发送头之前无输出!

在发送任何输出之前,必须调用 发送/修改HTTP标头的功能 摘要⇊ 否则,呼叫失败:

警告:无法修改标头信息-标头已发送(输出从 script:line 开始)

一些修改HTTP标头的函数是:

输出可以是:

  • 故意:

    • printecho和其他产生输出的功能
    • 原始部分在 代码之前。

为什么会发生?

要了解为什么在输出之前必须发送标头,有必要查看典型的 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接收到第一个输出(printecho)时,它将 flush 全部收集的标头。之后,它可以发送所需的所有输出。但是那时不可能发送更多的HTTP标头。

您如何找出发生过早输出的位置?

header()警告包含查找问题原因的所有相关信息:

警告:无法修改标头信息- 已经发送的标头(输出始于 /www/usr2345/htdocs/auth.php:52)在第100行的/www/usr2345/htdocs/index.php中

这里的"第100行"是指header() 调用失败的脚本。

括号中的" 输出始于"注释更为重要。它表示先前输出的来源。在此示例中,它是auth.php line 52 。那是您必须寻找过早输出的地方。

典型原因:

  1. 打印,回显

    printecho语句的有意输出将终止发送HTTP标头的机会。必须对应用程序流程进行重组以避免这种情况。使用功能和模板方案。确保在写出消息之前 header()调用发生。

    产生输出的函数包括

    • printechoprintfvprintf
    • trigger_errorob_flushob_end_flushvar_dumpprint_r
    • readfilepassthruflushimagepngimagejpeg


    以及用户定义的功能。

  2. 原始HTML区域

    .php文件中未解析的HTML部分也可以直接输出。在任何原始块之前,必须注意将触发header()调用的脚本条件。

    <!DOCTYPE html>
    <?php
        // Too late for headers already.
    
  3. "

没有错误消息

如果根据php.ini禁用了error_reportingdisplay_errors,则不会显示警告。但是,忽略错误并不能解决问题。过早输出后仍无法发送标头。

因此,当header("Location:...")静默重定向失败时,建议对警告进行探测。通过调用脚本顶部的两个简单命令来重新启用它们:

 <?php
# There's a SINGLE space/newline before <? - Which already seals it.

set_error_handler("var_dump");(如果所有其他方法都失败)。

说到重定向头,您应该经常将这样的惯用法用于最终代码路径:

?>

<?php

最好甚至是一个实用程序功能,在header()失败的情况下打印用户消息。

输出缓冲作为解决方法

PHP 输出缓冲是缓解此问题的一种解决方法。它通常可以可靠地运行,但不能替代适当的应用程序结构并将输出与控制逻辑分开。其实际目的是最大程度地减少到Web服务器的分块传输。

  1. output_buffering= 设置不过可以提供帮助。在 php.ini 或通过。htaccess 或什至。user.ini
    启用它将允许PHP缓冲输出,而不是立即将其传递到Web服务器。因此,PHP可以聚合HTTP标头。

  2. 同样可以调用 ob_start(); 在调用脚本之上。但是,由于多种原因,可靠性较低:

    • 即使 启动第一个脚本,空格或BOM可能在之前被改组,使其无效

    • 它可以隐藏HTML输出的空白。但是,一旦应用程序逻辑尝试发送二进制内容(例如,生成的图像)​​,则缓冲的无关输出就成为问题。 (需要ob_clean()作为进一步的解决方法。)

    • 缓冲区的大小是有限的,当保留默认值时,缓冲区很容易溢出。而且难以追踪发生这种情况。

因此,两种方法都可能变得不可靠-尤其是在开发设置和/或生产服务器之间切换时。这就是为什么输出缓冲被广泛认为只是一个拐杖,严格来说是一种解决方法。

另请参见手册中的基本用法示例,以及更多利弊:

但是它可以在另一台服务器上工作!?

如果以前没有收到标头警告,则输出缓冲php.ini设置已更改。可能在当前/新服务器上未配置。

使用headers_sent()

进行检查

您始终可以使用 headers_sent() 来探查是否仍然可能。 ..发送标题。这对于有条件地打印信息或应用其他后备逻辑很有用。

phptags  --whitespace  *.php

有用的后备解决方法是:

  • HTML 标记

    如果您的应用程序在结构上难以修复,则允许重定向的一种简单(但有些不专业)的方法是注入HTML 标签。可以通过以下方式实现重定向:

    error_reporting(E_ALL);
    ini_set("display_errors", 1);
    

    或短暂延迟:

    exit(header("Location: /finished.html"));
    

    使用此方法会导致无效的HTML经过部分。大多数浏览器仍然接受它。

  • JavaScript重定向

    作为替代方法, JavaScript重定向可用于页面重定向:

    if (headers_sent()) {
        die("Redirect failed. Please click on this link: <a href=...>");
    }
    else{
        exit(header("Location: /user.php"));
    }
    

    尽管这通常比 更符合HTMLcode>解决方法,它会依赖具有JavaScript功能的客户端。

但是,当真正的HTTP header()调用失败时,两种方法都会产生可接受的回退。理想情况下,您总是将其与用户友好的消息和可点击的链接结合起来作为最后的选择。 (例如, http_redirect() PECL扩展的作用。)

为什么setcookie()session_start()也受到影响

setcookie()session_start()都需要发送Set-Cookie: HTTP标头。因此,适用相同的条件,并且对于过早的输出情况,将生成类似的错误消息。

(当然,它们还受到浏览器中禁用的cookie甚至代理问题的影响。会话功能显然还取决于可用磁盘空间和其他php.ini设置等)

其他链接

回答2:

在发送HTTP标头(使用 setcookie header )。在HTTP标头之前输出内容的常见原因是:

  • 偶然的空格,通常在文件的开头或结尾,如下所示:

     <?php
    // Note the space before "<?php"
    ?>
    

为避免这种情况,只需省略结尾的?>-仍然不需要。

    php文件开头的
  • 字节顺序标记。使用十六进制编辑器检查您的php文件,以了解是否是这种情况。它们应以3F3C字节开头。您可以从文件开头安全地删除BOM表EFBBBF
  • 显式输出,例如调用echoprintfreadfilepassthru,在 <?等
  • 如果 display_errors php.ini属性,则php输出警告。被设置。 php不会死于程序员错误,而可以静默地修复错误并发出警告。虽然可以修改 display_errors error_reporting 配置,您应该解决此问题。
    常见原因是访问数组的未定义元素(例如$_POST['input'] 而不使用 isset 来测试是否设置了输入),或使用未定义的常量而不是字符串文字(如< code> $ _ POST [input] ,请注意缺少引号)。

打开输出缓冲可以使问题消失;调用 ob_start 之后的所有输出都将缓冲在内存中,直到释放缓冲区为止,例如与 ob_end_flush

但是,尽管输出缓冲可以避免这些问题,但是您应该真正确定为什么应用程序在HTTP标头之前输出HTTP正文。这就好比打个电话,讨论您的一天和天气,然后告诉呼叫者电话号码错误。

回答3:

我以前多次犯过此错误,并且我确定所有PHP程序员以前至少都犯过此错误。

可能的解决方案1 ​​

此错误可能是由于文件开始前 或文件结束后 的空格引起的。这些空格不应在此处。 / p>

ex)这里应该没有空白

   echo "your code here";

?>
THERE SHOULD BE NO BLANK SPACES HERE

检查与导致此错误的文件关联的所有文件。

注意: 有时,像gedit(默认的Linux编辑器)这样的EDITOR(IDE)在保存文件上添加一个空行。这不应该发生。如果您使用的是Linux。您可以使用VI编辑器删除页面末尾?>之后的空格/行。

可能的解决方案2:如果您的情况并非如此,请使用 ob_start 输出缓冲:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

这将打开输出缓冲,并在缓冲页面后创建标题。

回答4:

代替下面的行

//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

肯定会解决您的问题。我遇到了同样的问题,但是我通过以上述方式编写标头位置来解决了。

回答5:

您这样做

printf ("Hi %s,</br />", $name);

在设置cookie之前,这是不允许的。您不能在标题之前发送任何输出,甚至不能发送空行。

回答6:

是因为这一行:

printf ("Hi %s,</br />", $name);

在发送标题之前,您不应 打印/回显 任何内容。

回答7:

常见问题:

(复制自:)

===================

1) 头之前不应有任何输出(即echo.. 或HTML代码) (.......); 命令。

2)删除 之前和之后的任何空白(或换行符)>?> 标签。

3) 黄金法则!-检查该php文件(以及是否包含include个其他文件)是否具有 UTF8没有BOM 编码(而不仅仅是 UTF-8 )。在许多情况下,这是一个问题(因为 UTF8 编码文件在php文件的开头具有某些特殊字符,而您的文本编辑器不会显示该字符)!!!!!!!!!!!

4)header(...);之后,您必须使用exit;

5):始终使用301或302参考:

header("location: http://example.com",  true,  301 );  exit;

6) 打开错误报告并查找错误。您的错误可能是由无法使用的功能引起的。开启错误报告功能时,应始终首先修复最上面的错误。例如,可能为"警告:date_default_timezone_get():依靠系统的时区设置并不安全。" -再往下走,您可能会看到"未发送标题"错误。修复最上面的(第一个)错误后,请重新加载页面。如果仍然有错误,请再次修复最上面的错误。

7)如果以上方法均无济于事,请使用JAVSCRIPT重定向(但是,强烈建议不要使用此方法),这可能是自定义情况下的最后机会...:

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;

回答8:

一个简单的提示:在脚本中,在第一个 标记之前的简单空格(或不可见的特殊字符)可能会导致这种情况!尤其是当您在团队中工作并且有人在使用"弱" IDE或使用奇怪的文本编辑器弄乱文件时。

我看过这些东西;)

回答9:

另一种不好的做法可能会引起这个尚未说明的问题。

请参阅以下代码段:

<?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框架,该框架会在将内容移交给控制器之前加载大量文件?这并非罕见的情况。为此做好准备。

来自 PSR-2 2.2:


  • 所有PHP文件都必须使用UnixLF(换行)行结尾
  • 所有PHP文件都必须以单个空白行结尾。
  • 必须从仅包含php
  • 的文件中省略>结束标记?

相信我,遵循这些标准可以为您节省很多时间:)

回答10:

有时,开发进程同时具有WIN工作站和LINUX系统(托管),并且在代码中您在相关行之前看不到任何输出,这可能是文件的格式设置以及缺少 Unix的原因LF(换行符)行尾。

为了快速解决此问题,我们通常要做的是重命名该文件,然后在LINUX系统上创建一个新文件(而不是重命名的文件),然后将内容复制到该文件中。很多时候,这可以解决该问题,因为在WIN中创建的某些文件一旦移至托管位置,便会导致此问题。

此修补程序是我们通过FTP管理的网站的简单修补程序,有时可以节省一些新团队成员的时间。

回答11:

通常,当我们在回显或打印后发送标题时,会出现此错误。如果在特定页面上出现此错误,请确保在调用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()函数甚至是空格或换行符之前,请勿输出任何字符

回到顶部