web-dev-qa-db-ja.com

PHPの5分間のファイルキャッシュ

私は非常に簡単な質問があります:PHPでファイルをダウンロードする最良の方法は何ですか?ただし、ローカルバージョンが5分以上前にダウンロードされた場合のみですか?

私の実際のケースでは、リモートでホストされているcsvファイルからデータを取得したいと思います。

$file = file_get_contents($url);

ローカルコピーやキャッシュなし。これをキャッシュされたバージョンに変換する最も簡単な方法は何ですか?最終結果は変わりません($ fileは同じままです)が、それほど前にフェッチされていない場合(たとえば5分)、ローカルコピーを使用しますか?

27
hyperknot

ローカルキャッシュファイルを使用し、使用する前にファイルの存在と変更時刻を確認してください。たとえば、_$cache_file_がローカルキャッシュファイル名の場合:

_if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 60 * 5 ))) {
   // Cache file is less than five minutes old. 
   // Don't bother refreshing, just use the file as-is.
   $file = file_get_contents($cache_file);
} else {
   // Our cache is out-of-date, so load the data from our remote server,
   // and also save it over our cache for next time.
   $file = file_get_contents($url);
   file_put_contents($cache_file, $file, LOCK_EX);
}
_

(未テストですが、現在使用しているコードに基づいています。)

このコードのどちらの方法でも、$ fileは必要なデータになり、新しい場合はキャッシュを使用するか、そうでない場合はリモートサーバーからデータを取得してキャッシュを更新します。

編集:私は上記を書いて以来、ファイルロックについてもう少し理解しています。ここでファイルのロックを心配しているのであれば、 この答え を読む価値があるかもしれません。

ロックと同時アクセスが心配な場合は、file_put_contentsをtemporaryファイルにしてから rename() これは、アトミック操作である_$cache_file_を超えています。つまり、_$cache_file_は、古いコンテンツまたは完全に新しいコンテンツであり、途中で書き込まれることはありません。

65
Matt Gibson

phpFastCache を試してください。ファイルのキャッシュをサポートしており、キャッシュクラスをコーディングする必要はありません。共有ホスティングとVPSで使いやすい

次に例を示します。

<?php

// change files to memcached, wincache, xcache, apc, files, sqlite
$cache = phpFastCache("files");

$content = $cache->get($url);

if($content == null) {
     $content = file_get_contents($url);
     // 300 = 5 minutes 
     $cache->set($url, $content, 300);
}

// use ur $content here
echo $content;
7
Ken Le

これもウィンドウを渡すシンプルなバージョンですUser-Agent文字列をリモートホストに送信すると、適切なヘッダーがなければ問題の原因になりません。

<?php

function getCacheContent($cachefile, $remotepath, $cachetime = 120){

    // Generate the cache version if it doesn't exist or it's too old!
    if( ! file_exists($cachefile) OR (filemtime($cachefile) < (time() - $cachetime))) {

        $options = array(
            'method' => "GET",
            'header' => "Accept-language: en\r\n" .
            "User-Agent: Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)\r\n"
        );

        $context = stream_context_create(array('http' => $options));
        $contents = file_get_contents($remotepath, false, $context);

        file_put_contents($cachefile, $contents, LOCK_EX);
        return $contents;

    }

    return file_get_contents($cachefile);
}
1
Xeoncross

最初に、設計パターンをチェックすることをお勧めします: 遅延読み込み

実装は常にローカルキャッシュからファイルをロードするように変更する必要があります。ローカルキャッシュが存在しないか、ファイルの時間ジッターが5分を超える場合は、サーバーからファイルをフェッチします。

疑似コードは次のようなものです。

$time = filetime($local_cache)
if ($time == false || (now() - $time) > 300000)
     fetch_localcache($url)  #You have to do it yourself
$file = fopen($local_cache)
0
Theon Lin

任意のタイプのデータベースシステムを使用している場合は、このファイルをそこにキャッシュできます。キャッシュされた情報用のテーブルを作成し、少なくとも以下のフィールドを指定します。

  • 識別子。次に必要になったときにファイルを取得するために使用できるもの。おそらくファイル名のようなものです。
  • URLからファイルを最後にダウンロードしたときのタイムスタンプ。
  • ローカルファイルシステムに格納されているファイルへのパス、またはBLOBタイプのフィールドを使用して、ファイル自体の内容をデータベースに格納するだけです。個人的にパスを保存することをお勧めします。ファイルが非常に大きい場合は、データベースに保存したくありません。

これで、上記のスクリプトを次回実行するときに、まずデータベースで識別子を確認し、タイムスタンプを取得します。現在の時刻と保存されているタイムスタンプの差が5分を超える場合は、URLから取得してデータベースを更新します。それ以外の場合は、データベースからファイルをロードします。

データベースを設定していない場合は、ファイルを使用して同じことを行うことができます。1つのファイルまたはファイル内のフィールドには、最後にファイルをダウンロードしたときのタイムスタンプが含まれます。

0
user470714