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)?
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.
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;
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);
}
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)
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:
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.