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

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

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

警告: ヘッダー情報を変更できません - ヘッダーは既に送信されています (出力は /some/file.php:12 で開始されました) /some/file.php23 行目

エラーメッセージに記載されている行には、header()そしてsetcookie()通話します。

原因は何でしょうか? また、どうすれば修正できるでしょうか?

ベストアンサー1

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

HTTP ヘッダーを送信/変更する関数は、出力が行われる前に呼び出す必要があります。summary ⇊そうしないと、呼び出しは失敗します。

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

HTTP ヘッダーを変更する関数には次のようなものがあります。

出力は次のようになります。

  • 意図的:

    • printechoおよび出力を生成するその他の関数
    • <html>コードの前の生のセクション<?php

なぜそうなるのでしょうか?

出力の前にヘッダーを送信する必要がある理由を理解するには、典型的な例を見る必要があります。ウェブ応答。PHP スクリプトは主に HTML コンテンツを生成しますが、一連の HTTP/CGI ヘッダーも Web サーバーに渡します。

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 サーバーに渡す必要があります。これは 1 回しか実行できません。二重改行の後は、ヘッダーを修正できなくなります。

PHP は最初の出力 ( print、、) を受信すると、収集されたすべてのヘッダーをフラッシュしますechoその後は、必要なすべての出力を送信できます。ただし、その場合、さらに HTTP ヘッダーを送信することは不可能です。<html>

早期出力が発生した場所をどのように調べることができますか?

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

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

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

括弧内の「出力は で開始されましたauth.php」という注記の方が重要です。これは、以前の出力のソースを示します。この例では、行です52。ここで、早すぎる出力を探す必要がありました。

一般的な原因:

  1. 印刷、エコー

    printおよびステートメントからの意図的な出力は、echoHTTPヘッダーを送信する機会を終了させます。これを回避するには、アプリケーションフローを再構築する必要があります。機能およびテンプレート スキーム。メッセージが書き込まれる前にheader()呼び出しが行われるようにします。

    出力を生成する関数には以下が含まれる。

    • print、、、echoprintfvprintf
    • trigger_error、、、、、ob_flushob_end_flushvar_dumpprint_r
    • readfile、、、、、passthruflushimagepngimagejpeg


    その他、ユーザー定義関数など。

  2. 生の HTML 領域

    ファイル内の解析されていない HTML セクションも.php直接出力されます。呼び出しをトリガーするスクリプト条件は、rawブロック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 (バイトオーダーマーク)これは、ほとんどのテキスト エディタでは表示されません。これはEF BB BF、UTF-8 でエンコードされたドキュメントではオプションで冗長なバイト シーケンスです。ただし、PHP ではこれを生の出力として処理する必要があります。出力内の文字 (クライアントがドキュメントを Latin-1 として解釈する場合) または同様の「ゴミ」として表示される可能性があります。

    特に、グラフィカル エディターや Java ベースの IDE では、その存在が認識されません。Unicode 標準により、視覚化されません。ただし、ほとんどのプログラマー エディターやコンソール エディターでは、次の処理が行われます。

    joes エディタでは UTF-8 BOM プレースホルダーが表示され、MC エディタではドットが表示されます

    そこでは、問題を早期に認識するのは簡単です。他のエディターでは、ファイル/設定メニューでその存在を識別できます(WindowsのNotepad++では、問題を解決する)、BOMの存在を確認する別の方法として、16進エディタを使用する方法があります。*nixシステムではhexdump通常は、これらの問題やその他の問題の監査を簡素化するグラフィカルなバージョンが利用可能です。

    beav hexeditor が utf-8 bom を表示

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

    修正ユーティリティ

    テキストファイルを検査して書き換える自動化ツールもあります(sed/awkまたはrecode)。PHPの場合は、phptagsタグを整理する閉じタグと開きタグを長い形式と短い形式に書き換えるだけでなく、先頭と末尾の空白、Unicode および UTF-x BOM の問題も簡単に修正します。

    phptags  --whitespace  *.php
    

    インクルード ディレクトリ全体またはプロジェクト ディレクトリで使用しても安全です。

  5. 後ろの空白?>

    エラーの原因が閉鎖?>ここで、空白または生のテキストが書き出されます。PHP 終了マーカーは、この時点ではスクリプトの実行を終了しません。その後のテキスト/スペース文字は、ページ コンテンツとして引き続き書き出されます。

    特に初心者には、末尾の?>PHP 終了タグを省略することが一般的に推奨されています。これにより、こうしたケースの一部が回避されますinclude()d。(スクリプトが原因となることが非常に多くあります。)

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

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

    • gzipストリームエンコード設定が原因の場合もありますまたはob_gzhandler
    • extension=しかし、二重にロードされたモジュールが暗黙の PHP 起動/警告メッセージを生成する可能性もあります。

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

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

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

エラーメッセージなし

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

したがって、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=設定は役に立ちます。php.iniまたは.htaccessあるいは.user.ini最新の FPM/FastCGI 設定では、
    これを有効にすることで、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">
    

    このセクション以降で使用すると、HTML が有効ではなくなります<head>。ほとんどのブラウザは、これを引き続き受け入れます。

  • JavaScript リダイレクト

    代替案としてJavaScript リダイレクトページのリダイレクトに使用できます:

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

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

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

なぜsetcookie()、そしてsession_start()も影響を受けるのか

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

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

その他のリンク

おすすめ記事