5-минутный файловый кеш в PHP - PullRequest
26 голосов
/ 10 марта 2011

У меня очень простой вопрос: как лучше всего загрузить файл на PHP, но только если локальная версия была загружена более 5 минут назад?

В моем случае я хотел бы получить данные из удаленного файла CSV, для которого я сейчас использую

$file = file_get_contents($url);

без какой-либо локальной копии или кэширования. Какой самый простой способ преобразовать это в кэшированную версию, где конечный результат не изменяется ($ file остается прежним), но использует локальную копию, если она была получена не так давно (скажем, 5 минут)?

Ответы [ 8 ]

63 голосов
/ 10 марта 2011

Используйте файл локального кэша и просто проверьте наличие и время изменения файла, прежде чем использовать его. Например, если $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 для временного файла, тогда rename() над $cache_file, которая должна быть атомарной операцией, т.е. $cache_file будет либо старым содержимым, либо полным новым содержимым, никогда не написанным наполовину.

7 голосов
/ 07 августа 2013

Попробуйте 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;
1 голос
/ 14 марта 2014

Вот простая версия, которая также передает строку windows 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);
}
0 голосов
/ 10 марта 2011

Во-первых, вы можете проверить шаблон проектирования: Ленивая загрузка .

Реализация должна измениться, чтобы всегда загружать файл из локального кэша. Если локальный кэш не существует или время дрожания файла превышает 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 голосов
/ 10 марта 2011

Вы бы превратили его в метод, подобный кешу:

function getFile($name) {
    // code stolen from @Peter M
    if ($file exists) {
      if ($file time stamp older than 5 minutes) {
         $file = file_get_contents($url)
      }
    } else {
         $file = file_get_contents($url)
    }
    return $file;
}
0 голосов
/ 10 марта 2011

Я думаю, вы хотите некоторую (псевдо-код) логику, такую ​​как:

if ($file exists) {
  if ($file time stamp older than 5 minutes) {
     $file = file_get_contents($url)
  }
} else {
     $file = file_get_contents($url)
}

use $file
0 голосов
/ 10 марта 2011

Если вы используете систему баз данных любого типа, вы можете кэшировать этот файл там.Создайте таблицу для кэшированной информации и предоставьте как минимум следующие поля:

  • Идентификатор;то, что вы можете использовать, чтобы получить файл в следующий раз, когда вам это нужно.Вероятно, что-то вроде имени файла.
  • Метка времени с момента последней загрузки файла с URL-адреса.
  • Либо путь к файлу, где он хранится в локальной файловой системе, либоиспользуйте поле типа BLOB, чтобы просто сохранить содержимое самого файла в базе данных.Я бы порекомендовал просто хранить путь, лично.Если файл очень большой, вы определенно не захотите помещать его в базу данных.

Теперь, когда вы в следующий раз запустите скрипт, сначала проверьте в базе данных идентификатор, ипотяните отметку времени.Если разница между текущим временем и сохраненной отметкой времени превышает 5 минут, извлеките URL-адрес и обновите базу данных.В противном случае загрузите файл из базы данных.

Если у вас нет настройки базы данных, вы можете сделать то же самое, просто используя файлы, где один файл или поле в файле будет содержать метку времени изкогда вы последний раз скачивали файл.

0 голосов
/ 10 марта 2011

Вы можете сохранить копию вашего файла при первом обращении, а затем с помощью filemtime проверить время последнего изменения локального файла при следующих попаданиях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...