[解決済み] PHPで「Header already sent」エラーを修正する方法
質問
スクリプトを実行すると、このようにいくつかのエラーが発生します。
警告 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ヘッダを変更する機能には、以下のようなものがあります。
出力することができます。
-
意図的でない
-
前の空白
<?php
または?>
- は UTF-8 バイトオーダーマーク 具体的には
- 過去のエラーメッセージやお知らせ
-
前の空白
-
意図的である。
-
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
. そこで、早すぎる出力を探す必要があったんですね。
代表的な原因
-
印刷、エコー
からの意図的な出力
print
とecho
ステートメントを使用すると、HTTP ヘッダを送信する機会が終了してしまいます。それを避けるためには、アプリケーションフローを再構築する必要があります。使用方法 機能 とテンプレート化するスキームがあります。確実なheader()
の呼び出しが発生します。 前 メッセージ が書き出されます。出力を行う関数は以下の通りです。
-
print
,echo
,printf
,vprintf
-
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
-
readfile
,passthru
,flush
,imagepng
,imagejpeg
などとユーザー定義関数があります。 -
-
生のHTML領域
解析されていないHTMLセクションを
.php
ファイルも同様に直接出力されます。 をトリガーとするスクリプト条件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は実際に シングル のように、closeタグの後に改行します。しかし、それは は、複数の改行やタブ、スペースがそのような隙間に移動することを補償しています。
-
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
インクルードディレクトリやプロジェクトディレクトリ全体で使っても安全です。
-
の後に空白を入れる。
?>
の後ろとしてエラーソースが記載されている場合、そのエラーソースは クロージング
?>
であれば、ここで空白や生テキストが書き出されたことになります。 PHP のエンドマーカーは、この時点ではスクリプトの実行を終了させません。これ以降のテキストや空白文字は、ページの内容として書き出されます。 のままです。特に初心者の方には、一般的に、末尾の
?>
PHP の閉じタグは省略します。これは を省く。 は、このようなケースのごく一部です。 (ごく一般的にinclude()d
スクリプトが原因です)。 -
エラーソースに "Unknown on line 0" と記載されています。
エラーソースがない場合、通常はPHPの拡張モジュールかphp.iniの設定になります。 が具体化されている。
-
これは、時折
gzip
ストリームエンコードの設定 またはob_gzhandler
. -
しかし、それはまた、任意の二重にロードされる可能性があります
extension=
モジュール は、暗黙のうちに PHP の起動/警告メッセージを発生させます。
-
これは、時折
-
先行するエラーメッセージ
他の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 出力バッファリング は、この問題を軽減するための回避策です。多くの場合、この回避策は確実に機能しますが アプリケーションを適切に構造化し、出力と制御を分離する代わりに ロジックを使用します。実際の目的は、ウェブサーバーへのチャンク転送を最小化することです。
-
は
output_buffering=
の設定は、それにもかかわらず、役に立ちます。 この設定は php.ini または .htaccess あるいは .user.ini で 最近の FPM/FastCGI のセットアップ。
これを有効にすると、PHP は出力をウェブサーバーに即座に渡すのではなく、バッファリングすることができます。このため、PHP は HTTP ヘッダを集約することができます。 -
同様に
ob_start();
を呼び出すスクリプトの上に置く。しかし、これは複数の理由から信頼性に欠ける。-
たとえ
<?php ob_start(); ?>
は最初のスクリプトを開始しますが、空白または BOMは前にシャッフルされるかもしれません。 をレンダリングしても効果がない . -
HTML出力のための空白を隠すことができます。しかし、アプリケーションロジックがバイナリコンテンツ(例えば生成された画像)を送信しようとするとすぐに、空白を隠すことができます。 バッファリングされた余計な出力が問題になります。(必要なのは
ob_clean()
を追加して回避しています)。 -
バッファのサイズには制限があり、デフォルトのままでは簡単にオーバーランしてしまいます。 それも稀なことではありません。 追跡困難 が発生した場合。
-
そのため、どちらのアプローチも信頼性に欠ける可能性があります(特に、切り替えの際に)。 開発用セットアップと本番用サーバーの両方が必要です。このため、出力バッファリングは は、松葉づえや回避策に過ぎないと広く考えられています。
以下もご参照ください。 基本的な使用例 を参照してください。
- 出力バッファリングとは何ですか?
- なぜ PHP で出力バッファリングを使用するのですか?
- 出力バッファリングの使用はバッドプラクティスと考えられていますか?
- ヘッダがすでに送信されている場合の正しい解決策として、出力バッファリングの使用例。
でも、他のサーバーでは動いたのに!?
以前、ヘッダーの警告が出なかった場合は 出力バッファリング 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の設定など)
リンク集
- Googleが提供する 類似の議論の長大なリスト .
- そしてもちろん 多くの具体例 は、Stack Overflowでも取り上げられています。
- WordPressのFAQに説明があります。 Headers already sent warning の問題を解決するにはどうすればよいですか? を一般的な方法で説明します。
- アドビコミュニティ PHP開発:リダイレクトがうまくいかない理由(ヘッダーはすでに送信済み)
- NucleusのFAQです。 page headers already sent"とは何ですか?
- より丁寧な説明のひとつに HTTP ヘッダーと PHP header() 関数 - NicholasSolutions によるチュートリアル (インターネットアーカイブのリンク)。 HTTPを詳しく説明し、スクリプトを書き換える際のガイドラインをいくつか提示しています。
関連
-
[解決済み】Notice: 非オブジェクトのプロパティを取得しようとしているエラー
-
[解決済み】XAMPPポート80をPID 4の「Unable to open process」が使用中 [重複] XAMPPポート80をPID 4の「Unable to open process」が使用中。]
-
[解決済み】SQLSTATE[42000]: 構文エラーまたはアクセス違反が発生しました。1064 SQL 構文にエラーがあります - PHP - PDO [重複]。
-
[解決済み】DateTimeクラスのオブジェクトを文字列に変換できない
-
[解決済み】未定義の関数mysql_query()をLoginで呼び出す【重複
-
[解決済み] PHP - ストリームを開くのに失敗しました : そのようなファイルまたはディレクトリがありません。
-
[解決済み】mysqli::query(): mysqli をフェッチできない
-
[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
-
[解決済み] PHPでHTML/XMLをパースして処理する方法とは?
-
[解決済み】PHPの'foreach'は実際どのように動作するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】move_uploaded_fileは、「failed to open stream: Permission denied" というエラーが出る
-
[解決済み] PHP & MySQL: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given [重複] PHP & MySQL: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given.
-
[解決済み】PHPで空の値からデフォルトオブジェクトを作成する?
-
[解決済み】新しいPHPMailerはPHPMailerAutoload.phpが必要?
-
[解決済み] PHP - ストリームを開くのに失敗しました : そのようなファイルまたはディレクトリがありません。
-
MacでPHPを実行した際に、メモリサイズが134217728バイトも消費される問題の解決方法について
-
[解決済み】書き込みコンテキストでメソッドの戻り値を使用することができない
-
[解決済み] Uncaught Error: 未定義の関数 mysql_escape_string() の呼び出し。
-
[解決済み】MySQLのカラム数が1行目の値数と一致しない【非公開
-
[解決済み] PHPのヘッダーリダイレクトが機能しない [重複]。