1. ホーム
  2. php

[解決済み] PHPで「Header already sent」エラーを修正する方法

2022-03-19 17:14:21

質問

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

警告 Cannot modify header information - headers already sent by ( 出力は /some/file.php:12 で開始されました。 ) にある /some/file.php について 23行目

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

この原因は何でしょうか?また、それを修正する方法は?

解決方法は?

ヘッダーを送信する前に出力がない!

HTTPヘッダを送信/変更する関数は必ず起動すること 出力が行われる前に . 概要 それ以外の場合は呼び出しに失敗します。

警告 Cannot modify header information - headers already sent (output started at スクリプト:行 )

HTTPヘッダを変更する機能には、以下のようなものがあります。

出力することができます。

  • 意図的である。

    • print , echo および出力を生成するその他の関数
    • <html> 前のセクション <?php のコードを使用します。

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

なぜヘッダーを出力の前に送らなければならないかを理解するためには の典型的な例を見てみましょう。 HTTP のレスポンスがあります。PHPスクリプトは主にHTMLコンテンツを生成しますが、同時に HTTP/CGIヘッダーのセットをウェブサーバーに送信します。

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はヘッダーを ヘッダを最初にウェブサーバに送信します。これは一度しかできません。 二重改行した後は、もう修正することができません。

PHPが最初の出力を受け取るとき ( print , echo , <html> ) になります。 フラッシュ 収集されたすべてのヘッダ。その後、すべての出力を送信することができます となります。しかし、それ以上のHTTPヘッダを送信することは、その時点では不可能です。

早すぎる出力が発生した箇所を調べるには?

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

<ブロッククオート

警告 ヘッダー情報を変更できません - ヘッダーはすでに (出力開始位置 /www/usr2345/htdocs/ auth.php:52 ) にある /www/usr2345/htdocs/index.php の 100 行目にあります。

ここで、"line 100"はスクリプトを指しており、そのスクリプトでは header() 起動 が失敗しました。

を使用することで、" で出力が開始されました。 括弧の中の " の注釈はより重要である。 これは、前の出力のソースを示すものです。この例では auth.php そして ライン 52 . そこで、早すぎる出力を探す必要があったんですね。

代表的な原因

  1. 印刷、エコー

    からの意図的な出力 printecho ステートメントを使用すると、HTTP ヘッダを送信する機会が終了してしまいます。それを避けるためには、アプリケーションフローを再構築する必要があります。使用方法 機能 とテンプレート化するスキームがあります。確実な header() の呼び出しが発生します。 メッセージ が書き出されます。

    出力を行う関数は以下の通りです。

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


    などとユーザー定義関数があります。

  2. 生のHTML領域

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

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

    テンプレート方式で、処理と出力ロジックを分離する。

    • フォーム処理のコードをスクリプトの上に配置する。
    • 一時的な文字列変数を使用して、メッセージを繰り延べる。
    • 実際の出力ロジックや混在するHTML出力は最後に続くようにします。
  3. 前の空白 <?php script.phpの場合 1行目 警告

    警告がインラインの出力に言及している場合 1 であれば、それはほとんど リーディング 空白 の前にあるテキストまたはHTML <?php トークンを使用します。

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

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

    ?>
    
    <?php
    
    

    PHPは実際に シングル のように、closeタグの後に改行します。しかし、それは は、複数の改行やタブ、スペースがそのような隙間に移動することを補償しています。

  4. UTF-8 BOM

    改行やスペースだけでも問題になることがあります。しかし、quot;invisible".もあります。 という文字列があります。最も有名なのは UTF-8 BOM (バイトオーダーマーク) これは、ほとんどのテキストエディタでは表示されません。これは、バイト列 EF BB BF これはUTF-8でエンコードされた文書ではオプションであり、冗長です。しかし、PHP はこれを生の出力として扱わなければなりません。この場合、次のような文字が表示されます。  が出力されます (クライアントがドキュメントを Latin-1 として解釈している場合)、または同様の "garbage" が出力されます。

    特にグラフィカルなエディタやJavaベースのIDEは、その存在に気づかない。 存在する。彼らはそれを視覚化しません(Unicode標準によって義務付けられています)。 しかし、ほとんどのプログラマーエディターやコンソールエディターはそうしています。

    そこでは、問題を早期に認識することが容易です。他のエディタでは ファイル/設定メニューに存在する(WindowsのNotepad++はそれを識別して 問題解決 ), BOMの存在を確認するためのもう一つの方法は ヘキサエディタ . nix システムの場合 hexdump は通常利用可能です。 これらの問題やその他の問題の監査を簡素化するグラフィカルなバリアントがない場合。

    簡単な対処法としては、テキストエディタでファイルを保存する際に "UTF-8 (no BOM)".と設定することです。 などで保存するように設定することです。多くの場合、新参者は新しいファイルを作成し、以前のコードをコピー&ペーストして戻すという方法を取ります。

    修正ユーティリティ

    また、テキストファイルを検査し、書き換えるための自動化ツールもあります ( sed / awk または recode ). PHP では、特に phptags タグのtidier . closeタグとopenタグを長いものと短いものに書き換えるだけでなく、簡単に は、先頭と末尾のホワイトスペース、UnicodeとUTF-x BOMの問題を修正します。

    phptags  --whitespace  *.php
    
    

    インクルードディレクトリやプロジェクトディレクトリ全体で使っても安全です。

  5. の後に空白を入れる。 ?>

    の後ろとしてエラーソースが記載されている場合、そのエラーソースは クロージング ?> であれば、ここで空白や生テキストが書き出されたことになります。 PHP のエンドマーカーは、この時点ではスクリプトの実行を終了させません。これ以降のテキストや空白文字は、ページの内容として書き出されます。 のままです。

    特に初心者の方には、一般的に、末尾の ?> PHP の閉じタグは省略します。これは を省く。 は、このようなケースのごく一部です。 (ごく一般的に include()d スクリプトが原因です)。

  6. エラーソースに "Unknown on line 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() の失敗があります。

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

PHPs 出力バッファリング は、この問題を軽減するための回避策です。多くの場合、この回避策は確実に機能しますが アプリケーションを適切に構造化し、出力と制御を分離する代わりに ロジックを使用します。実際の目的は、ウェブサーバーへのチャンク転送を最小化することです。

  1. output_buffering= の設定は、それにもかかわらず、役に立ちます。 この設定は php.ini または .htaccess あるいは .user.ini で 最近の FPM/FastCGI のセットアップ。
    これを有効にすると、PHP は出力をウェブサーバーに即座に渡すのではなく、バッファリングすることができます。このため、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ヘッダー() の呼び出しに失敗しました。理想的なのは、常にユーザーフレンドリーなメッセージと 最後の手段として、クリッカブルリンクを使用します。(例えば http_redirect() PECL 拡張はこれを行います)。

なぜ setcookie()session_start() も影響を受けます。

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

(もちろん、ブラウザのクッキーが無効な場合も影響します。 あるいはプロキシの問題。セッションの機能性は、明らかに ディスク容量やその他のphp.iniの設定など)

リンク集