対象読者
はじめに
キャッシュの必須事項
スクリプト キャッシュ ソリューション
キャッシュ スクリプト
実装: よくある落とし穴の回避
概要
スクリプト
著者について
対象読者
この記事は、静的ファイルの作成に興味のある PHP プログラマーを対象としています。動的 PHP スクリプトの HTML キャッシュ。この記事は、PHP スクリプトを実行する Apache サーバーに特化して書かれていますが、ここで説明されているアイデアは、ほぼすべての Web 環境に適用できます。
この記事は、動的 Web サイトの作成にある程度の経験があり、HTTP に精通しており、少なくとも「404 Page Not Found」エラーの意味と環境変数 $REQUEST_URI および $DOCUMENT_ROOT の定義を理解していることを前提としています。
はじめに
動的 Web ページを使用する利点はよく知られていますが、それでも、速度と検索エンジンのアクセシビリティという 2 つの重大な欠点があります。
速度: ユーザーがリンクをクリックするか URL を入力した後にページを受信する速度は、ウェブサイトにとって重要な要素です。それは数十の変数に依存しますが、その中には制御できるものもあれば、制御できないものもあります。プロセスには無数のボトルネックがあり、それらをすべて解決することはおそらく不可能です。ここで取り組むこのボトルネックは、サーバー側スクリプトが HTML 出力を作成するのを待機することによって引き起こされるものです。
検索エンジンのアクセシビリティ: これは、検索エンジンが特定の Web ページを参照できる能力を意味します。ほとんどの検索エンジンは、「クローラー」プログラムを使用して機能します。クローラー プログラムは特定のページから開始し、そのページ上のリンクをナビゲートします。クローラーがアクセスするすべてのページは、検索エンジンのデータベースにインデックス付けされます。
ただし、ほとんどのクローラーは、動的ページではなく、静的 (HTML) ページをナビゲートするようにのみプログラムされています。たとえば、URL に「?」が含まれるページは、文字(クエリ文字列を示す)または「.php」で終わるファイル名にはアクセスできません。その結果、クローラーはこれらのページにインデックスを付けなくなり、新しい訪問者がサイトにアクセスしにくくなります。
注: クローラーは、HTML ファイルの出力と PHP ファイルの出力の違いを区別できません。どちらも同じコンテンツ タイプを送信します。したがって、ほとんどのクローラーは、ファイル名および/または URL にクエリ文字列があるかどうか、つまり URL に「?」が含まれているかどうかに応じて単純に判断します。
この記事では、これらの欠点の両方に対処する手順について説明します。記事のスクリプトはほとんどの状況で十分に使用できますが、特に小規模な Web サイトや個々のスクリプト ページでは、変更 (ダイナミクス) が中程度にしか行われません。
キャッシュの必須事項
簡単に言うと、キャッシュには、 1 つ以上の動的スクリプトを静的 HTML ファイルに変換します。サイトの訪問者は、元の動的バージョンではなく、これらの HTML ファイルに誘導されます。
そのためのメカニズムは、雑誌の Web サイトを例として説明できます。
雑誌の Web サイトには、多数の記事やストーリーを含むデータベースが存在する可能性があります。通常は、次のようなスクリプト (たとえば「show_article.php」) を作成します:
記事 ID 番号を受け取る
データベースから記事のコンテンツを読み取る
それをある種の HTML テンプレートに入れる
ナビゲーション リンクなどでページ全体をフォーマットする..
結果の HTML を訪問者のブラウザに送信します
そのため、サイトのホームページには、次のようにコード化された現在の記事へのリンクが含まれる場合があります:
記事をキャッシュ< ;/a>
さて、記事は静的になる傾向があり、サイトが高いリクエスト負荷の下で動作していることを望むでしょう (なぜなら人気があるからです!!)。そのため、各記事に対するリクエストには、データベースへのアクセス、記事の検索、表示など、広範囲にわたる処理が必要になります
さらに、レイアウト仕様などの他のデータベース情報に依存する場合、処理にさらに時間がかかります。最後に、記事ページへのリンクに「?」が含まれているため、検索エンジンのクローラーは記事のコンテンツのインデックスを作成することさえできません。
そのため、これらの問題を軽減するために、ウェブマスターは少なくとも何らかの形式のキャッシュ システムの実装を検討する必要があります。
スクリプトをキャッシュする必要がある場合
キャッシュしている間この記事で紹介するソリューションは多くのユーザーにとって有益ですが、スクリプトをまったくキャッシュしたくない場合や、別のキャッシュ方法を使用したい場合もあるでしょう。
株価、ディスカッション フォーラム、プロセス フォームなど、頻繁に変化するデータを処理する必要があるスクリプトは、この記事で説明するシステムには適していません。このような場合、決定はあなた次第です。動的のままにするか、Zend Cache の使用などのより高度なソリューションを選択することもできます。
注: サイトのキャッシュ ニーズに Zend Cache を使用すると、この記事で説明されているシステムはまったく必要ありません (ただし、PHP スキルを向上させるために読んだほうがよいかもしれません!)。 Zend Cache は、完全なターンキー キャッシュ ソリューションを提供します。複雑なサイトの場合は、それを購入することをお勧めします (これは Zend のサイトだからという理由だけでなく、アプリケーションの保守が容易で、サポートも充実しているためです。
一方、サイトに基本的なスクリプトがほとんどない場合は、おそらくキャッシュをまったく気にする必要はありません
それにもかかわらず、次の場合は、
(少なくとも比較的) 複雑なスクリプトをサイトに搭載し、多数のページ ヒットを処理できるようにしたいと考えています。 、
および/または
商用キャッシュ ソリューションのコストを支払う余裕がありません。
その場合は、このキャッシュ メカニズムが役立つことを願っています。
最新の情報を維持する必要がないページの場合は、このシステムの速度純粋な静的 HTML ページを作成するため、これに勝つことはできません。
スクリプト キャッシュ ソリューション
標準的なキャッシュ システム ソリューションは、前述の例から、キャッシュ記事へのリンクは次のようにコード化されます。
キャッシュ記事
id_123.html には、id=123 を使用して呼び出された show_article.php スクリプトによって生成された出力が含まれています。
キャッシュされたすべてのファイルを独自の単一ディレクトリ (上記の例では「/cache」ディレクトリ) の下に保存し、作成する動的スクリプト (つまり「show_article」など) ごとにサブディレクトリを付けて保存することをお勧めします。 /" ディレクトリ)。
このようにして、キャッシュされたファイルが動的スクリプトから分離されるため、サイトのメンテナンスが非常に管理しやすくなります。たとえば、特定のスクリプトによって生成された古いキャッシュ ファイルを削除するなどのアクションを簡単に実行できます。ただし、より重要なのは、cache.php の文字列置換メカニズムが簡素化されることです。詳細については、cache.php の詳細を参照してください。
動的ページへのリンクは、それぞれの HTML スクリプト (出力) を指すように切り替える必要があることに注意してください。
したがって、記事 #123 を次のようにしたい場合は、たとえば、リンクを「show_article.php?id=123」から「cache/show_article/id_123.html」に変更するだけです。
注: これらの新しいリンクを割り当てる前に HTML ファイルを定義する必要はありません。 。スクリプトは、サーバーによって呼び出されるまでキャッシュされません。
さらに、HTML ファイルは別の URL に存在するため、それらのファイル内の相対パス (例: "http://www.myserver.com/path/to/images/art.gif") は次のようにする必要があります。修正しました。したがって、「http://www.myserver.com/path/to/images/art.gif」または「/path/to/images/art.gif」などの絶対パスを使用することを検討してください。先頭の「/」に注意してください。 、現在のサーバーに相対的な意味です。
あるいは、 を追加することもできます。 HTML
タグを追加します。セクション。
注: パスをキャッシュ ディレクトリからの相対パス (「../../path/to/images/art.gif」など) に変更することはお勧めしません。これは、このキャッシュ システムの重要な点は、ユーザーの好みに応じてファイルがキャッシュされるかどうかが異なるためです。 HTML がキャッシュされたファイル (/cache/ ディレクトリーの下) から読み取られるか、動的スクリプト (他のディレクトリーにある) から読み取られるかに関係なく、リンクが機能するようにする必要があります。絶対 URL はこれを保証します。
キャッシュ スクリプト
キャッシュ システムの中心となるのは、キャッシュ スクリプト自体 (cache.php) です。 fopen() を使用して、ブラウザーのように動的スクリプトを読み取ります。出力を生成し、ユーザーに表示した後、この出力を静的 HTML ファイルに保存します。
cache.php 自体は、基本的な PHP のみを使用します。他のスクリプトから独立して機能することもできます。したがって、スクリプト キャッシュを実装するために既存のスクリプトを変更する必要はありません。
キャッシュ スクリプトのアクティブ化
cache.php をアクティブ化するための推奨方法は、「404 ページが見つかりません」イベントを使用してアクティブ化することで、その実行を自動化し、サイトへの影響を最小限に抑えることです。
「404 ページが見つかりません」エラーは、サーバーが要求したページを見つけることができなかったことを訪問者に通知します。ほとんどの場合、標準の「ページが見つかりません」ページが表示されます。ただし、ほとんどの Web サーバーではエラー ページをカスタマイズできるため、ファイルが見つからない場合は、デフォルトの「ページが見つかりません」ページを表示する代わりに、cache.php スクリプトを呼び出すことができます。
たとえば、Apache では、次のステートメントを追加することで、設定ファイル (httpd.conf および「apache/conf/」ディレクトリにあります) を編集できます:
ErrorDocument 404 /cache.php
このステートメントは、404 エラーを処理する責任をキャッシュ.php に割り当てます。脚本。ファイルが見つからない場合、Apache はデフォルトの「ページが見つかりません」ページの代わりにこのスクリプトを呼び出します。
警告: 元の設定ファイルを変更する前に、そのコピーが保存されていることを確認してください。設定ファイルを変更する前に、そのコピーを保存しておくことをお勧めします。意図せずファイルを破損してしまった場合でも、いつでも元のファイルに頼ることができます。
次に、変更を適用する前に、cache.php スクリプトをシステムに追加します。そうしないと、404 エラーでcache.php スクリプトが見つからず、別の 404 エラーなどが発生し、無限ループが発生します。 (実際には、Apache は 500 エラーを発行してこのケースを処理しますが、サーバー/バージョンが適切に処理しない可能性があります)
404 エラーを使用したキャッシュの主な利点は、自動的とオンデマンドの両方でキャッシュを実行できることです。最初に HTML スクリプトへのリンクを定義している場合に限ります。 「リンクされた」HTML ファイルが存在しないと 404 エラー メッセージが表示され、cache.php にファイルを定義するよう求められます。
ただし、このファイルへの最初の訪問者は、キャッシュ スクリプトを介して、より遅い動的ファイルをアクティブにします。 cache.php がトリガーされると、スクリプトは元の動的ファイルへのリンクを特定し、HTML 出力を生成します。その際、新しい HTML (静的) ファイルに保存する前に、この出力が訪問者に表示されます。
cache.php は最初の訪問者に対してのみ生成されます。 HTML 静的ファイルが作成されると、定義されたリンクが有効になり、後続のリクエストで 404 エラーが生成されなくなります。ただし、動的スクリプトのデータが変更された場合 (例: 誰かが記事を更新した場合)、キャッシュされた .html ファイルを削除するだけで、404 エラーが再び発生する可能性があります。
注: 前の例を続けると、HTML 出力が変更されるように show_article.php 自体を変更した場合、キャッシュを「クリーン」する必要があります。これは、「show_article/」の下にあるすべてのファイルを削除することを意味します。 "ディレクトリ。その結果、キャッシュは (最終的には) 新しい HTML で更新されます。
ヒント: 特定のファイルをキャッシュしたくない場合は、動的ファイルへの (元の) リンクをそのままにしておきます (つまり、そのファイルの HTML リンク)。
cache.php の詳細
キャッシュ スクリプト (cache.php) は $REQUEST_URI 経由で (存在しない) 静的ファイルの場所を受け取り、その目的は最終的にこの静的ファイルを生成することです。 ($REQUEST_URI は str_replace() コマンドを使用して解析されます)。
cache.php は、最初に str_replace() を使用して元の動的スクリプトの URL を決定します。結果の URL は、$maker_URL 変数に保存されます。
その後、スクリプトは動的スクリプトの URL を開いて、その出力を読み取ります。 PHP では fopen() 関数を使用してこれを行うことができるため、これは非常に簡単です。
注: fopen() はファイルだけでなく Web ページも開くことができます。サイトの URL (または、常にローカル マシンを指す予約済み IP アドレスである「127.0.0.1」) を入力すると、自分のサイトからページを読むことができます。
雑誌の例では、次のように使用します。
$read = fopen ( "http://www.newspapersite.com/show_article.php?id=123","r" );次に、
cache.php は、ファイルであるかのように、fread() を使用して動的スクリプト URL を読み取ります。スクリプトは HTML を読み取りながら、それをすべて変数に保存します。 (cache.php のように) 出力の読み取り中に画面に表示することも、読み取りが完了するまで表示を延期することもできます。
最後に、スクリプトはローカル ファイルを開き、新しく作成された HTML を保存します:
$write=fopen ("cache/show_article/id_123.html","r");
注意:cache.php は、動的スクリプトからの読み取りが完了するまで静的ファイルを保存しません。ファイル全体が一度に保存されるため、保存操作も迅速です。
実装: よくある落とし穴の回避
ここで提供されるキャッシュ スクリプトは、遭遇する可能性のあるいくつかの一般的なトラップを処理します。ここで説明するのは、スクリプトの動作をより深く理解し、独自のスクリプトを作成する場合にそのような落とし穴を回避できるようにするためです。
サイトの訪問者の動作が予測できない場合、スクリプトのアクションがトリガーされます。したがって、すべての HTML を生成した後でのみ静的ファイルを作成し、すべてを一度に保存してください。
そうすることで、最初の訪問者がページの一部だけを表示してから別のページに移動するという決定によって、不完全なファイルが作成されることを防ぎます。ファイルがキャッシュに保存されると、キャッシュ スクリプトは再度トリガーされないことに注意してください。そのため、実際の HTML の一部しか保存されていない場合でも、後続の訪問者にはキャッシュされたファイルが表示されます。 cache.php は、すべての HTML が 1 つの文字列で定義された後でのみファイルに書き込むことで、待ち時間を最小限に抑えます。 fwrite() コマンドが使用されます。
2 人の訪問者が同時に同じファイルをリクエストする可能性があります。ファイルがまだキャッシュされていない場合は、両方のスクリプトが同じキャッシュされたファイルを同時に作成しようとすることを意味する可能性があります。これはおそらく問題を引き起こすでしょう。それを避けるために、cache.php は静的ファイルを作成するときに flock() を使用します。このコマンドはファイルをロックし、別の flock() が発行されてファイルのロックが解除されるまで、別のスクリプトがそのファイルにアクセスできないようにします。
これまでクエリ文字列であったもの (例: "?id=123&x=1") が、ファイル名になりました。 。オペレーティング システムが異なれば、ファイルの命名規則も異なります。 cache.phpでは、「=」と「&」をそれぞれ「_」と「__」に変換することにしました。必要が生じた場合 (たとえば、スクリプトの一部はクエリ文字列に「_」を含む文字列を受け入れます)、スクリプトを変更して、最適な規則を反映できます。
本物の 404 イベントに備えてください。キャッシュ システムとは関係なく、実際には存在しない特定のファイルに対してリクエストが行われたため、404 が呼び出される場合があります。キャッシュ スクリプトは、要求されたファイルが見つかるかどうかを確認することでこれに対応します。これは、file_exists() 関数を使用して行われます。ファイルが見つからない場合、スクリプトは「$REQUEST_URI が見つかりません」というメッセージを表示し、実行を停止します。このメッセージを特定のニーズに合わせてカスタマイズしたり、ページが見つからないときに ($REQUEST_URI 値を使用して) Web マスターに自動電子メール メッセージを送信するなどの機能を追加して、後で修正できるようにすることもできます。
概要
速度は動的な Web サイトにおいて重要な要素です。この記事では、サイトの速度を上げる方法について説明しました。その効果は、サイトが動的スクリプトに依存しているかどうかによって異なります。スクリプトが重いほど、それを静的ページに変換することで速度が向上します。さらに、静的ページはクローラー プログラムによってインデックス付けされるため、新しい訪問者がサイトにアクセスしやすくなります。
ただし、動的 Web ページをキャッシュして高速化するためのさまざまなソリューションが多数あります。ここで説明するものは最も単純なものの 1 つですが、多くの場合に非常に役立ちます。動的ページではなく静的 HTML ページを作成することで機能するため、純粋なソフトウェア ソリューションを使用するのと同じくらい高速です。
スクリプトは、「404 ページが見つかりません」イベントによってトリガーされるように設定するのが最適です。したがって、アクションが自動化され、サイトへの影響が最小限に抑えられます。さらに、このスクリプトでは、最初に HTML 内で画像、JS ファイル、その他のファイルへのリンクを絶対パスとして定義する必要があります。キャッシュしたいファイルへのリンクは、(結果として得られる) 静的キャッシュ ファイルを直接指すように変更する必要があります (404 events/cache.php が自動的に作成するため、静的ファイルがまだ作成されていない場合でも)。キャッシュしたくないスクリプトもあります。これらには、フォームの処理、急速に変化するデータ (株価など) またはタイムクリティカルな情報の表示を処理するスクリプトが含まれます。このような状況では、動的スクリプトを指すリンクをそのままにしておきます。
サイトにいくつかの小さなスクリプトが含まれている場合は、キャッシュを気にする必要はまったくないかもしれません。一方、複雑なスクリプトや新しいデータに依存する場合は、Zend Cache などのより洗練されたソリューションを使用する必要があります。しかし、もしあなたがその中間にいるなら、この記事が役立つことを願っています。ご意見がございましたら、お気軽にメールでお問い合わせください。
スクリプト
cache.php
これは、キャッシュ スクリプトの簡易バージョンです。このバージョンは意図的にシンプルで、簡単に読めるように意図されています。実際には、例外をより適切に処理できます (より適切な「ページが見つかりません」ページ、ファイル操作の前に「@」を追加するなど)。また、作成スクリプトが「.php」で終わると想定する代わりに、ニーズに合わせて調整することもできます。 "、たとえば、".php3"、".pl"、またはその他のバリエーションに構成できます。
それでも、このスクリプトは機能するので、そのまま使用できます。
/ / キャッシュ スクリプトの例
// 静的 HTML ファイルの場所を取得します
$cache_file = $REQUEST_URI;
// 静的ファイルを作成する動的スクリプト
// の URL を調べます。
$maker_URL = str_replace ( "/cache/" , "/" , $cache_file );
$maker_URL = str_replace ( ".html" , "" , $maker_URL );
$last_slash = strrpos ( $maker_URL , "/" );
// 作成するスクリプトの名前
// を見つけて、それが存在することを確認します。
$script = substr ( $maker_URL , 0 , $last_slash ) 。 ".php";
$find = $DOCUMENT_ROOT 。 $script;
if ( !file_exists ( $find )) {
// ファイルが存在しない場合は、
// ファイルが見つからないエラーを表示します -
// echo ("$REQUEST_URI が見つかりませんでした");
// ここに素敵なページを置くことができます...
終了;
// ただし、終了することを忘れないでください!
}
// ここでクエリ文字列を解析します
// ここで、「_」は「=」を意味し、「__」は「&」を意味します
// これらのルールは単なる個人的な好みです
$query_str = "?" 。 substr ( $maker_URL , $last_slash+1 );
$query_str = str_replace ( "__" , "&" , $query_str );
$query_str = str_replace ( "_" , "=" , $query_str );
// そして完全な Maker_URL
$maker_URL = "http://" を作成します。 $HTTP_HOST 。 $script 。 $クエリ_文字列;
// Maker スクリプトを開いてその出力を読み取ります
$read = fopen ( $maker_URL , "r" );
if ( !$read ) {
echo ( "$maker_URL を開けませんでした" );
終了;
}
$HTML_output = "";
// HTML 出力を表示しながら読み取ります
while ($line = fgets ( $read , 256 )) {
$HTML_output.= $line;
エコー $line;
}
fclose ( $read );
// 最後に、HTML 出力
// をキャッシュ ファイルに保存します。
$write = fopen ( $DOCUMENT_ROOT . $cache_file , "w" );
if ( !$write ) {
// そのディレクトリに書き込む権限
// がない可能性があります。
echo ( "書き込みのために $writefile を開けませんでした" );
終了;
}
// 書き込みファイルをロックし、
// すべての HTML をそこに書き込みます
if ( !flock ( $write , LOCK_EX + LOCK_NB )) {
// PHP バージョンの場合 < 4.0.1
// LOCK_EX を 2 に変更
echo ( "$writefile をロックできませんでした" );
終了;
}
fwrite ( $write , $HTML_output , strlen ( $HTML_output ) );
flock ( $write , LOCK_UN );
// ロックを解除します。 PHP バージョンの場合 // LOCK_UN を 3 に変更します
fclose ( $write );
?>