php - 如何修复 PHP 中的 "Headers already sent"错误

标签 php header

这个问题的答案是community effort .编辑现有答案以改进这篇文章。它目前不接受新的答案或互动。








运行我的脚本时,我收到了几个这样的错误:

Warning: Cannot modify header information - headers already sent by (output started at /some/file.php:12) in /some/file.php on line 23



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

这可能是什么原因?以及如何修复它?

最佳答案

发送 header 之前没有输出!
必须调用发送/修改 HTTP header 的函数 在进行任何输出之前 .
summary ⇊
否则调用失败:

Warning: Cannot modify header information - headers already sent (output started at script:line)


一些修改 HTTP header 的函数是:
  • header / header_remove
  • session_start / session_regenerate_id
  • setcookie / setrawcookie

  • 输出可以是:
  • 无意:
  • 前面的空格 <?php或之后 ?>
  • UTF-8 Byte Order Mark特别
  • 以前的错误消息或通知

  • 故意的:
  • print , echo和其他产生输出的函数
  • 原始 <html>之前的部分 <?php代码。


  • 为什么会发生?
    要了解为什么必须在输出之前发送 header ,这是必要的
    看一个典型的HTTP
    回复。 PHP 脚本主要生成 HTML 内容,但也传递一个
    网络服务器的一组 HTTP/CGI header :
    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 必须通过
    首先将 header 发送到网络服务器。它只能这样做一次。
    在双换行之后,它再也不能修改它们了。
    当 PHP 收到第一个输出( printecho<html> )时,它会
    刷新所有收集的标题。之后它可以发送所有输出
    它想要。但是发送更多的 HTTP header 是不可能的。
    如何找出过早输出发生的位置?header()警告包含所有相关信息
    定位问题原因:

    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


    这里的“第 100 行”指的是 header() 所在的脚本调用失败。
    括号内的“输出开始于”注释更重要。
    它指定了先前输出的来源。在这个例子中,它是 auth.php线路52 .这就是您必须寻找过早输出的地方。
    典型原因:
  • 打印, echo
    来自 print 的有意输出和 echo语句将终止发送 HTTP header 的机会。必须重构应用程序流程以避免这种情况。使用 functions
    和模板计划。确保 header()调用发生在消息之前
    写出来了。
    产生输出的函数包括
  • print , echo , printf , vprintf
  • trigger_error , ob_flush , ob_end_flush , var_dump , print_r
  • readfile , passthru , flush , imagepng , imagejpeg

  • 其中包括和用户定义的函数。
  • 原始 HTML 区域.php 中未解析的 HTML 部分文件也是直接输出。
    将触发 header() 的脚本条件来电须注意
    在任何原始 <html> 之前块。
    <!DOCTYPE html>
    <?php
        // Too late for headers already.
    
    使用模板方案将处理与输出逻辑分开。
  • 将表单处理代码置于脚本之上。
  • 使用临时字符串变量来延迟消息。
  • 实际的输出逻辑和混合的 HTML 输出应该在最后。

  • 前面的空格 <?php对于“script.php 第 1 行 ” 警告
    如果警告是指输出内联 1 ,那么它主要是
    领先 空格 、文本或 HTML 之前的开头 <?php token 。
     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.
    
    同样,附加脚本或脚本部分也可能发生这种情况:
    ?>
    
    <?php
    
    PHP 实际上在关闭标签之后吃掉一个换行符。但它不会
    补偿移动到此类间隙中的多个换行符或制表符或空格。
  • UTF-8 Material list
    单独的换行符和空格可能是一个问题。但也有“隐形”
    可能导致这种情况的字符序列。最著名的是
    UTF-8 BOM (Byte-Order-Mark)
    大多数文本编辑器不显示。它是字节序列 EF BB BF ,对于 UTF-8 编码的文档是可选的和冗余的。然而,PHP 必须将其视为原始输出。它可能显示为字符 在输出中(如果客户端将文档解释为 Latin-1)或类似的“垃圾”。
    特别是图形编辑器和基于 Java 的 IDE
    在场。他们没有将它可视化(Unicode 标准要求)。
    然而,大多数程序员和控制台编辑器都这样做:
    joes editor showing UTF-8 BOM placeholder, and MC editor a dot
    在那里很容易及早发现问题。其他编辑可能会识别
    它存在于文件/设置菜单中(Windows 上的 Notepad++ 可以识别和
    remedy the problem ),
    检查 BOM 是否存在的另一种选择是使用 十六进制编辑器 .
    在 *nix 系统上 hexdump 通常可用,
    如果不是简化审核这些和其他问题的图形变体:
    beav hexeditor showing utf-8 bom
    一个简单的解决方法是将文本编辑器设置为将文件保存为“UTF-8(无 BOM)”
    或类似于此类命名法。否则,新手通常会求助于创建新文件,然后将之前的代码复制并粘贴回去。
    校正实用程序
    还有一些自动化工具可以检查和重写文本文件
    ( sed / awk recode )。
    对于 PHP,特别是 phptags tag tidier .
    它将关闭和打开标签重写为长短形式,但也很容易
    修复了前导和尾随空格、Unicode 和 UTF-x BOM 问题:
    phptags  --whitespace  *.php
    
    在整个包含或项目目录上使用是安全的。
  • ?> 之后的空格
    如果在后面提到错误源
    closing ?>
    那么这是写出一些空白或原始文本的地方。
    此时 PHP 结束标记不会终止脚本执行。其后的任何文本/空格字符都将作为页面内容写出
    仍然。
    通常建议,特别是对于新手,尾随 ?> PHP
    应该省略关闭标签。这避免了这些案例中的一小部分。
    (通常 include()d 脚本是罪魁祸首。)
  • 错误来源被提及为“第 0 行未知”
    如果没有错误源,通常是 PHP 扩展或 php.ini 设置
    被具体化。
  • 偶尔是 gzip流编码设置
    or the ob_gzhandler .
  • 但它也可以是任何双重加载 extension=模块
    生成隐式 PHP 启动/警告消息。

  • 之前的错误消息
    如果另一个 PHP 语句或表达式导致警告消息或
    通知被打印出来,这也算作过早输出。
    在这种情况下,您需要避免错误,
    延迟语句执行,或使用例如抑制消息
    isset() @() ——
    当两者都不会妨碍以后的调试时。

  • 没有错误信息
    如果您有 error_reportingdisplay_errorsphp.ini 禁用,
    然后不会出现警告。但是忽略错误不会使问题解决
    离开。过早输出后仍然无法发送 header 。
    所以当 header("Location: ...")重定向默默地失败,这是非常
    建议探测警告。使用两个简单的命令重新启用它们
    在调用脚本之上:
    error_reporting(E_ALL);
    ini_set("display_errors", 1);
    
    set_error_handler("var_dump");如果一切都失败了。
    说到重定向头,你应该经常使用这样的习惯用法
    这对于最终代码路径:
    exit(header("Location: /finished.html"));
    
    最好是一个效用函数,它打印用户消息
    header() 的情况下失败。
    输出缓冲作为一种解决方法
    PHP output buffering
    是缓解此问题的解决方法。它通常工作可靠,但不应该
    替代适当的应用程序结构并将输出与控制分离
    逻辑。它的实际目的是最小化到网络服务器的分块传输。
  • output_buffering=
    尽管如此,设置还是有帮助的。
    php.ini 中配置它
    或通过 .htaccess
    甚至 .user.ini
    现代 FPM/FastCGI 设置。
    启用它将允许 PHP 缓冲输出而不是立即将其传递到网络服务器。 PHP 因此可以聚合 HTTP header 。
  • 它也可以拨打 ob_start();
    在调用脚本之上。然而,由于多种原因,它不太可靠:
  • 即使 <?php ob_start(); ?>开始第一个脚本,空格或
    BOM 之前可能会被洗牌,rendering it ineffective .
  • 它可以隐藏 HTML 输出的空格。但是一旦应用程序逻辑尝试发送二进制内容(例如生成的图像)​​,
    缓冲的无关输出成为一个问题。 (需要ob_clean()作为进一步的解决方法。)
  • 缓冲区大小有限,如果保留默认值,很容易溢出。
    这也不是罕见的,difficult to track down
    当它发生时。


  • 因此,两种方法都可能变得不可靠 - 特别是在两者之间切换时
    开发设置和/或生产服务器。这就是为什么输出缓冲是
    被广泛认为只是一个拐杖/严格的解决方法。
    另见 basic usage example
    在手册中,以及更多的利弊:
  • 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"

  • 但它在另一台服务器上工作!?
    如果您之前没有收到标题警告,那么 output buffering php.ini setting
    已经改变。它可能未在当前/新服务器上配置。
    headers_sent() 核对
    您可以随时使用 headers_sent() 探查是否
    仍然可以...发送 header 。这对有条件地打印很有用
    信息或应用其他回退逻辑。
    if (headers_sent()) {
        die("Redirect failed. Please click on this link: <a href=...>");
    }
    else{
        exit(header("Location: /user.php"));
    }
    
    有用的回退解决方法是:
  • HTML <meta>标签
    如果您的应用程序在结构上难以修复,那么一个简单的(但
    有点不专业)允许重定向的方法是注入(inject) HTML<meta>标签。可以通过以下方式实现重定向:
     <meta http-equiv="Location" content="http://example.com/">
    
    或者有一个短暂的延迟:
     <meta http-equiv="Refresh" content="2; url=../target.html">
    
    当使用超过 <head> 时,这会导致无效的 HTML。部分。
    大多数浏览器仍然接受它。
  • JavaScript 重定向
    作为替代 JavaScript redirect
    可用于页面重定向:
     <script> location.replace("target.html"); </script>
    
    虽然这通常比 <meta> 更符合 HTML 标准解决方法,
    它导致对支持 JavaScript 的客户端的依赖。

  • 然而,当真正的 HTTP header()
    调用失败。理想情况下,您总是将此与用户友好的消息相结合,并且
    可点击链接作为最后的手段。 (例如,这是什么 http_redirect()
    PECL 扩展确实如此。)
    为什么setcookie()session_start()也受到影响
    两者 setcookie()session_start()需要发一个Set-Cookie: HTTP header 。
    因此适用相同的条件,并会生成类似的错误消息
    对于过早的输出情况。
    (当然,它们还受到浏览器中禁用 cookie 的影响
    甚至代理问题。 session 功能显然也取决于免费
    磁盘空间和其他 php.ini 设置等)
    更多链接
  • Google 提供了一个 lengthy list of similar discussions .
  • 当然还有 many specific cases Stack Overflow 上也有介绍。
  • WordPress 常见问题解答 How do I solve the Headers already sent warning problem?以一种通用的方式。
  • Adobe 社区:PHP development: why redirects don't work (headers already sent)
  • Nucleus 常见问题解答:What does "page headers already sent" mean?
  • 更彻底的解释之一是 HTTP Headers and the PHP header() Function - A tutorial by NicholasSolutions (互联网文件链接)。
    它详细介绍了 HTTP 并提供了一些重写脚本的指南。
  • 关于php - 如何修复 PHP 中的 "Headers already sent"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8028957/

    相关文章:

    iphone - 未找到 RestKit/RestKit.h 文件错误 - 版本 0.10.0

    php - 无法修改 header 信息 - header 已发送(混淆)

    php - mysql 和 php 的夏令时

    php - jQuery 验证,使用 submitHandler 提交

    php - 这是使用内存缓存的最佳方式吗?

    php - 获取文件编码

    caching - 在 Acrobat Reader 10.0 (HTTP 1.0/HTTP 1.1) 中使用 PDF 流时如何防止缓存

    C++ 头文件链接器错误

    HTML:页眉+页脚+具有特定规范的流体内容

    php - Android中jSONArray解析异常的问题