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

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

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
リリース: 2016-06-23 13:14:44
オリジナル
653 人が閲覧しました

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

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

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

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

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

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

出力は次のとおりです:

  • 意図的でない:
    • UTF-8 BOM
  • 意図的:
    • print 、 echo などの出力を生成するメソッド
    • ブロック

このエラーが発生する理由

出力を送信する前に HTTP ヘッダーが必要な理由を理解するため、典型的な HTTP 応答を見てみる必要があります。 PHP スクリプトは主に HTML の生成に使用されますが、一連の HTTP/CGI ヘッダー情報も Web サーバーに送信します。

HTTP/1.1 200 OKPowered-By: PHP/5.3.7Vary: Accept-EncodingContent-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 サーバーに送信する必要があり、送信できるのは 1 回だけであり、その後はヘッダー情報を変更できません。

PHP が最初に出力 ( print 、 echo 、 ) を受け取ると、収集されたすべてのヘッダー情報がクリアされます。この後、出力したい内容はすべて出力できますが、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() の呼び出しをトリガーするスクリプト内の条件はすべて、 ブロックの前に宣言する必要があります。

  3. 警告が 1 行の出力を指している場合、それは

     <?php// 在 <?php 前有个空格
    ログイン後にコピー

また、添付されたスクリプトまたはスクリプト ブロックに表示される場合もあります:

?><?php
ログイン後にコピー

PHP は終了タグの後に改行を占有しますが、その上には改行を挿入しません。タブ、または空白スペースにスペースを入れます(これは私たち自身の責任であることを意味します)。

  1. UTF-8 BOM

    改行やスペースは問題を引き起こす可能性がありますが、目に見えない文字シーケンスも問題を引き起こす可能性があります。最も有名なものは UTF-8 BOM で、ほとんどのテキスト エディターでは表示されません。これは、UTF-8 でエンコードされたドキュメント内のオプションまたは冗長バイト シーケンスであり、EF BB BF としてマークされます。ただし、PHP はそれを生の出力として扱う必要があります。 â で終わる場合もあります このような記号出力 (クライアントが文書を Latin-1 として解釈する場合) またはその他の「不正な出力」。

    以某种图形化的编辑器或者基于 JAVA 的 IDE 查看这类文件时,你可能察觉不到 UTF-8 BOM 的存在。它们没有把 UTF-8 BOM 形象化(受制于 Unicode 标准)。然而大多数程序编辑器和控制台编辑程序会这样处理:

    像这样就能简单地提早发现问题了。其他的编辑器在设置某些选项后也能纠正这样的问题(Windows 上的 Notepad++ 可以识别并且 纠正 BOM 问题 ),另一个发现 BOM 的方法就是借助十六进制的编辑器。在 *nix 系统上,大都提供了 hexdump ,如果没有的话,其他图形化的变种也可以用来简化审计这些问题的步骤:

    一个简单的修正方法就是将文本编辑器设置为 以 UTF-8 (no BOM) 保存文件save files as UTF-8 (no BOM) )或者其他类似的设置。

    修正程序

    有很多自动化的工具可以检测并修改文本文件( sed / awk 或者 recode )。PHP 里有 phptags 。它可以把打开标签和关闭标签重写成长标签(

    phptags  --whitespace  *.php
    ログイン後にコピー

同样,你可以在某个目录或整个项目目录使用这个命令。

  1. ?> 后的空白

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

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

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

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

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

    如果前面的 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() 来设置,但是它并没那么可靠:
    • 即使 在第一个脚本里,空格或者 BOM 也有可能在此之前被输出
    • 它可以隐藏 HTML 输出里的空格(将空格放到 buffer 中),但是只要应用程序逻辑企图发送二进制内容(比如生成的图片),缓冲里的无关的输出就会成为问题(这样 ob_clean() 方法就成为下一步的变通方法了)。
    • 缓冲有大小限制,并且在默认配置下很容易超出,并且这种情况并不少见,一旦发生也不太容易追踪。

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

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

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

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

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

使用 headers_sent() 检查

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

不错的回退变通方法有:

  • HTML 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

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート