PHPで「ヘッダーはすでに送信されています」エラーを修正する方法

2011年11月07日に質問されました。  ·  閲覧回数 1.5M回  ·  ソース

Moses89 picture
2011年11月07日

スクリプトを実行すると、次のようなエラーが発生します。

警告:ヘッダー情報を変更することはできません-23行目の/some/file.php

エラーメッセージに記載されている行には、 header()およびsetcookie()呼び出しが含まれています。

これの理由は何でしょうか? そしてそれを修正する方法は?

回答

mario picture
2011年11月07日
3066

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

HTTPヘッダーを送信/変更する関数は、出力を行う要約⇊それ以外の場合、呼び出しは失敗します。

警告:ヘッダー情報を変更できません-ヘッダーはすでに送信されています(出力はscript:lineで開始され

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<html> )を受け取ると、収集されたすべてのヘッダーがフラッシュされます。 その後、必要なすべての出力を送信できます。 しかし、それ以上のHTTPヘッダーを送信することは不可能です。

時期尚早の出力が発生した場所をどのように見つけることができますか?

header()警告には、問題の原因を特定するためのすべての関連情報が含まれています。

警告:CAN変更しないヘッダ情報-既に(出力/ WWW / usr2345 / htdocsに/ auth.phpで開始:52)によって送られたヘッダライン100上に/www/usr2345/htdocs/index.php

ここで、「100行目」は、 header()呼び出しが失敗したスクリプトを指し

括弧内の「出力開始」の注記はより重要です。 これは、前の出力のソースを示します。 この例では、 auth.php52です。 ここで、時期尚早の出力を探す必要がありました。

典型的な原因:

  1. 印刷、エコー

    printおよびechoステートメントからの意図的な出力は、HTTPヘッダーを送信する機会を終了します。 これを回避するには、アプリケーションフローを再構築する必要があります。 関数とテンプレートスキームを使用し前に、 header()呼び出しが発生することを確認してください。

    出力を生成する関数は次のとおりです。

    • printechoprintfvprintf
    • trigger_errorob_flushob_end_flushvar_dumpprint_r
    • readfilepassthruflushimagepngimagejpeg


    とりわけ、ユーザー定義関数。

  2. 生のHTML領域

    .phpファイル内の未解析のHTMLセクションも直接出力されます。 header()呼び出しをトリガーするスクリプト条件は生の<html>ブロックの前に注意する必要があります。

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

    テンプレートスキームを使用して、処理を出力ロジックから分離します。

    • フォーム処理コードをスクリプトの上に配置します。
    • 一時的な文字列変数を使用してメッセージを延期します。
    • 実際の出力ロジックと混合HTML出力は最後に続く必要があります。

  3. 空白の前に<?php "script.phpライン1"の警告について

    警告が行1出力に言及している場合、それはほとんどの場合、開始<?phpトークンの前の先頭の空白、テキスト、またはHTMLです。

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

    同様に、追加されたスクリプトまたはスクリプトセクションでも発生する可能性があります。

    ?>
    
    <?php
    

    PHPは、タグを閉じると、実際には1つの改行を消費します。 ただし、そのようなギャップにシフトされた複数の改行、タブ、またはスペースは補正されません。

  4. UTF-8 BOM

    改行とスペースだけが問題になる可能性があります。 しかし、これを引き起こす可能性のある「見えない」文字シーケンスもあります。 最も有名なのは、ほとんどのテキストエディタで表示されない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 ++は問題を識別して16進エディターに頼ることhexdumpが通常利用可能ですが、これらの問題やその他の問題の監査を簡素化するグラフィカルなバリアントではありません。

    beav hexeditor showing utf-8 bom

    簡単な修正は、ファイルを「UTF-8(BOMなし)」または同様の命名法で保存するようにテキストエディタを設定することです。 それ以外の場合、新規参入者は新しいファイルを作成し、前のコードをコピーして貼り付けるだけで済みます。

    修正ユーティリティ

    テキストファイルを調べて書き換えるための自動化されたツールもあります( sed / awkまたはrecode )。 特にPHPの場合、 phptagsタグの整理整頓があります。 クローズタグとオープンタグを長い形式と短い形式に書き換えますが、先頭と末尾の空白、Unicode、UTF-xBOMの問題も簡単に修正できます。

    phptags  --whitespace  *.php
    

    インクルードディレクトリまたはプロジェクトディレクトリ全体で使用するのは正気です。

  5. ?>後の空白

    エラーの原因が?>

    特に新規参入者には、末尾の?> PHPクローズタグを省略することをお勧めします。 これにより、これらのケースのごく一部が回避されます。 (非常に一般的にはinclude()dスクリプトが原因です。)

  6. 「0行目で不明」と記載されているエラーソース

    エラーソースが具体化されていない場合、これは通常、PHP拡張機能またはphp.ini設定です。

    • gzipストリームエンコーディング設定またはob_gzhandlerます。
    • ただし、二重にロードされたextension=モジュールで、暗黙のPHP起動/警告メッセージを生成することもできます。

  7. 先行するエラーメッセージ

    別のPHPステートメントまたは式によって警告メッセージまたは通知が出力される場合、それも時期尚早の出力としてカウントされます。

    この場合、エラーを回避するか、ステートメントの実行を遅らせるか、 isset()または@()メッセージを抑制する必要があります。どちらも後でデバッグを妨げない場合です。

エラーメッセージはありません

php.iniごとにerror_reportingまたはdisplay_errors無効になっている場合、警告は表示されません。 ただし、エラーを無視しても問題は解決しません。 早すぎる出力の後でも、ヘッダーを送信することはできません。

したがって、 header("Location: ...")リダイレクトがサイレントに失敗した場合は、警告をプローブすることをお勧めします。 呼び出しスクリプトの上にある2つの簡単なコマンドでそれらを再度有効にします。

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

または、他のすべてが失敗した場合はset_error_handler("var_dump");

リダイレクトヘッダーと言えば、最終的なコードパスには次のようなイディオムを使用する必要があります。

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

できれば、 header()失敗した場合にユーザーメッセージを出力するユーティリティ関数ですら。

回避策としての出力バッファリング

PHPの出力バッファリングは、この問題を軽減するための回避策です。 多くの場合、確実に機能しますが、適切なアプリケーションの構造化と制御ロジックからの出力の分離に代わるものではありません。 その実際の目的は、Webサーバーへのチャンク転送を最小限に抑えることです。

  1. それでも、 output_buffering=設定が役立ちます。 最新のFPM / FastCGIセットアップでは、 php.iniで、または.htaccessまたは.user.iniを介して構成します。
    これを有効にすると、PHPは出力をWebサーバーに即座に渡すのではなく、バッファリングできるようになります。 したがって、PHPはHTTPヘッダーを集約できます。

  2. 同様に、呼び出しスクリプトの上でob_start();呼び出すこともできます。 ただし、これは複数の理由で信頼性が低くなります。

    • <?php ob_start(); ?>が最初のスクリプトを開始したとしても、空白またはBOMが以前にシャッフルされて、効果がなくなる可能性があります。

    • HTML出力の空白を隠すことができます。 ただし、アプリケーションロジックがバイナリコンテンツ(生成された画像など)を送信しようとするとすぐに、バッファリングされた無関係な出力が問題になります。 (さらなる回避策としてob_clean()が必要です。)

    • バッファのサイズは制限されており、デフォルトのままにすると簡単にオーバーランする可能性があります。 そして、それも珍しいことではなく、発生したとき困難です。

したがって、両方のアプローチは、特に開発セットアップや本番サーバーを切り替えるときに、信頼性が低くなる可能性があります。 そのため、出力バッファリングは単なる松葉杖/厳密な回避策と広く見なされています。

マニュアルの基本的な使用例、およびその他の長所と短所も参照してください。

しかし、それは他のサーバーで動作しました!?

以前にヘッダーの警告が表示されなかった場合は、出力バッファリングのphp.ini設定が変更されています。 現在の/新しいサーバーでは構成されていない可能性があります。

headers_sent()確認

ヘッダーを送信することがまだ可能かどうかを調べるために、いつでもheaders_sent()を使用できます。 これは、条件付きで情報を印刷したり、他のフォールバックロジックを適用したりするのに役立ちます。

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

便利なフォールバック回避策は次のとおりです。

  • HTML <meta>タグ

    アプリケーションを構造的に修正するのが難しい場合、リダイレクトを許可する簡単な(しかしやや専門的ではない)方法は、HTML <meta>タグを挿入することです。 リダイレクトは次の方法で実現できます。

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

    または少し遅れて:

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

    これにより、 <head>セクションを超えて使用すると、HTMLが無効になります。 ほとんどのブラウザはまだそれを受け入れます。

  • JavaScriptリダイレクト

    別の方法として、 JavaScriptリダイレクトをページリダイレクトに使用できます。

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

    これは多くの場合、 <meta>回避策よりもHTMLに準拠していますが、JavaScript対応のクライアントに依存することになります。

ただし、どちらのアプローチも、正規のHTTP header()呼び出しが失敗した場合に許容可能なフォールバックを行います。 理想的には、最後の手段として、これを常にユーザーフレンドリーなメッセージとクリック可能なリンクと組み合わせるでしょう。 (これは、たとえばhttp_redirect() PECL拡張機能が行うことです。)

setcookie()session_start()も影響を受ける理由

setcookie()session_start()両方がsetcookie() Set-Cookie: HTTPヘッダーを送信する必要があります。 したがって、同じ条件が適用され、出力が早すぎる状況でも同様のエラーメッセージが生成されます。

(もちろん、ブラウザで無効になっているCookieや、プロキシの問題によっても影響を受けます。セッション機能は、明らかに空きディスク容量やその他のphp.ini設定などにも依存します。)

その他のリンク

phihag picture
2011年11月07日
203

このエラーメッセージは、HTTPヘッダー( setcookieまたはheader )を送信する前に何かが送信されたときにトリガーされます。 HTTPヘッダーの前に何かを出力する一般的な理由は次のとおりです。

  • 多くの場合、次のようにファイルの最初または最後にある偶発的な空白。

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

これを回避するには、終了?>省略します。とにかく必須ではありません。

  • phpファイルの先頭にあるバイト順マーク。 phpファイルを16進エディターで調べて、それが当てはまるかどうかを確認します。 それらはバイト3F 3C始まる必要があります。 ファイルの先頭からBOM EF BB BFを安全に削除できます。
  • echoprintfreadfilepassthru<?前のコードなどの明示的な出力。
  • display_errors php.iniプロパティが設定されている場合、phpによって出力される警告。 プログラマーのミスでクラッシュする代わりに、phpはサイレントにエラーを修正し、警告を発します。 display_errorsまたはerror_reporting構成を変更できますが、問題を修正する必要があります。
    一般的な理由は、配列の未定義の要素へのアクセス(入力が設定されているかどうかをテストするために、 emptyまたはissetを使用せずに$_POST['input']など)、または代わりに未定義の定数を使用することです。文字列リテラル( $_POST[input] 、引用符がないことに注意してください)。

出力バッファリングをオンにすると、問題が解決するはずです。 ob_startの呼び出し後のすべての出力は、バッファを解放するまで、たとえばob_end_flushしてメモリにバッファリングされます。

ただし、出力バッファリングは問題を回避しますが、アプリケーションがHTTPヘッダーの前にHTTPボディを出力する理由を実際に判断する必要があります。 それは、電話をかけて、あなたの日と天気について話し合ってから、発信者に間違った番号を持っていることを伝えるようなものです。

Manish Shrivastava picture
2012年08月01日
126

私は以前に何度もこのエラーを受け取りました、そして私はすべてのPHPプログラマーが少なくとも一度はこのエラーを受け取ったと確信しています。

考えられる解決策1

このエラーは、ファイルの開始またはファイルの終了の空白が原因である可能性があります。これらの空白はここにあるべきではありません。

例)ここに空白スペースがあってはなりません

   echo "your code here";

?>
THERE SHOULD BE NO BLANK SPACES HERE

このエラーの原因となっているファイルに関連付けられているすべてのファイルを確認してください。

注: gedit(デフォルトのLinuxエディター)のようなEDITOR(IDE)は、保存ファイルに1行の空白行を追加することがあります。 Linuxを使用している場合。

考えられる解決策2:これが当てはまらない場合は、 ob_startを使用してバッファリングを出力します。

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

これにより、出力バッファリングがオンになり、ページがバッファリングされた後にヘッダーが作成されます。

Ipsita Rout picture
2013年03月24日
90

以下の行の代わりに

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

それは間違いなくあなたの問題を解決します。 同じ問題に直面しましたが、上記の方法でヘッダーの場所を書き込むことで解決しました。

Seth Carnegie picture
2011年11月07日
41

あなたがやる

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

クッキーを設定する前に、これは許可されていません。 ヘッダーの前に出力を送信することはできません。空白行も送信できません。

Jorn picture
2015年04月10日
34

一般的な問題:

(コピー

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

1) header(.......);コマンドの前に出力(つまり、 echo..またはHTMLコードがあってはなりません。

2) <?php?>タグの後の空白(または改行)を削除します。

3)ゴールデンルール! -そのphpファイル(およびinclude他のファイル)にBOMエンコードUTF-8だけではありません)。 これは多くの場合問題です( UTF8でエンコードされたファイルのphpファイルの先頭に特殊文字が含まれているため、テキストエディターには表示されません)!!!!!!!!!!!

4)header(...);あなたが使用する必要がありますexit;

5)常に301または302参照を使用します。

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

6)エラー報告をオンにして、エラーを見つけます。 機能していない機能が原因でエラーが発生している可能性があります。 エラーレポートをオンにするときは、常に最上位のエラーを最初に修正する必要があります。 たとえば、「警告:date_default_timezone_get():システムのタイムゾーン設定に依存するのは安全ではありません」のようになります。 -さらに下に行くと、「ヘッダーが送信されていません」というエラーが表示される場合があります。 最上位(1番目)のエラーを修正した後、ページを再ロードします。 それでもエラーが発生する場合は、一番上のエラーを再度修正してください。

7)上記のいずれも役に立たない場合は、JAVSCRIPTリダイレクトを使用します(ただし、強く推奨されない方法)。カスタムケースでは最後のチャンスかもしれません...:

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
Sarfraz picture
2011年11月07日
33

それはこの行のためです:

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

ヘッダーを送信する前に、何も印刷/エコーしないでください。

Sliq picture
2012年05月17日
27

簡単なヒント:最初の<?phpタグの直前にある、スクリプト内の単純なスペース(または非表示の特殊文字)がこれを引き起こす可能性があります。 特に、チームで作業していて、誰かが「弱い」IDEを使用している場合や、奇妙なテキストエディタでファイルをいじり回している場合は特にそうです。

私はこれらのものを見ました;)

MD. Sahib Bin Mahboob picture
2013年11月08日
22

別の悪い習慣は、まだ述べられていないこの問題を引き起こす可能性があります。

このコードスニペットを参照してください。

<?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ファイルはUnix LF (linefeed) line ending使用する必要があります。
Lupin picture
2015年05月22日
16

開発プロセスにWINワークステーションとLINUXシステム(ホスティング)の両方があり、コード内で関連する行の前に出力が表示されない場合は、ファイルのフォーマットとUnix LF(改行)行末の欠如が考えられます。 。

これをすばやく修正するために通常行うことは、ファイルの名前を変更し、LINUXシステムで名前を変更したファイルの代わりに新しいファイルを作成し、その中にコンテンツをコピーすることです。 WINで作成されたファイルの一部がホスティングに移動されるとこの問題が発生するため、これで問題が解決することがよくあります。

この修正は、FTPで管理するサイトの簡単な修正であり、新しいチームメンバーの時間を節約できる場合があります。