PHPのheader関数でHTTPステータスを複数実行せざるえない場合、常に上書きされてホッとした話

WordPressで通常の記事以外のURLで追加の動作をさせたいAPIっぽいものを作っている際、PHPのheader関数でHTTPステータスを複数出力する状況が生じたので試してみました。

具体的にはWordPressのループでは通常の記事が存在するかのチェックをし、記事が存在しない場合にまずheader関数でcode404(ファイルが存在しない)が出力されます。私の行いたい実装は、その後、特定のURLの場合にだけ、独自のPHPの動作に行うためにフローを抜き出してファイル存在code200する必要があるためです。

実際、FlashやJavascriptで、通常のWordPressのフローで404を返してしまった場合、頑張ってデータを作っても無視されて読まれないので、ぜひ回避したい。

まずHTTPステータスの書き方

まずHTTPステータスの書き方。

<?php

// ステータス 404 -> File Not Found
header("HTTP/1.1 404 Not Found");
// ステータス 200
header("HTTP/1.1 200 OK");

?>

こういったコードがよく引っかかりましたが、以下の方も使えるようなので試してみます。

<?php

// ステータス 404 -> File Not Found
header(" ",true,404);
// ステータス 200
header(" ",true,200);

?>

この用法は第一引数が空文字だとダメなので、そのあたりはご注意ください。 via. phpのHeader関数が変 – ブックマクロ開発に

まずファイル存在のcode200とNotFoundのcode400をそれぞれ書いてみる

では、通常のheader関数で1つだけ叩くケース。

HTTPステータス 200

→サンプル HTTPステータス 200

<?php

// ステータス 200
header(" ",true,200);
?>

<html>
<head>
<title>test</title>
</head>
<body>
TEST
</body>
</html>

ちゃんとTESTが表示されますね。

HTTPステータス 404

→サンプル HTTPステータス 404

<?php

// ステータス 404 -> File Not Found
header(" ",true,404);

?>

こちらもちゃんとFile Not Found(Chrome確認)になります。

ステータス 200の時に記述していたHTMLはブラウザによって表示されるケースがあるので割愛しています。謎だ・・・。

もちろんブラウザで表示されたとしても、FLASHではエラーが返ります。

続いて、複数発生するケース。

それではいよいよ上記の2つを組み合わせたケースをやってみます。

私がやりたい挙動は「通常の判定では404判定になっているフローから200にして抜け出す。」なのでそのように書いてみます。

→サンプル HTTPステータス 404の後に200

<?php

// ステータス 404 -> File Not Found
header(" ",true,404);
// ステータス 200
header(" ",true,200);

// 後発の200が優先される。

?>

<html>
<head>
<title>test</title>
</head>
<body>
TEST
</body>
</html>

これは最初に404が発生しているのにもかかわらず後発の200が優先されました。
いろいろなブラウザで見ても同様の挙動で、FirebugやChromeのデベロッパーツールでも200のステータスコードが検出されています。

そしてFLASHでも読めました。希望通りの挙動です!

PHPマニュアルにも保証されているようだ

さて、ちゃんと動いているとはいえ、なにか保証が欲しいものです。

PHPマニュアルを漁っていたところ、ちゃんと書いてありました。

PHPマニュアル
PHPマニュアル:header:生の HTTP ヘッダを送信する

注意:
実際に header() が最初にコールされたか どうかにかかわらず、HTTP ステータスヘッダ行は クライアントに対し常に最初に送信されます。 HTTP ヘッダが既に送信されていない限り、 header() をコールすることでステータスは 常に上書きされます。

なるほど、よかった。

おわりに

今回はFlashやJavascriptで読み込むケースで先に404が返るために以後データが無視されることを回避するのが目的なのでこの方法でOKではないでしょうか。

それでは良き WordPress Lifeを。