web-dev-qa-db-fra.com

Cache de fichiers de 5 minutes dans PHP

J'ai une question très simple: quelle est la meilleure façon de télécharger un fichier en PHP mais seulement si une version locale a été téléchargée il y a plus de 5 minutes?

Dans mon cas, je voudrais obtenir des données d'un fichier csv hébergé à distance, pour lequel j'utilise actuellement

$file = file_get_contents($url);

sans aucune copie ou mise en cache locale. Quelle est la manière la plus simple de convertir ceci en une version mise en cache, où le résultat final ne change pas ($ file reste le même), mais il utilise une copie locale si elle a été récupérée il n'y a pas si longtemps (disons 5 minutes)?

27
hyperknot

Utilisez un fichier de cache local et vérifiez simplement l'existence et l'heure de modification sur le fichier avant de l'utiliser. Par exemple, si $cache_file Est un nom de fichier de cache 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);
}

(Non testé, mais basé sur le code que j'utilise actuellement.)

Quoi qu'il en soit dans ce code, $ file se retrouve comme les données dont vous avez besoin, et il utilisera le cache s'il est frais, ou récupérera les données du serveur distant et actualisera le cache sinon.

EDIT: Je comprends un peu plus sur le verrouillage de fichiers depuis que j'ai écrit ce qui précède. Il pourrait être utile d'avoir une lecture de cette réponse si vous êtes préoccupé par le verrouillage du fichier ici.

Si vous êtes préoccupé par le verrouillage et l'accès simultané, je dirais que la solution la plus propre serait de file_put_contents dans un fichier temporaire , puis rename() sur $cache_file, qui devrait être une opération atomique, c'est-à-dire que $cache_file sera soit l'ancien contenu, soit le nouveau contenu complet, jamais à mi-chemin.

65
Matt Gibson

Essayez phpFastCache , il prend en charge la mise en cache des fichiers et vous n'avez pas besoin de coder votre classe de cache. facile à utiliser sur l'hébergement mutualisé et VPS

Voici un exemple:

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

Voici une version simple qui passe également une fenêtre User-Agent chaîne vers l'hôte distant pour ne pas ressembler à un fauteur de troubles sans en-têtes appropriés.

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

Tout d'abord, vous voudrez peut-être vérifier le modèle de conception: chargement paresseux .

L'implémentation doit changer pour toujours charger le fichier à partir du cache local. Si le cache local n'existe pas ou si la gigue de temps de fichier est supérieure à 5 minutes, vous récupérez le fichier sur le serveur.

Le pseudo-code est comme suit:

$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

Si vous utilisez un système de base de données de tout type, vous pouvez y mettre ce fichier en cache. Créez une table pour les informations mises en cache et donnez-lui au minimum les champs suivants:

  • Un identifiant; quelque chose que vous pouvez utiliser pour récupérer le fichier la prochaine fois que vous en aurez besoin. Probablement quelque chose comme un nom de fichier.
  • Un horodatage de la dernière fois que vous avez téléchargé le fichier à partir de l'URL.
  • Soit un chemin d'accès au fichier, où il est stocké dans votre système de fichiers local, soit utilisez un champ de type BLOB pour simplement stocker le contenu du fichier lui-même dans la base de données. Je recommanderais simplement de stocker le chemin, personnellement. Si le fichier était très volumineux, vous ne voudriez certainement pas le mettre dans la base de données.

Maintenant, lorsque vous exécuterez le script ci-dessus la prochaine fois, vérifiez d'abord l'identifiant dans la base de données et tirez l'horodatage. Si la différence entre l'heure actuelle et l'horodatage stocké est supérieure à 5 minutes, extrayez de l'URL et mettez à jour la base de données. Sinon, chargez le fichier à partir de la base de données.

Si vous n'avez pas de configuration de base de données, vous pouvez faire la même chose en utilisant simplement des fichiers, où un fichier, ou un champ dans un fichier, contiendrait l'horodatage du dernier téléchargement du fichier.

0
user470714