« あーあ・・・ |
サーバー構築からDVDまで
| 直リンク防止 バナー作成ツール版 »
動的なページを静的に見せる If-Modified-Since
土曜日, 9, 02, 2006
googleヘルプのウェブマスター向けのガイドラインには、次のような一文があります。
ウェブ サーバーが If-Modified-Since HTTP ヘッダーに対応していることを確認する。 この機能を使用すると、Google が前回サイトをクロールした後にコンテンツが変更されたかどうかをサーバーから Google に通知し、 帯域幅や負荷を軽減できます。
おそらくこれを理解できている人は、PHPプログラマーでもあまりいないと思います。
どちらかというとサーバー構築・運営の範囲だからです。
If-Modified-Since HTTP ヘッダー とは
If-Modified-Since HTTP ヘッダーは何かというと、なんてことはない単純にステータスコード「304 Not Modified」を返すことです。
この304ステータスコードは、日本語に言い換えれば「リクエストされたページは、前回アクセスした時から更新されていません。パソコンに保存されたキャッシュを表示してください」ということ。
なんでWebサーバーがアクセスしてきた人がいちいち前回アクセスした時間がわかるかっていうと、実はブラウザ(IEやFirefox)自体が該当ページにアクセスする時に、パソコンに保存されたキャッシュを調べて、もしキャッシュがあるようなら(以前アクセスしたことがあるページであれば)、そのときサーバーから受け取った「最終更新時刻」というのも保存していて、2回目以降アクセスする時は、
「前回アクセスした時は、○○時○×分××秒に更新されたって言っていましたが」
みたいなことをURLと同時に送っているからです。
それを受け取ったサーバーは、そのURLページの最終更新日と、ブラウザから送られてきた最終更新日比較して、もし前回アクセスしてきた時から更新されていないようだったら、ページの内容を送らず「304」ステータスコードを返して終了します。
これを受け取ったブラウザは、キャッシュを取り出してブラウザ上に表示されます。
パソコンを使っている人にとっては、いかにもサーバーから送られてきた情報が表示されているように見えますが、実際にはパソコンに保存してあるキャッシュを表示しています。
こうすることによってムダなトラフィックを防ぐことが出来るわけです。
たとえば、普通のページであればせいぜい数百バイトから数十キロバイト程度ですが、画像や動画にもなってくると数百キロバイトから数メガ単位になるわけです。
そうなると一度表示させた画像なんかは、毎回毎回そのつど画像をサーバーから送っていたら、回線がパンクしてしまう可能性もあるわけで、しかもキャッシュを表示させればあっという間に表示させることも出来るし、トラフィックも節約できるし、すぐに表示させることも出来るという一石二鳥の技術なわけです。
んで、googleのクローラーもこのIf-Modified-Sinceという技術を利用していて、クロールする時は1度クロールしたことがあるページであれば、前回受け取った最終更新日をブラウザと同じように送信してきます。
もし、レンタルサーバー等でクローラーのアクセスログを見ることが出来る環境にあるのならば、googleクローラーのアクセスログで「304」ステータスコードを返しているものが数多くあるはずです。
その理由が今言ったIf-modified-Sinceという技術を使用しているためです。
PHPでIf-Modified-Sinceを利用する
最終更新日というのは、あくまで静的なファイルだけしか該当しません。
動的なページというのは、アクセスするたびにページが作成されるため、最終更新日という概念自体が存在しません。
そのため動的なページにアクセスした場合には、「304」ステータスコードがかえってくることはまずありません。
それどころかレスポンスヘッダに「If-Modified-Since」自体が含まれません。
なので、いくらWEBサーバーの設定でPHPやCGIを「○○.html」でも動作するような設定にしても、レスポンスヘッダを見れば、動的なページなのか静的なページなのかは一発でばれてしまいます。
さて、今回は、PHPでこの「If-Modified-Since」を実現させてみようと。
基本的にPHPは、CGIやJSP等に比べて非常に軽い動作なものの、中にはいちいち複雑な計算をしなければならないようなPHPも多いでしょう。
その場合は、304ステータスコードを返してしまえばいいわけです。
まず、ブラウザが前回の最終更新日を送ってきたかを調べるには、以下のようにします。
$requestHeaders = apache_request_headers();
if ($requestHeaders["If-Modified-Since"]){
print "ブラウザが送ってきた最終更新日は、";
print $requestHeaders["If-Modified-Since"];
}else{
print "初めてのアクセスですね?";
}
ただし、これだけだとサーバー側で最終更新日を送ることがないので、いつまでも「初めてのアクセスですね?」が表示されてしまいます。
なので、以下のように改良します。
$requestHeaders = apache_request_headers();
if ($requestHeaders["If-Modified-Since"]){
print "ブラウザが送ってきた最終更新日は、";
print $requestHeaders["If-Modified-Since"];
}else{
header("Last-Modified: " .
GmDate("D, d M Y H:i:s") . " GMT");
print "初めてのアクセスですね?";
}
GmDate関数は、Date関数の出力結果をGMT時間に変更してから出力してくれます。
日本時間は、標準時間より9時間進んでいるため、具体的にはGmDate関数を使うと、日本時間より9時間前の時間を返します。
また、書式は、
Fri, 01 Sep 2006 14:42:36 GMT
のような感じです。
曜日, 日にち 月 年 時:分:秒 GMT
ですね。
初めてのアクセスであれば、この偽装した(?)最終更新時間を返してやります。
すると、次にアクセスしてきたブラウザは、この最終更新時間をURLと一緒に送ってくるので、
$requestHeaders = apache_request_headers();
if ($requestHeaders["If-Modified-Since"]){
処理;
}
がマッチするわけです。
apache_request_headers関数を使わず、直接
if ($_SERVER["If-Modified-Since"])
とやるとなぜかうまく取得できません。なので、ブラウザが送ってきた最終更新日を取得する場合は、「apache_request_headers関数」を使用します。
実際にはデータファイルの最終更新日と比較してから304ステータスコードを返すか、もしくはそのまま出力するか判断するわけですが、この場合以下のようになります。
※モジュール版PHPで「If-Modified-Since」に対応するを参考に作りました。よって、このページで紹介されている「parse_http_date( $string_date ) 」を使うとします。
ここでは、データファイルを「./aaaa.dat」とします。
このデータファイルが、ブラウザが送ってきた最終更新日以降更新されていなければ、304を返すようにします。
$dataFile = "./aaaa.dat";
// データファイルの最終更新時間を取得(GMT時間で)
$lastRenewTime = FileMTime($dataFile) - 60 * 60 * 9;
$requestHeaders = apache_request_headers();
$array = parse_http_date($requestHeaders["If-Modified-Since"]);
if ($array["timestamp"] >= $lastRenewTime){
// もし、データファイルの更新時間がブラウザが送ってきた最終更新日より小さかったら
header("HTTP/1.1 304 Not Modified");
exit();
}
// データファイルが更新されていたら処理
print "データファイルは、前回アクセスした時以降に更新されたようです。";
と、こんな感じ。
PHPやステータスコードを理解している人でも、こうしたスクリプトをずらずら駄文と共に並べても理解しにくいでしょう。
なのでおもしろい実験を。
上のリンクをクリックすると、「現在の時間は、00:11:51」というようなサーバーの時間が表示されるはずです。
んで、更新ボタンをクリックするか、別のページを表示させてもう一度今のページにアクセスしてください。
1回目にアクセスした時の時間のままのハズです。
今度は別のブラウザ(IEでアクセスしたのであれば、Firefox。FirefoxでアクセスしたのであればIE)でアクセスしてみてください。
1回目のアクセスは、別の時間になっていて、2回目以降は1回目のアクセスと同じ時間のハズです。
さぁ~て、今書いてきたことをどれくらいの人が理解できたかは私にはわかりませんが、アフィリエイトで大量ページをPHPで出力している人なんかにとっては、まさによだれものの機能になるはずだと理解できたでしょうか?
ただし!!!!
レスポンスヘッダをいじる場合は、誤った設定によっては全く検索サイトにインデックス化されない。といった危険もはらんでいます。
んで、今後悔したスクリプトは、適当に書きながら考えたスクリプトなので、実験していません。(汗
使用する際は、よ~~~~くテストしてから。
検索サイトに嫌われる、インデックス化されない。といった症状になったとしても責任を持ちませんので。
投稿者 campanella : 2006年09月02日 00:16 | SEO対策4 | 編集
![]()


□□□ コメント □□□