ヘッダーを送信する前に出力がありません!
出力を行う前に、 HTTPヘッダーを送信/変更する関数を呼び出す必要があります。
summary ⇊
そうでない場合、呼び出しは失敗します。
警告:ヘッダー情報を変更できません-ヘッダーはすでに送信されています(出力はscript:lineで開始されます)
HTTPヘッダーを変更する関数には次のものがあります。
出力は次のとおりです。
意図的:
print
、echo
および出力を生成するその他の関数
- 未加工
<html>
セクションの前の<?php
コード。
なぜそれが起こるのですか?
ヘッダーを出力前に送信する必要がある理由を理解するには、一般的なHTTP
応答を調べる必要があります。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はまずヘッダーをウェブサーバーに渡す必要があります。それは一度しかできません。二重改行の後、それを修正することはできません。
PHPが最初の出力(、、)を受信するprint
とecho
、収集されたすべてのヘッダー<html>
を
フラッシュします。その後、必要なすべての出力を送信できます。しかし、それ以上のHTTPヘッダーを送信することは不可能です。
時期尚早の出力が発生した場所をどのように見つけることができますか?
header()
警告は、問題の原因を特定するために、関連するすべての情報が含まれています。
警告:ヘッダー情報を変更できません-ヘッダーは既に送信されており
(出力は / www / usr2345 / htdocs / auth.php:52 から開始されます)/www/usr2345/htdocs/index.phpの100行目
ここで「100行目」は、header()
呼び出しが失敗したスクリプトを指します。
括弧内の「出力開始位置」の注記の方が重要です。以前の出力のソースを示します。この例では、それはだauth.php
とライン52
。これは、時期尚早の出力を探す必要がある場所です。
典型的な原因:
印刷、エコー
print
and echo
ステートメントからの意図的な出力により、HTTPヘッダーを送信する機会が終了します。これを回避するには、アプリケーションフローを再構築する必要があります。関数
とテンプレートスキームを使用します。確認header()
の呼び出しが発生する前にメッセージが書き出されます。
出力を生成する関数には、
print
、echo
、printf
、vprintf
trigger_error
、ob_flush
、ob_end_flush
、var_dump
、print_r
readfile
、passthru
、flush
、imagepng
、imagejpeg
特にユーザー定義関数。
生のHTML領域
.php
ファイル内の解析されていないHTMLセクションも直接出力されます。header()
呼び出しをトリガーするスクリプト条件は、未加工<html>
ブロックの前に注意する必要があります。
<!DOCTYPE html>
<?php
// Too late for headers already.
テンプレートスキームを使用して、処理を出力ロジックから分離します。
- スクリプトの上にフォーム処理コードを配置します。
- 一時的な文字列変数を使用してメッセージを延期します。
- 実際の出力ロジックと混合HTML出力は最後に続く必要があります。
<?php
「script.php 1行目」警告の前の空白
警告が行内の出力を参照している場合、1
それは主に開始トークンの前の空白、テキスト、またはHTMLの先頭<?php
です。
<?php
# There's a SINGLE space/newline before <? - Which already seals it.
同様に、追加されたスクリプトまたはスクリプトセクションでも発生する可能性があります。
?>
<?php
PHPは、実際には終了タグの後に1つの改行を消費します。ただし、このようなギャップにシフトされた複数の改行、タブ、スペースは補正されません。
UTF-8 BOM
改行とスペースだけでも問題になることがあります。しかし、これを引き起こす可能性のある「見えない」文字シーケンスもあります。最も有名なのは
、ほとんどのテキストエディターでは表示されないUTF-8 BOM(Byte-Order-Mark)です。これはバイトシーケンスEF BB BF
であり、UTF-8でエンコードされたドキュメントではオプションであり、冗長です。ただし、PHPはそれを生の出力として処理する必要があります。キャラクターとして現れるかもしれません
、出力(クライアントがドキュメントをLatin-1と解釈した場合)または同様の「ガベージ」場合があります。
特に、グラフィカルエディタとJavaベースのIDEは、その存在に気づいていません。彼らはそれを視覚化しません(Unicode標準で義務付けられています)。ただし、ほとんどのプログラマーおよびコンソールエディターは次のことを行います。
そこで問題を早期に認識するのは簡単です。他の編集者は、ファイル/設定メニューでその存在を識別できます(WindowsのNotepad ++ は問題を識別して修正できます
)。BOMの存在を検査する別のオプションは、hexeditorを使用します。* nixシステムでhexdump
は、これらの問題やその他の問題の監査を簡素化するグラフィカルなバリアントではない場合でも、通常は利用できます。
簡単な修正は、ファイルを「UTF-8(BOMなし)」または同様の命名法で保存するようにテキストエディターを設定することです。それ以外の場合は、新しいファイルを作成して、以前のコードをコピー&ペーストするだけで済むことがよくあります。
修正ユーティリティ
テキストファイル(sed
/awk
またはrecode
)を調べて書き換えるための自動化ツールもあります。特にPHPにはphptags
タグtidierがあります。クローズタグとオープンタグを長い形式と短い形式に書き換えますが、先頭と末尾の空白、Unicode、UTF-x BOMの問題も簡単に修正します。
phptags --whitespace *.php
インクルードまたはプロジェクトディレクトリ全体で使用するのは常識です。
後の空白 ?>
エラーの原因がクロージングの?>
背後にあると述べられている
場合は、ここで空白または生のテキストが書き出されます。PHP終了マーカーは、この時点ではスクリプトの実行を終了しません。それ以降のテキスト/スペース文字は、ページコンテンツとして書き出されます。
一般に、特に初心者には、末尾の?>
PHP終了タグを省略してください。これは、これらのケースのごく一部を避けています。(かなり一般的にinclude()d
スクリプトが原因です。)
「行0で不明」と記載されたエラーソース
エラーソースが具体化されていない場合、これは通常、PHP拡張またはphp.ini設定です。
- それは時折だ
gzip
ストリームのエンコードの設定
やob_gzhandler
。
- ただし
extension=
、暗黙的にPHPの起動/警告メッセージを生成する、2重にロードされたモジュールの場合もあります。
先行するエラーメッセージ
別の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サーバーへのチャンク転送を最小限に抑えることです。
output_buffering=
設定は、それにもかかわらず、助けることができます。php.iniで、
または.htaccessを介して、または最新のFPM / FastCGIセットアップ
で.user.iniで構成します。
これを有効にすると、PHPは出力を即座にWebサーバーに渡すのではなく、バッファリングできます。したがって、PHPはHTTPヘッダーを集約できます。
同様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()
必要送信するSet-Cookie:
HTTPヘッダーを。したがって、同じ条件が適用され、同様のエラーメッセージが時期尚早の出力状況に対して生成されます。
(もちろん、それらはさらに、ブラウザーで無効にされたCookie、またはプロキシの問題によっても影響を受けます。セッション機能は、明らかに、空きディスク領域や他のphp.ini設定などにも依存します。)
さらなるリンク