404をチェックするにはHTTPリクエストが出来なくてはいけないと言うことで、まずはHTTPのHEADレスポンスを取得するスクリプトを書いてみます。
PEARを使っている人はHTTP::head
を使うこともできます。
サーバ内のファイルならapache_lookup_uri()
やapache_request_headers
、apache_response_headers()
がでHTTPヘッダレスポンスが簡単に取得できますが、リモートにあるファイルでは不可能です。そこで自前で実装することにしました。
PHPだと関数が結構そろっているので簡単に実装できました。User-AgentがH2CなのはHTTP Header Checkerの略です。URIのエスケープを行っていないのでチルダや半角スペースが入っているURIだとエラーを起こす可能性があります。また、http://www.arielworks.netのように最後のスラッシュが抜けている場合も補完は行われないので注意してください。
//-------------------------------------------------------------------------
// array get_http_header( string URI )
// URIがHTTPプロトコルだった場合、そのURIにHEADリクエストを行います。
// 返り値にはHTTP-Version、Status-Code、Reason-Phraseが必ず含まれ、それ以外
// にサーバが返した情報(index: value)が含まれます。
// Status-Codeが9xxの場合、それはホストが存在しない場合などHTTPリクエストが
// 正常に行われなかったことを意味します。
//-------------------------------------------------------------------------
function get_http_header( $target ) {
// URIから各情報を取得
$info = parse_url( $target );
$scheme = $info['scheme'];
$host = $info['host'];
$port = $info['port'];
$path = $info['path'];
// ポートが空の時はデフォルトの80にします。
if( ! $port ) {
$port = 80;
}
// リクエストフィールドを制作。
$msg_req = "HEAD " . $path . " HTTP/1.0\r\n";
$msg_req .= "Host: $host\r\n";
$msg_req .=
"User-Agent: H2C/1.0\r\n";
$msg_req .= "\r\n";
// スキームがHTTPの時のみ実行
if ( $scheme == 'http' ) {
$status = array();
// 指定ホストに接続。
if ( $handle = @fsockopen( $host, $port, $errno, $errstr, 1 ) ) {
fputs ( $handle, $msg_req );
if ( socket_set_timeout( $handle, 3 ) ) {
$line = 0;
while( ! feof( $handle) ) {
// 1行めはステータスライン
if( $line == 0 ) {
$temp_stat =
explode( ' ', fgets( $handle, 4096 ) );
$status['HTTP-Version'] =
array_shift( $temp_stat );
$status['Status-Code'] = array_shift( $temp_stat );
$status['Reason-Phrase'] =
implode( ' ', $temp_stat );
// 2行目以降はコロンで分割してそれぞれ代入
} else {
$temp_stat =
explode( ':', fgets( $handle, 4096 ) );
$name = array_shift( $temp_stat );
// 通常:の後に1文字半角スペースがあるので除去
$status[ $name ] =
substr( implode( ':', $temp_stat ), 1);
}
$line++;
}
} else {
$status['HTTP-Version'] = '---';
$status['Status-Code'] = '902';
$status['Reason-Phrase'] = "No Response";
}
fclose ( $handle );
} else {
$status['HTTP-Version'] = '---';
$status['Status-Code'] = '901';
$status['Reason-Phrase'] = "Unable To Connect";
}
} else {
$status['HTTP-Version'] = '---';
$status['Status-Code'] = '903';
$status['Reason-Phrase'] = "Not HTTP Request";
}
return $status;
}
$head = get_http_header( "http://foo.bar/hoge.html" )
とすれば$head['Status-Code']
で「200」や「404」等が返ってきます。900番台が返ってきたときはHTTP1.0の正式なレスポンスではなくて、ホストが見つからなかったり、プロトコルがHTTPでは無かった場合などのHTTPリクエスト以前のエラーです。
そのほかレスポンスに含まれる情報は$head['Server']
のように名前を指定すれば取得できます。