2011-03-10 19 views
20

Tengo una pregunta muy simple: ¿cuál es la mejor manera de descargar un archivo en PHP pero solo si una versión local se ha descargado hace más de 5 minutos?caché de archivos de 5 minutos en PHP

En mi caso concreto me gustaría obtener datos de un archivo CSV alojado de forma remota, por lo que actualmente utilizo

$file = file_get_contents($url); 

sin ninguna copia local o el almacenamiento en caché. ¿Cuál es la forma más sencilla de convertir esto en una versión almacenada en caché, donde el resultado final no cambia ($ archivo permanece igual), pero utiliza una copia local si no se ha obtenido hace tanto tiempo (digamos 5 minutos)?

Respuesta

49

utiliza un archivo de caché local, y sólo comprobar la existencia y tiempo de modificación en el archivo antes de usarlo. Por ejemplo, si $cache_file es un nombre de archivo caché local:

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

(. No probado, pero basado en el código que utilizo en este momento)

cualquier manera a través de este código, archivo $ termina como los datos que Necesitará, y usará la memoria caché si está fresca, o tomará los datos del servidor remoto y actualizará la memoria caché si no es así.

EDIT: Entiendo un poco más sobre el bloqueo de archivos desde que escribí lo anterior. Puede valer la pena leer this answer si le preocupa el bloqueo de archivos aquí.

Si usted está preocupado por el bloqueo y el acceso concurrente, yo diría que la solución más limpia sería file_put_contents a un archivo temporal , a continuación, se rename() sobre $cache_file, que debería ser una operación atómica, es decir, la voluntad $cache_file ya sea el contenido antiguo o el contenido completamente nuevo, nunca escrito a medio camino.

+0

Gracias por el código Matt! ¡Es súper limpio, bien comentado y funciona sin modificaciones! – zsero

+0

@zsero Cool. Pero ponga un error al verificar allí :) Es posible que tenga problemas si el usuario del servidor web no puede escribir en el directorio de caché, por ejemplo ... –

+1

Sí, podría necesitar una comprobación de error, pero es un proyecto tan pequeño que hay nadie más usará o desplegará este código. Y si está roto, la parte else entra en modo caché, en lugar de frenar. Bonito. – zsero

-1

Puede guardar una copia de su archivo en el primer hit, luego verifique con filemtime la marca de tiempo de la última modificación del archivo local en los siguientes hits.

0

Si está utilizando un sistema de base de datos de cualquier tipo, puede almacenar en caché este archivo allí. Cree una tabla para información almacenada en caché y proporciónele como mínimo los siguientes campos:

  • Identificador; algo que puede usar para recuperar el archivo la próxima vez que lo necesite. Probablemente algo así como un nombre de archivo.
  • Una marca de tiempo de la última vez que descargó el archivo de la URL.
  • O bien una ruta de acceso al archivo, donde está almacenado en su sistema de archivos local, o utilice un campo de tipo BLOB para simplemente almacenar el contenido del archivo en la base de datos. Yo recomendaría simplemente almacenar el camino, personalmente. Si el archivo era muy grande, definitivamente no querría ponerlo en la base de datos.

Ahora, cuando ejecute el script la próxima vez, primero compruebe en la base de datos el identificador y extraiga la marca de tiempo. Si la diferencia entre la hora actual y la marca de tiempo almacenada es superior a 5 minutos, extraiga de la URL y actualice la base de datos. De lo contrario, cargue el archivo de la base de datos.

Si no tiene una configuración de base de datos, puede hacer lo mismo simplemente usando archivos, donde un archivo o campo en un archivo contendría la marca de tiempo de la última vez que descargó el archivo.

-2

Creo que quieres algo de lógica (pseudo código) como:

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

que no entiendo, si el extremo más parece la misma ... – zsero

+0

@zsero .. La capa adicional está ahí porque no se puede probar la marca de tiempo de un archivo que no existe. –

-1

Se podría deformar en un caché como método:

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

Al igual que con la respuesta de Peter M, no sé por qué es así y si no es el mismo? – zsero

0

En primer lugar, es posible que desee comprobar el patrón de diseño: Lazy loading.

La implementación debe cambiar para cargar siempre el archivo de la memoria caché local. Si la memoria caché local no existe o la fluctuación de tiempo del archivo es superior a 5 minutos, puede recuperar el archivo del servidor.

pseudo código es como siguiente:

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

Trate phpFastCache, es compatible con los archivos de almacenamiento en caché, y que no es necesario para codificar la clase de caché. fácil de usar en el alojamiento compartido y VPS

Aquí es ejemplo:

<?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

¿Podría ejecutar un punto de referencia para ver si doctrine-cache es más rápido o phpFastCache con el almacenamiento en caché de archivos? – user4271704

0

Aquí es una versión simple que también pasa una ventana User-Agent cadena en el host remoto para que no ves como un alborotador sin los encabezados adecuados.

<?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); 
} 
Cuestiones relacionadas