2011-03-10 15 views
20

Mam bardzo proste pytanie: jaki jest najlepszy sposób na pobranie pliku w PHP, ale tylko wtedy, gdy lokalna wersja została pobrana ponad 5 minut temu?5-minutowa pamięć podręczna plików w PHP

W moim konkretnym przypadku chciałbym uzyskać dane z pliku csv hostowane zdalnie, za które obecnie używać

$file = file_get_contents($url); 

bez lokalnej kopii lub buforowania. Jaki jest najprostszy sposób przekonwertowania tej wersji na wersję buforowaną, w której wynik końcowy się nie zmienia (plik $ pozostaje taki sam), ale korzysta z kopii lokalnej, jeśli została pobrana nie tak dawno temu (powiedzmy 5 minut)?

Odpowiedz

49

użyć lokalnego pliku cache, i po prostu sprawdzić czas istnienia i modyfikacji pliku przed jego użyciem. Na przykład, jeśli $cache_file jest lokalna nazwa pliku cache:

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); 
} 

(. Nietestowane, ale opiera się na kodzie używam w tej chwili)

czy inaczej przez ten kod, $ plik kończy się jak dane Państwo Potrzebuję i będzie albo używać pamięci podręcznej, jeśli jest świeża, albo pobrać dane ze zdalnego serwera i odświeżyć pamięć podręczną, jeśli nie.

EDYCJA: Rozumiem trochę więcej na temat blokowania plików, ponieważ napisałem powyższe. Być może warto przeczytać artykuł this answer, jeśli niepokoi cię blokowanie pliku tutaj.

Jeżeli obawiasz się o blokowaniu i równoczesnego dostępu, powiedziałbym najczystszym rozwiązaniem byłoby file_put_contents do pliku tymczasowy, następnie rename() to ponad $cache_file, które powinny być operacja atomowa, czyli $cache_file będzie może być starą zawartością lub pełną nową treścią, nigdy w połowie napisaną.

+0

Dzięki za kod Matt! Jest super czysty, dobrze skomentowany i działa bez żadnych modyfikacji! – zsero

+0

@zsero Cool. Ale możesz tam sprawdzić błędy :) Możesz napotkać problemy, jeśli katalog cache nie jest zapisywalny przez użytkownika serwera WWW, na przykład ... –

+1

Tak, może to wymagać sprawdzenia błędów, ale jest to tak mały projekt, że nikt inny nie użyje ani nie wdroży tego kodu. A jeśli jest uszkodzona, druga część przechodzi w tryb bez cache zamiast hamowania. Miły. – zsero

-1

Możesz zapisać kopię pliku przy pierwszym uruchomieniu, a następnie sprawdzić za pomocą pliku czas znacznika czasu ostatniej modyfikacji pliku lokalnego po następnych trafieniach.

0

Jeśli używasz systemu bazodanowego dowolnego typu, możesz tam go przechowywać. Utwórz tabelę dla buforowanych informacji i podaj co najmniej następujące pola:

  • Identyfikator; coś, czego możesz użyć do pobrania pliku następnym razem, gdy go potrzebujesz. Prawdopodobnie coś w rodzaju nazwy pliku.
  • Znacznik czasu od ostatniego pobrania pliku z adresu URL.
  • Ścieżka do pliku, gdzie jest przechowywana w lokalnym systemie plików lub użyj pola typu BLOB, aby po prostu przechowywać zawartość samego pliku w bazie danych. Poleciłbym tylko osobistą przechowanie ścieżki. Jeśli plik był bardzo duży, zdecydowanie nie chciałbyś umieścić go w bazie danych.

Teraz, po uruchomieniu skryptu powyżej następnym razem, najpierw sprawdź w bazie danych identyfikator i wyciągnij znacznik czasu. Jeśli różnica między bieżącym czasem i przechowywanym znacznikiem czasu jest większa niż 5 minut, przeciągnij z adresu URL i zaktualizuj bazę danych. W przeciwnym razie załaduj plik z bazy danych.

Jeśli nie masz konfiguracji bazy danych, możesz zrobić to samo, używając tylko plików, w których jeden plik lub pole w pliku zawiera znacznik czasu od ostatniego pobrania pliku.

-2

Myślę, że chcesz trochę (psuedo code) logikę takiego:

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

use $file 
+2

nie rozumiem, jeśli koniec jeszcze wydaje samo ... – zsero

+0

@zsero .. Dodatkowa warstwa jest tam, ponieważ nie można przetestować datownik pliku, który nie istnieje. –

-1

Można by wypaczać go w pamięci podręcznej podobny sposób:

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; 
} 
+1

Podobnie jak w przypadku odpowiedzi Piotra M., nie wiem, dlaczego tak jest, a jeśli nie to samo? – zsero

0

Po pierwsze, możesz sprawdzić wzór: Lazy loading.

Implementacja powinna zmienić się, aby zawsze ładować plik z lokalnej pamięci podręcznej. Jeśli lokalna pamięć podręczna nie istnieje lub jitter ma więcej czasu niż 5 minut, pobierasz plik z serwera.

Pseudo kod jest jak następuje:

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

Spróbuj phpFastCache, to obsługuje plików buforowanie i nie trzeba kodować swoją klasę cache. łatwe w obsłudze i dzielonego hostingu VPS

Oto przykład:

<?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; 
+0

Czy można uruchomić test porównawczy, aby sprawdzić, czy cache doktryny jest szybszy, czy phpFastCache z buforowaniem plików? – user4271704

0

Oto prosta wersja, która przechodzi również Windows User-Agent ciąg do zdalnego hosta, aby nie wyglądać jak trouble-maker bez odpowiednich nagłówków.

<?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); 
} 
Powiązane problemy