第3回 HTTP_Header クラス - ヘッダフィールドを扱う - PEAR講座

PHP 中級 講座

くまっち先生のPEAR講座

Lecutures on PHP

第3回 HTTP_Header クラス - ヘッダフィールドを扱う (その1)

 このエントリーをはてなブックマークに追加

処理内容を決定するコード

くまっち先生前回の「リダイレクト(転送)処理」の紹介の際にも触れましたが、HTTP通信および実行される処理内容はすべてRFC (HTTPの場合はRFC2616) によって定められている仕様に基づいています。実行される処理は、その内容に割り当てられたコードを相手に送信することで決定されます。このコードのことをステータスコードといいます。ブラウザが転送処理を実行するのも、相手から転送処理用ステータスコードを受け取っているからです。

皆さんはブラウザでWebサイトを見ている際、ふと画面に「404 Not Found.」と表示されたことはありませんか?この404という数字がステータスコードであり、「指定されたURL (ページ) は有りませんよ。」ということを伝える意味を持っているのです。このようにステータスコードは3桁の数字からなりそれぞれ独立した意味を持つよう構成され、それらがRFCに規定されています。

ステータスコードの定数宣言

今回取り上げるHTTP_Headerでは、仕様として定められているこのステータスコードを簡単に送信することのできる機能を持っています。

ステータスコードは3桁のうちの先頭数字により以下のように分類されています。

* 1xx: 案内 - インフォメーション情報
* 2xx: 正常 - リクエスト内容に対しての正しい処理
* 3xx: 移転 - 更に操作および処理があることを通知
* 4xx: クライアントエラー
* 5xx: サーバーエラー

これらコードを送信するため、HTTP_Headerパッケージでは全てのステータスコードが準備され、リスト1のように定数として宣言されています。

それぞれ3桁のステータスコードと共に、コードが持つ意味を示す説明文を組み合わせた文字列を定義しています。

リスト1ステータスコードの定数宣言

/**#@+
 * Information Codes
 */
define('HTTP_HEADER_STATUS_100''100 Continue');
define('HTTP_HEADER_STATUS_101''101 Switching Protocols');
define('HTTP_HEADER_STATUS_102''102 Processing');
define('HTTP_HEADER_STATUS_INFORMATIONAL',1);
/**#@-*/

/**#+
 * Success Codes
 */
define('HTTP_HEADER_STATUS_200''200 OK');
define('HTTP_HEADER_STATUS_201''201 Created');
....

宣言している定数名が共通になってパターン化されている点を見てください。これは定数名に接頭辞 (プリフィックス、prefix) としてパッケージ名と同じ「HTTP_HEADER」という名称を付与することで、利用者や他パッケージの定数宣言と競合しないようにしています。これはPEAR「標準コーディング規約」の命名規約にもあげられているポイントですが、それに限らず皆さんが書くPHPのコード内でも汎用的な定数名はできる限り利用せず、リスト2のようにWebサイト名やプロジェクト名といった具体的な名称を接頭辞として加えた定数名を使用することで、思いがけない形で定数名が競合し動作に問題が生じることを予防できます。

リスト2定数宣言例

// このような汎用的な定数名では、他と競合する可能性があり大変危険
define('FROM_ADDRESS''from@example.com');

// 具体的な名称を接頭辞として付与することで競合の可能性を減少させる
define('MY_EXAMPLE_APPLICATION_FROM_ADDRESS''from@example.com');

ステータスコードの送信

実際にステータスコードを送信するには、リスト3に示すsendStatusCodeというメソッドを使用します。

リスト3sendStatusCodeメソッド

function sendStatusCode($code)
{
    if (
headers_sent()) {
        return 
false;
    }
    
    if (
$code == (int) $code && defined('HTTP_HEADER_STATUS_'$code)) {
        
$code constant('HTTP_HEADER_STATUS_'$code);
    }
    
    if (
strncasecmp(PHP_SAPI'cgi'3)) {
        
header('HTTP/'$this->_httpVersion .' '$code);
    } else {
        
header('Status: '$code);
    }
    return 
true;
}

まずはじめにheaders_sent関数を使用して、既にHTTPヘッダが出力されていないかどうかの確認を行っています。 これは前回のHTTPクラスの時にも同様のものがありました。通信内容を示す重要な情報であるHTTPヘッダは、その通信に適したものである必要があります。くまっち先生

先に何らかのHTTPヘッダが送信されていた際、場合によってはこれから送信するヘッダ内容と情報が重複し矛盾が生じる可能性があります。送信されたヘッダ情報を取り消すことはできませんので、headers_sent関数の戻り値を確認することでこういったトラブルが起きぬよう予防している処理になります。

続いて引数として受け取ったステータスコード (xxxとします) が「HTTP_HEADER_STATUS_xxx」という定数として存在しているかどうかを確認し、存在していればその定数の値に置き換える処理を行っています。 最後にheader関数を利用してステータスコードを送信する処理を行っていますが、条件によってHTTPヘッダの出力形式を切り替えるようにしているようです。

これは、本来ステータスコードをHTTPヘッダとして送信するには、

HTTP/1.x 200 OK

というようなフォーマットである必要があるためif構文の真評価側のコードが正しい形のように見えますが、ApacheやIISといったWebサーバ上で動作させている場合「Status: 200 OK」とヘッダ出力するだけで自動的にこの正しい形式を送信する処理を行ってくれます。真評価側はHTTPヘッダが自動的に送信されないCLI (Command Line Interface) 版 (*1) などで動作している場合に実行される処理になります。

以上より、このメソッドを利用すれば、利用者は「ステータスコードxxxを送信したい」という場合引数にxxxを与えるだけで、簡単に正しい形式でステータスコードを送信できることが分かります。

ちなみに、定数として準備されていないステータスコードをこのメソッドに与えたとしたらどうなるでしょう?定数値として存在しない3桁の数字が$code変数に与えられた場合、その$codeをそのままステータスコードとしてheader関数を実行してしまうことになります。

実はHTTPステータスコードはある程度の拡張が許されており、前述した先頭数字によるステータス分類の範囲であれば、RFCに示されていないステータスコードを扱うことが可能なのです。たとえば450ステータスコードはクライアントに関する何らかのエラーを意味することとする、といった具合にです。(そのエラーに対してサーバ、クライアントそれぞれ適切な振る舞いを準備する必要があります。)

----

*1)
http://www.php.net/manual/ja/features.commandline.php

  • 1
  • 2

  



Pick Up Q&A

Q
PHPのHTML埋め込み記述について
 このエントリーをはてなブックマークに追加 
A
$_POST["data"] == "男" ? $val = "checked" : $val = "" ; の意味は以下と同じです。 if($_POST["data"] == "男"){ $val = "checked; } e...

>>続きを読む

kende様のご指摘通り、三項演算子を使用する際には、コードの複雑度などを考慮する必要がありますね。書きやすさと共に可読性も追求したいところですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)