ホームページ >バックエンド開発 >PHPチュートリアル >PHPの「ヘッダーはすでに送信されました」エラーを解決する

PHPの「ヘッダーはすでに送信されました」エラーを解決する

WBOY
WBOYオリジナル
2016-06-23 13:14:44649ブラウズ

この記事は、stackoverflow に関する質問に対する回答です。この回答は、他の回答のアイデアに焦点を当ててまとめたものです。そのため、今後「ヘッダーはすでに送信されました」エラーが発生した場合は、次の方法で直接確認できます。あるいは、コーディングや設計においてそのような問題を単に回避することもできます。

ヘッダーを送信する前に出力はありません

HTTP ヘッダー情報を送信または変更するメソッドは、出力が出力される前に呼び出す必要があります。それ以外の場合、呼び出しはエラーになります:

警告: ヘッダー情報を変更することはできません - ヘッダーはすでに送信されました (outputが script:line で開始されました)

これらのメソッドは HTTP ヘッダー情報を変更 (修正) できます:

  • header / header_remove
  • session_start / session_regenerate_id
  • setcookie / setrawcookie

出力は次のとおりです:

  • 意図的でない:
    • 9fb9a1801df6836fbf56eed45e06ec57 ) を受け取ると、収集されたすべてのヘッダー情報がクリアされます。この後、出力したい内容はすべて出力できますが、HTTP ヘッダー情報を送信することはできません。

      出力がどこで生成されるかを事前に確認するにはどうすればよいですか?

      header() ヘッダー情報には、問題に関連するすべての情報が含まれています:

      警告: ヘッダー情報は変更できません - ヘッダーは既に送信されています (出力は /www/usr2345/htdocs/auth.php:52 で開始されました) in /www / usr2345/htdocs/index.php 100 行目

      上記の警告では、100 行目は header() の呼び出しが失敗したスクリプトの行番号を指しています。

      括弧内の出力開始メッセージの方が重要です。 header() の前にある出力のソースを示します。この場合、それは auth.php の 52 行目であり、そこが時期尚早の出力を探している場所です。

      一般的な理由は次のとおりです:

      1. print、echo

        意図的な print および echo ステートメントの出力により、HTTP ヘッダー情報を出力する機会が中断されます。この動作を回避するには、関数とテンプレートを使用して、情報が書き出される前に header() 呼び出しが行われるようにアプリケーション フローを再編成する必要があります。

        出力を生成するメソッドには次が含まれます:

        • print、echo、printf、vprintf
        • trigger_error、ob_flush、ob_end_flush、var_dump、print_r
        • readfile、passthru、flush、imagepng、imagejpeg

        その他のユーザー定義の定義方法。

      2. Raw HTML

        PHP ファイル内の解析されていない HTML チャンクも出力されます。 header() の呼び出しをトリガーするスクリプト内の条件はすべて、100db36a723c770d327fc0aef2ce13b1 ブロックの前に宣言する必要があります。

      3. c2feac5eae1caaa0f784a114d11807aa 后的空白

        如果错误代码在闭合标签 >? 这一行的前面,那么这就是 >? 后的空格或者原始文本输出导致的问题。PHP 的结束标记并不会在遇到闭合标签时终止执行脚本,任何 ?> 之后的文本或者空格字符都会被当作页面内容输出。

        通用的被鼓励的做法,特别是针对新手,是避免在 PHP 文件后加上闭合标签 ?> 。这样就能避免一部分产生这类问题的情况。

      4. 错误源提示:”Unknown on line 0”

        如果没有给出具体的错误源,那么这就是典型的 PHP 扩展或者 php.ini 设置的问题:

        • 偶尔是 gzip 编码设置或者是 ob_gzhandler
        • 也有可能是 php.ini 设置里模块加载了两次导致 PHP 产生了启动 / 警告信息
      5. 先前的错误导致输出了错误信息

        如果前面的 PHP 语句或者表达式造成了 warning 或者 notice 信息导致输出,这些输出也被认为是过早地输出。

        在这种情况下你需要避免错误,推后这些语句的执行,或者抑制这些信息的输出,可以使用 isset() 进行判断,或者使用抑制符 @ ,前提是它们不会阻止后续的调试。

      没有错误信息输出

      如果你禁用了 php.ini 里的 error_reporting 或者 display_errors 设置,那么将不会产生 warning 。但是忽略错误并不会让问题消失,头信息仍然不能在过早的输出输出之前发送出去。

      所以当 header("Location: ...") 跳转静默地失败时,建议你去查看 warnings 。在脚本的最前面用下面的两条命令重新开启错误报告设置:

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

      或者如果其他的设置都失败了那就设置 set_error_handler("var_dump"); 。

      至于跳转的 header ,在执行至最后的代码时你应该遵循下面的这种风格:

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

      最好是提供一个方法,特别是当 header() 执行失败时打印出用户信息。

      变通方法:输出缓冲

      PHP 的输出缓冲的方法是缓解这种问题的一种变通方法。它运行起来可靠,但是你绝不要使用它来替代你架构良好应用程序结构,从控制逻辑中分离输出。它的真实目的是用来减轻大块数据传输至服务器时的压力。

      1. output_buffering 设置 在 php.ini 或者 .htaccess 或者甚至在最新的 FPM/FastCGI 的 .user.ini 中设置;
      2. 同样你可以在脚本的最前面使用 ob_start() 来设置,但是它并没那么可靠:
        • 即使 1021a262b685dcb3c7e39a7f9104eb5e 在第一个脚本里,空格或者 BOM 也有可能在此之前被输出
        • 它可以隐藏 HTML 输出里的空格(将空格放到 buffer 中),但是只要应用程序逻辑企图发送二进制内容(比如生成的图片),缓冲里的无关的输出就会成为问题(这样 ob_clean() 方法就成为下一步的变通方法了)。
        • 缓冲有大小限制,并且在默认配置下很容易超出,并且这种情况并不少见,一旦发生也不太容易追踪。

      因此这两个方法变得不可靠了,特别是当你需要更改开发环境或者生产环境的配置的时候。这就是为什么输出缓冲被认为只是一种蹩脚的变通方法。

      建议参考官方手册里的基本 使用方法 ,以及它的优缺点:

      • 输出缓冲是什么
      • 为什么使用 output buffering
      • 使用输出缓冲是不好的实践吗?
      • 正确使用 output buffering 解决 “header already sent” 的例子

      但是在其他的服务器上是好的?

      如果你之前没有收到过头信息的 warning ,那么 php.ini 里的 output_buffering 设置改变了。在现在的/不同的服务器上很有可能没有设置。

      使用 headers_sent() 检查

      你可以使用 headers_sent 来检查是否可以发送头信息。这种方法可以有效地检查以便输出一个错误信息或是应用其他的逻辑。

      不错的回退变通方法有:

      • HTML e8e496c15ba93d81f6ea4fe5f55a2244 tag

        如果你的应用程序很难在结构上解决这个问题,有个简单但显得不专业的做法是在 HTML

        标签中来跳转网页。可以这样实现:

        <meta http-equiv="Location" content="http://example.com/">

        或者加上一个延迟时间

        <meta http-equiv="Refresh" content="2; url=../target.html">

      • JavaScript 跳转

        另一个可选的方法就是使用 JavaScript 跳转 来实现网页跳转:

        <script> location.replace("target.html"); </script>

      这种方式相比较

      方法起来更兼容 HTML 标准,它只依赖于可以运行 JavaScript 的客户端。

      这两种方式在 HTTP header() 调用失败时都提供了可以接受的回退方式。理想化的处理方式应该是将跳转与其它方式结合,给出对用户友好的辅助信息并且提供一个可点的链接以供后续操作。

      为什么 setcookie() 和 session_start() 都会被影响

      setcookie() 和 session_start() 都需要发送一个 set-cookie: 的 HTTP 头信息。这种情况就和前面输出 header() 的情况类似,所以同样会出现由于过早地输出错误信息导致的错误。

      (当然它们受影响也有可能是因为客户端禁止了 cookie 导致的,设置可能是代理的问题。很明显,session 也取决去剩余磁盘空间大小或者 php.ini 里的其它设置)

      原文链接: http://stackoverflow.com/questions/8028957/how-to-fix-headers-already-sent-error-in-php

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。