如何修复PHP中的“已发送邮件头”错误

这个问题's的答案是社区的努力。编辑现有答案以改进此帖子。它目前不接受新的答案或互动。

运行脚本时,我会遇到如下错误:

警告:无法修改标题信息-标题已由第23行的/some/file.php中的/some/file.php中的(输出开始于/some/file.php:12)发送

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

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

发送标题之前没有输出

在进行任何输出之前,必须调用发送/修改HTTP头的函数。
总结⇊
否则,调用将失败:

警告:无法修改标题信息-标题已发送(输出从脚本:行开始)

修改HTTP头的一些函数包括:

  • 标题/标题_删除
  • 会话\u开始/会话\u重新生成\u id
  • setcookie/setrawcookie

输出可以是:

  • 无意的:

    • 之前的空格<?php或之后的?&gt
    • UTF-8字节顺序标记
    • 以前的错误消息或通知
  • 故意的:

    • printecho和其他产生输出的功能
    • 原始<html&gt前面的章节<?phpcode

为什么会这样

要理解为什么在输出之前必须发送头,这是必要的
查看典型的HTTP
回答PHP脚本主要生成HTML内容,但也传递
Web服务器的HTTP/CGI头集:

HTTP/1.1 200正常
受支持:PHP/5.3.7
改变:接受编码
内容类型:text/html;字符集=utf-8
<html&gt&书信电报;头&gt&书信电报;标题>PHP页面输出页面&lt/标题&gt&lt/头>
<车身&gt&书信电报;h1>内容&lt/h1&gt&书信电报;p>接下来会有更多的输出…&lt/p>
及<a href=&quot/&引用&燃气轮机&书信电报;img src=内部图标延迟&gt&lt/a>

页面/输出始终在标题之后。PHP必须通过
首先将标题发送到Web服务器。它只能这样做一次。
在双线中断之后,它再也不能修改它们了

当PHP收到第一个输出(printecho<html>)时,它将
刷新所有收集的标题。之后,它可以发送所有输出
它想要。但是发送更多的HTTP头是不可能的

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

标题()
查找问题原因:

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

“这里”;第100行“;指头()调用失败的脚本

"输出从开始;括号内的注释更为重要。
它命名以前输出的源。在本例中,它是auth.php
52。这就是你必须寻找过早产出的地方

典型原因:

  1. 打印、回显

    来自printecho语句的有意输出将终止发送HTTP头的机会。必须重新构造应用程序流以避免这种情况。使用函数
    以及模板方案。确保header()调用发生在消息之前
    都写出来了

    产生输出的函数包括

    • printechoprintfvprintf
    • trigger\u errorob\u flushob\u end\u flushvar\u dumpprint\u r
    • readfilepassthruflushimagepngimagejpeg

    以及用户定义的功能

  2. 原始HTML区域

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

    <!DOCTYPE html>
    <?php
    //对标题来说已经太晚了。
    

    使用模板方案将处理与输出逻辑分离

    • 将表单处理代码置于脚本之上
    • 使用临时字符串变量延迟消息
    • 实际的输出逻辑和混合HTML输出应该紧跟在最后。
  3. 之前的空格<?phpfor"script.php第1行;警告

    如果警告指的是输出内联1,则通常是
    开头前的前导空格、文本或HTML<?phptoken

    <?php
    #前面只有一个空格/换行符<?-它已经封住了它。
    

    类似地,附加脚本或脚本节也会出现这种情况:

    ?>
    <?php
    

    PHP实际上会在关闭标记后吃掉一个单个换行符。但不会
    补偿多个换行符、制表符或空格移动到这些间隙中

  4. UTF-8物料清单

    换行符和空格本身就是一个问题。但也有",;无形的;
    可能导致这种情况的字符序列。最著名的是
    UTF-8 BOM(字节顺序标记)
    大多数文本编辑器都不会显示它。它是字节序列EF BB BF,对于UTF-8编码的文档是可选的和冗余的。然而,PHP必须将其视为原始输出。它可能会在输出中显示为字符ï»(如果客户将文档解释为拉丁语-1)或类似的“;“垃圾”

    尤其是图形编辑器和基于Java的IDE,它们不知道它的功能
    在场他们没有将其可视化(受Unicode标准的约束)。
    但是,大多数程序员和控制台编辑器会:

    在那里,很容易在早期发现问题。其他编辑可能会识别
    它出现在文件/设置菜单中(Windows上的记事本+)可以识别
    解决问题),,
    检查BOM存在的另一个选项是求助于hexeditor
    在*nix系统上,通常可以使用hexdump
    如果不是简化审计这些问题和其他问题的图形变体:

    一个简单的解决方法是将文本编辑器设置为将文件另存为;UTF-8(无物料清单)“;
    或类似于这种命名法。通常新来者会以其他方式创建新文件,而只是复制&将以前的代码粘贴回

    校正实用程序

    也有自动工具来检查和重写文本文件
    sed/awkrecode)。
    特别是对于PHP,有phptagstagtidier。
    它将关闭和打开标记重写为长和短形式,但也很容易
    修复了前导和尾随空格、Unicode和UTF-x BOM问题:

    phptag——空白*.php
    

    在整个include或project目录中使用是安全的

  5. ?&gt

    如果提到错误源是在
    关闭?&gt
    然后这就是一些空白或原始文本被写出的地方。
    PHP结束标记不会在此时终止脚本执行。之后的任何文本/空格字符都将作为页面内容写出
    还是

    人们通常建议,尤其是对于新手,跟踪?&gtPHP
    应该省略关闭标记。这避免了这些案例中的一小部分。
    (通常情况下,include()d脚本是罪魁祸首。)

  6. 错误源称为;第0行“未知”

    如果没有错误源,它通常是一个PHP扩展或PHP.ini设置
    它被具体化了

    • 有时是gzip流编码设置
      或者ob\u gzhandler
    • 但它也可以是任何双重加载的扩展=模块
      生成隐式PHP启动/警告消息。

  7. 前面的错误消息

    如果另一个PHP语句或表达式导致警告消息或
    请注意,打印出来时,这也算作过早输出

    在这种情况下,您需要避免错误,
    延迟语句执行,或使用以下命令抑制消息:。
    isset()@()-
    当任何一个都不妨碍以后的调试时

没有错误消息

如果根据php.ini禁用了错误报告显示错误
那么就不会出现任何警告。但是忽略错误并不能解决问题
离开在过早输出后仍无法发送标题

所以当标题(“Location:…”)以静默方式重定向f时

发表评论