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を。