スタッフブログ
こんにちわ。 なおとです。
開発では、なにごともやってみて初めて分かるということがあるものです。 今回は、あるコンテンツに対して「HEADリクエストを送って存在確認をする」、というスクリプトを(PHPで)書いた時の話です。
マニュアルにはレスポンスが正常な場合(200 OK)の例が掲載されています。 これが、リダイレクトするコンテンツの場合には、少々様子が異なってきます。
結果を書いてしまうと、「get_headers()はリダイレクトを辿って複数のリクエストを行う」ということを知りました。 私は「HTTP HEADの結果に係わらず、1回だけリクエストして、その結果を返す」という動作を(勝手に)想像していたのですが、違いました。
動作を確認するために以下のような、リダイレクトを数回繰り返すサンプルを用意しました。(redirect.php)
<?php $req = $res = $_SERVER['REQUEST_URI']; if (preg_match('/[^\w\:\/\.]/i', $req)) { echo 'wrong request.'; } else { if (strpos($req, '.php') === (strlen($req) - 4)) { $res = $res . '/'; } if (!strpos($req, '1111')) { $res = $res . '1'; header('Location: ' . $res); } else { echo htmlspecialchars($req, ENT_QUOTES, 'UTF-8'); } }
これを、get_headers()を使って結果を見ます。(別のスクリプトです)
<?php var_dump(get_headers('http://localhost/redirect.php', 1));
その結果が以下になります。
※分かりやすくするために、一部を編集しました
array 0 => string 'HTTP/1.1 302 Found' (length=18) 1 => string 'HTTP/1.1 302 Found' (length=18) 2 => string 'HTTP/1.1 302 Found' (length=18) 3 => string 'HTTP/1.1 302 Found' (length=18) 4 => string 'HTTP/1.1 200 OK' (length=15) 'Date' => array 0 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29) 1 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29) 2 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29) 3 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29) 4 => string 'Tue, 13 Oct 2009 06:38:51 GMT' (length=29) 'Server' => array 0 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx) 1 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx) 2 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx) 3 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx) 4 => string 'Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.7 with Suhosin-Patch' (length=xxx) 'X-Powered-By' => array 0 => string 'PHP/5.2.4-2ubuntu5.7' (length=20) 1 => string 'PHP/5.2.4-2ubuntu5.7' (length=20) 2 => string 'PHP/5.2.4-2ubuntu5.7' (length=20) 3 => string 'PHP/5.2.4-2ubuntu5.7' (length=20) 4 => string 'PHP/5.2.4-2ubuntu5.7' (length=20) 'Location' => array 0 => string '/redirect.php/1' (length=15) 1 => string '/redirect.php/11' (length=16) 2 => string '/redirect.php/111' (length=17) 3 => string '/redirect.php/1111' (length=18) 'Content-Length' => array 0 => string '0' (length=1) 1 => string '0' (length=1) 2 => string '0' (length=1) 3 => string '0' (length=1) 4 => string '18' (length=2) 'Connection' => array 0 => string 'close' (length=5) 1 => string 'close' (length=5) 2 => string 'close' (length=5) 3 => string 'close' (length=5) 4 => string 'close' (length=5) 'Content-Type' => array 0 => string 'text/html' (length=9) 1 => string 'text/html' (length=9) 2 => string 'text/html' (length=9) 3 => string 'text/html' (length=9) 4 => string 'text/html' (length=9)
get_headers()の第2引数に「1」をセットしなかった場合は、もっと混沌とした結果になっていましたが、省略します。
それと今回は、自分自身にリダイレクトするスクリプトで実験しました。 異なるサーバ/スクリプトに跨ってリダイレクトを辿った場合は、レスポンス・ヘッダーの内容も異なると思われますので、もう少し複雑な結果になります。
これを受けて、「Locationの結果、行き着くコンテンツ」は次のように取得できることがわかります。 ただし、URLの解決(絶対URLに直す処理)は端折っています。 あと実際のコードでは、エラー処理など適宜しています。
<?php $url = 'http://localhost/redirect.php'; $headers = get_headers($url, 1); $location = $headers['Location']; if (is_array($location)) { $location = array_pop($location); } if ( (strpos('/', $location) === false) and (strpos('http', $location) === false) ) { $location = dirname($url) . '/' . $location; } echo "original: {$url} \n redirected: {$location} \n";
以上です。