前書き
PHPにおけるheader()関数は、HTTPヘッダを操作するための強力なツールです。
この記事では、header()関数の基本的な使い方とその重要性を紹介します。
header()関数の基本
PHPのheader()関数は、生のHTTPヘッダを送信します。
この関数を使用すると、ブラウザに対して特定の命令を送信することができます。
基本的な使い方
|
|
このコードは、コンテンツタイプを「text/plain」に設定します。
例:HTTPヘッダの操作
リダイレクト
|
|
このコードは、ブラウザをhttps://example.comにリダイレクトします。
コンテンツタイプの設定
|
|
このコードは、コンテンツタイプを「application/json」に設定します。
これは、JSONデータを出力するAPIを作成する際に便利です。
header()の注意点
header()関数は、どんな出力も送信される前に呼び出す必要があります。
出力後にheader()を呼び出すと、警告が発生します。
セキュリティと互換性を確保するために、適切なHTTPヘッダを設定することが重要です。
出力後にheader関数を呼び出した際の警告
もし何らかの出力(例えば、echoやHTMLタグ、空白や改行など)が既に行われた後にheader()関数を呼び出すと、PHPは「headers already sent(ヘッダーは既に送信された)」という警告を発生させます。
「headers already sent」警告
|
|
この警告メッセージには、次の情報が含まれます:
- 警告の種類:Cannot modify header information(ヘッダー情報を変更できない)
- 警告の理由:headers already sent(ヘッダーは既に送信された)
- 出力の開始場所:出力が開始されたファイルと行番号
- 警告発生場所:header()関数が呼び出されたファイルと行番号
警告の発生原因
- 早期の出力:PHPファイルの先頭にある余分な空白や改行、echoやprintなどの出力関数の使用。
- BOM(Byte Order Mark)の存在:UTF-8のBOMがファイルの先頭に含まれている場合。
解決策
- 出力の遅延:header()関数を呼び出す前に、すべての出力を避けます。
- 出力バッファリングの使用:ob_start()で出力バッファリングを開始し、header()関数の後でob_end_flush()やob_get_clean()を使用してバッファをフラッシュまたは取得します。
- ファイルの確認:ファイルの先頭に余分な空白や改行がないことを確認し、BOMがないことを確認します。
出力バッファリングの使用例
こちらは少し複雑なので、実際のコード例を用いて解説します。
1. 出力バッファリングの有効化
出力バッファリングを有効にするには、スクリプトの最初にob_start()関数を呼び出します。
これにより、出力バッファリングが開始されます。
|
|
2. ヘッダの送信
バッファリングが有効な状態で、どのタイミングでも安全にヘッダを送信できます。
|
|
header
関数の前にテキストを出力していますが、ob_start
関数でバッファリングしているため、まだブラウザに送信されていません。
そのため、echo
の後にheader
関数を使用してもheaders already sent
の警告は出ません。
3. バッファのフラッシュ
最後に、出力バッファリングを終了し、バッファに溜まった内容をクライアント(ブラウザ)に送信するためにob_end_flush()
を呼び出します。
または、バッファの内容を取得してからクリアするためにob_get_clean()
を使用することもできます。
|
|
ここでob_end_flush
関数を呼び出した時、またはob_get_clean
関数で$content
変数に先ほどの文字列が代入されecho
でブラウザに送信される流れになります。
実際に試してみよう
ここからはdocker composeを使用してheader
関数の実際の動作を確認してみましょう。
1. プロジェクトのディレクトリを作成
ターミナルで以下のコマンドを実行して、新しいディレクトリを作成します。
|
|
2. docker-compose.yml の作成
docker-compose.yml
を作成し、以下の内容を記述します。
|
|
3. Nginx の設定ファイルを作成
nginx
ディレクトリを作成し、default.conf
を作成します。
|
|
|
|
4. PHP のフォームを作成
html
ディレクトリを作成し、headerを出力する PHP ファイルを作成します。
|
|
|
|
5. フォルダ構成の確認
ここまでで下記のフォルダ構成になっていればOKです。
|
|
6. Docker Compose を起動
php-header-test
フォルダで以下のコマンドを実行して、コンテナを起動します。
|
|
7. ヘッダーの出力を確認してみる
ブラウザで http://localhost:8080
にアクセスすると、「ヘッダーを出力しました」と表示されます。
しかし、実際にヘッダーが正しく出力されているかどうかを確認してみましょう。
7-1. 開発者ツールでヘッダーを確認
ブラウザの開発者ツールを使用して Content-Type
のヘッダーを確認できます。以下の手順で確認してください。
- ブラウザで F12 キーを押して「開発者ツール」を表示し「Network」タブを選択する。
- 下記のように初回は何も情報が表示されないため、指示通りCtrl+Rを押下するかF5キーを押下しページを更新する。
- 「Network」タブの「Doc」タブをクリックする。
- 左側のペインで「localhost」を選択する。
- 右側に詳細ペインが表示されるので、「Headers」タブをクリックする。
📷 開発者ツールの Headers
タブのスクリーンショット
7-2. Content-Type
ヘッダーの確認
「Headers」タブ内の「Response Headers」に Content-Type:
という項目が text/plain;charset=UTF-8
となっていればちゃんと設定されています。
また、PHP によって charset=UTF-8
が追加されていることが分かります。
📷 Content-Type
の表示例
7-3. charset=UTF-8
が自動で追加される理由
charset=UTF-8
を明示的に設定していないのに勝手に追加されているのは、PHP の default_charset
設定が UTF-8
になっているため です。PHP は Content-Type
を設定する際に、default_charset
に基づいて charset=UTF-8
を自動で付加します。
7-4. charset=UTF-8
を削除するとどうなるか?
試しに charset
を明示的に削除すると、ブラウザの表示が文字化けすることが確認できます。
以下のコードを実行してください。
|
|
📷 実行結果(文字化けの例)
7-5. 文字化けの原因
なぜ文字化けするのか?
それは、PHP から出力される文字コード と ブラウザが表示時に解釈する文字コード が一致していないためです。
7-6. PHPの出力文字コードの確認
現在の PHP の出力文字コードを確認するには、以下のコードを実行します。
|
|
|
|
通常は UTF-8
ですが、ini_set('default_charset', '')
を適用すると空になります。
7-7. ブラウザの文字コードの確認
Chromeブラウザではどの文字コードでページを表示しているかは、「テキストエンコーディング」から分かります。
※Edgeではどこで確認できるか分からずでした…
ページ内の適当な場所で右クリックを押下し「テキストエンコーディング」を選択します。
charsetを指定しないと「自動判別」になるようです。
今はもうほとんどの場合でUTF-8一択になっているため、文字コードで問題になることはないかと思いますが、上記のような仕様になっているんだなぁと知っておくと役に立つ時が来るかもしれません。
8. Locationでリダイレクトを発生させてみる
次に、Location
ヘッダーを使用してリダイレクトを発生させてみましょう。
8-1. PHPファイルの作成
html
フォルダに以下の3つのPHPファイルを作成してください。
|
|
|
|
|
|
8-2. リダイレクトの確認
3つのPHPファイルを作成したら、http://localhost:8080/redirect-index.php
にアクセスします。
表示された「リダイレクトしてみる?」のリンクをクリックすると、redirect-destination.php
に遷移することが確認できるはずです。
また、開発者ツールの「Network」タブで確認すると、リダイレクトのステータスコードが 302 Found
(一時的なリダイレクト)となっていることが分かります。
📷 リダイレクトされていることを確認
8-3. リダイレクトのステータスコードを変更する
リダイレクトのステータスコードにはいくつか種類があります。
デフォルトでは 302
ですが、これは header
関数の第3引数を指定するか、http_response_code
関数を使うことで変更できます。
試しに、301 Moved Permanently
(恒久的なリダイレクト)に変更してみましょう。
|
|
再度「Network」タブで確認すると、リダイレクトのステータスコードが 301 Moved Permanently
になっていることが分かります。
📷 恒久的なリダイレクトになっていることを確認
8-4. 301リダイレクトのキャッシュの影響
では、もう一度 301
リダイレクトを試してみましょう。
すると、ステータスコードが 200
となり、リダイレクトされていない ことが確認できます。
これは、301リダイレクトがブラウザにキャッシュされるため、2回目以降はリダイレクトせずに、直接 redirect-destination.php
に遷移するためです。
📷 2回目はリダイレクトされていないことを確認
8-5. キャッシュを無効化する方法
テスト時にこのキャッシュが影響すると不便なため、キャッシュを無効化する方法 があります。
開発者ツールの「Network」タブにある 「Disable cache」 を有効にすると、キャッシュが適用されなくなります。
📷 「Disable cache」の設定
「Disable cache」にチェックを入れてから再度リダイレクトを試すと、301
リダイレクトが適用されることが確認できます。
📷 Disable cacheにチェックを入れるとリダイレクトされる
テストする際に結構ハマるポイントなのでキャッシュには注意するようにしてください。
9. jsonデータを出力してみる
ヘッダーのContent Type
をapplication/json
にしてjsonデータを生成し、HTML側から取得する手順を解説します。
PHP側では配列をjson形式に変換して出力し、HTML側ではfetch
APIを使ってそのデータを取得・表示します。
9-1. PHPファイルでjsonデータを作成する
まずは、PHPファイルを作成して、jsonデータを出力する方法を見ていきましょう。
作成ファイル: json-data-api.php
以下のコードでは、PHPの連想配列を用いてユーザー情報を定義し、json_encode
関数でjson形式に変換しています。
また、Content-Type
ヘッダーを application/json
に設定することで、レスポンスがjsonデータであることを明示しています。
|
|
解説
- json_encode関数: PHPの連想配列
$data
をjson形式に変換します。JSON_UNESCAPED_UNICODE
オプションを使用することで、日本語などのマルチバイト文字をエスケープせずに出力できます。
9-2. HTMLファイルからjsonデータを取得する
次に、作成したPHPファイルからjsonデータを取得するためのHTMLファイルを作成します。
このHTMLファイルでは、JavaScriptの fetch
API を利用して、PHPのjsonデータを取得し、画面上に整形して表示します。
作成ファイル: get-data.html
|
|
解説
- fetch関数: 指定したURL(この場合は
json-data-api.php
)に対してHTTPリクエストを送信します。 - response.ok: レスポンスが正常に受け取れたかどうかをチェックしています。
- response.json(): レスポンスをjson形式に変換して返します。
- JSON.stringify(data, null, 2): 取得したjsonデータを整形して見やすく表示しています。
9-3. 動作確認
http://localhost:8080/get-data.html
にアクセスすると、json-data-api.php
に対してHTTPリクエストを送信し、json
データが表示されます。
レスポンスヘッダーにContent-Type: application/json; charset=UTF-8
が設定されていることも確認できました。
10. 「headers already sent」警告を発生させてみる
この章では、実際に「headers already sent」警告を発生させて理解を深めます。
警告の原因や回避方法を確認していきましょう。
10-1. 「headers already sent」警告とは
改めておさらいですが、「headers already sent」警告は、HTTPヘッダーを送信する前に、既に何らかの出力が行われた場合に発生します。
ヘッダーはレスポンスの先頭に送信されるため、一度出力が開始されると後からヘッダーを変更することはできません。
10-2. 警告を発生させるファイルの作成
まず、html
フォルダ内に headers-already-sent-warning.php
を作成します。
以下のコードをファイルに貼り付け、意図的にヘッダー送信前に出力を行うことで、警告を発生させます。
|
|
10-3. 警告の確認と影響
ブラウザで http://localhost:8080/headers-already-sent-warning.php
にアクセスすると、
「headers already sent」警告が表示されます。また、Content-Type
が text/plain
に設定されていないことも確認できます。
なお、この警告はエラーではないため、処理は中断されず、後続の出力も実行されます。
10-4. 出力バッファリングによる警告の回避
出力バッファリングを利用すると、出力が一時的にバッファに蓄えられるため、ヘッダー送信前に出力が行われても、バッファがフラッシュされるタイミングでまとめて出力されます。
これにより、ヘッダーが正しく設定され、警告を回避することができます。
html
フォルダに headers-already-sent-no-warning.php
ファイルを作成し下記コードを貼り付けます。
|
|
10-5. バッファリング適用後の動作確認
ブラウザで http://localhost:8080/headers-already-sent-no-warning.php
にアクセスすると、
警告が発生せず、Content-Type
も正しく text/plain
に設定されていることが確認できます。
このように、出力バッファリングを活用することで、ヘッダー送信前の不要な出力を防ぎ、警告を回避できます。
また、警告は致命的なエラーではないため、処理自体は中断されずに継続されることも覚えておきましょう。
まとめ
PHPのheader()関数は、HTTPヘッダを操作し、ブラウザの振る舞いを制御するために不可欠です。
この記事で紹介した基本的な使い方と例を参考にして、あなたのPHPプログラミングに柔軟性と機能性を加えましょう。