[tutoriel] Mise en cache en PHP, la version complète.

WRInaute discret
Bonjour,

fandecine a fait un superbe script de mise en cache en PHP il est accesible sur cette page :
https://www.webrankinfo.com/forum/t/script-mise-en-cache-des-pages-php.28614/

Son script fonctionne très bien mais que pour les petits/moyens sites, s'il y a plusque 1 million fichiers cache ça va provoquer les performance du serveur.

j'ai ajouté des petits trucs pour l'améliorer pour qu'il supporte 600 millions fichiers cache facilement.

voici le script final :

Code:
<?php
$urldemandee=$_SERVER['REQUEST_URI']; //on lit l'adresse de la page
$urldemandee=ereg_replace('/','-',$urldemandee); // on tranforme l'adresse en nom de fichier

if($urldemandee=="-") $urldemandee="-index.html"; // si l'adresse est la racine du site, on ajoute index.html
if(!is_dir("cache/".substr(md5($_SERVER['REQUEST_URI']), -3))) { mkdir("cache/".substr(md5($_SERVER['REQUEST_URI']), -3)); } 
	$fichierCache="cache/".substr(md5($urldemandee), -3)."/".$urldemandee.".html"; // on construit le chemin du fichier cache de la page
	
if (@filemtime($fichierCache)<time()-(3600*24*360)) { //si la page n'existe pas dans le cache ou si elle a expir&eacute;
	ob_start(); // on d&eacute;marre la bufferisation de la page: rien de ce qui suit n'est envoy&eacute; au navigateur
	echo "Votre contenu à mettre en cache ici";
	$contenuCache = ob_get_contents(); // on recuperre le contenu du buffer
	ob_end_flush();// on termine la bufferisation
	$fd = fopen("$fichierCache", "w"); // on ouvre le fichier cache
	 if ($fd) {
		    fwrite($fd,$contenuCache); // on ecrit le contenu du buffer dans le fichier cache
		    fclose($fd);
	    }
} 

else { // le fichier cache existe d&eacute;j&agrave; 
 include ($fichierCache); // on le copie ici
}
?>

Le principe est simple, c'est de convertir chaque "page actuelle" en MD5, et de créer un dossier des 3 première caractères, et après on compare, si le 3 premières caractères du MD5 de notre page correspond à un dossier on met dedans.. donc on aura en total 15 x 15 x 15 (15 puissance 3 correspond à l'hexa (15) X 3 caractères) dossiers cache, ce qui fait 3375 dossiers.

donc pour 2 millions pages on aura seulement 592 fichiers par dossier :D

Voilà, je l'ai fais par besoin, mon serveur rame à cause de quelque millions fichiers cache, je me suis dis ça peut être utile pour quelques membres sur WRI.
 
WRInaute impliqué
Une chaine a toujours le même md5, mais es-tu sûr que la valeur d'un md5 représente toujours la même chaine ?
 
WRInaute impliqué
Petit-ourson je ne vois pas la pertinence de ta question par rapport au sujet, puisqu'un md5 est toujours le même pour une chaine donnée, et que lyonist se sert des 3 premiers charactères du md5 du nom de la page demandé pour créer/classer dans un dossier, mais que le nom du fichier cache reste "en clair" il n'y a pas de problème. Tu n'as pas dû bien lire le premier post ou alors j'ai loupé quelque chose?

Code:
$fichierCache="cache/".substr(md5($urldemandee), -3)."/".$urldemandee.".html"; // on construit le chemin du fichier cache de la page
 
Olivier Duffez (admin)
Membre du personnel
Merci pour ce partage d'infos et de code. Pour ma part le nom du fichier de cache est quasi toujours associé à un ID (nombre), par exemple pour un topic du forum ce sera l'ID du topic. Donc c'est simple de répartir les fichiers dans des sous-répertoires basés sur les chiffres.
J'ai testé jusqu'à 100.000 fichiers par répertoire sans voir de baisse sensible des perfs (serveur apache, je ne me prononce pas pour IIS ;-))
 
WRInaute passionné
Aurais-je un fils ... spiryuel !? :mrgreen:

Merci lyonist pour ces modifs trés pertinantes :wink:

Olivier, si le nombre de fichiers dans un répertoire doit poser des problèmes c'est au niveau du SE (Linux par exemple) pas au niveau d'apache :D

Je ne suis pas allé jusqu'à 100.000 fichiers dans un répertoire, mais le nombre n'influe pas sur le temps d'accés en adressage direct à un fichier (sauf avec une recherche). Par contre cela peut poser des problémes au niveau de l'optimisation de l'occupation de l'espace disque (avec un système de fichier EXT3 généralement utilisé sous linux) surtout pour un systéme de cache qui par définition effec et recré des fichiers (le disque peut vite resembler à un morceau de gruyère). C'est plus à ce niveau que le morcellement en répertoire est intéressant.

Maintenant, en matière de cache, je n'utilise plus ce systéme qui consomme beaucoup d'espace disque innutile et ne permet pas de modifier l'apparence des pages sans éffacer le cache. Il est bien plus efficace de sérialiser les données dynamique (de façon indépendante de l'habillage des données) et de stocker sur le disque la chaine sérialisée. Cela permet en plus de pouvoir utiliser ces données sur des pages différentes et diminue énormément la redondance.

Je crois me rappeller que j'avais promis de publier une classe PHP qui fait ce boulot, mais par manque de temps libre :mrgreen:

Je vais m'y remettre :wink:
 
WRInaute occasionnel
Bonsoir,

On peut aussi utiliser la librairie CacheLite, disponible sur Pear
http://pear.php.net/package/Cache_Lite

Cette librairie permet de mettre en cache le résultat d'une fonction php, par exemple, une fonction qui génère un menu. Ainsi celui-ci ne sera calculé qu'une seule fois.
De plus, on peut définir la durée de validité du cache.
Les fichiers plus vieux que le temps de cache spécifié ne sont plus utilisés et un autre fichier est calculé.

à plus
 
WRInaute impliqué
@fandecine: as-tu eu le temps de faire ta classe PHP pour la fonction cache (avec la modif des sous dossiers donnée par lyonist ca serait encore mieux) ?

phpmikedu83 a dit:
En utilisant des preg_replace déjà, ça sera plus performant... ;)
Ou un str_replace c'est encore plus rapide :)
 
WRInaute passionné
Bonjour,
Est-ce que ce script de mise en cache a subit une autre évolution depuis 2009 sur une autre discussion sur WRI ?

Est-ce qu'il est possible de rajouter un peu de code pour que lorsque un fichier cache doit être créé dans un sous répertoire, il y ait une vérification des fichiers trop vieux dans ce sous répertoire afin de les supprimer?

Cela permettrait de faire le ménage automatiquement petit à petit.

J'ai trouvé cette fonction mais pas sûr de comment l'intégrer dans le script de lyonist :

Code:
function destroy($dir) {
$mydir = opendir($dir);
while($file = readdir($mydir)) {
    if($file != "." && $file != "..") {
        chmod($dir.$file, 0777);
        if(is_dir($dir.$file)) {
            chdir('.');
            while($dir.$file) {
                if(date("U",filectime($file) >= time() - 3600)
                {
                    unlink($dir.$file)
                }
            }

        }
        else
            unlink($dir.$file) or DIE("couldn't delete $dir$file<br />");
    }
}
closedir($mydir);
}

Bien sûr il faudrait changer 3600 par 3600*24*360 ou mieux l'ajouter en argument de la fonction.
 
Discussions similaires
Haut