création de site internet

flus RSS du blogsur Facebooksur Twitter
créateur de mot de passe

Générateur de mot de passe

Créez un mot de passe sécurisé

18
06

Gestion d'un système de cache avec PHP

dans PHP

Principe

Le cache PHP est un système qui permet de stocker dans des fichiers sur le serveur les données qui sont affichées sur les pages de votre site internet. Ce fichier est ensuite lu pour restituer les données sur les pages en lieu et place d'un nouveau traitement par un script php (boucles, requêtes, ...).

Intérêt

Le système de cache PHP permet d'économiser les ressources serveur en réduisant le nombre de traitements des scripts PHP (boucles, variables, ...) et, plus intéressant, en limitant les utilisations d'une base de données telle que MySQL (requêtes, ...). Le serveur se retrouve ainsi moins sollicité, ses performances sont alors optimisées.

Par exemple, j'ai une table contenant 1 million d'enregistrements. A chaque affichage des pages de mon site, je fais une requête sur cette table pour sortir les données dont j'ai besoin et les afficher. Admettons que les résultats obtenus varient peu fréquemment. Partons sur un volume de 4000 pages vues par heure. Sans système de cache, j'ai donc 4000 requêtes sur ma table par heure soient un peu plus de 1 par seconde, et toutes me sortent potentiellement le même résultat.

Je mets en place le système de cache et configure sa fréquence de mise à jour à 1 heure. Donc en 1 heure, je n'ai plus 4000 requêtes exécutées, mais 1 seule, les 3999 autres résultats étant restitués à partir du cache et donc c'est autant d'économies de ressources MySQL.

Alors certes, cet exemple est purement illustratif et tout à fait basique, mais il démontre la logique mathématique qui régit le système de cache PHP. Les ressources économisées seront fonction des traitements mis en cache et de la durée de vie du cache. Cette économie est exponentielle, plus le volume de données traitées par un site est important, plus le gain de ressources obtenu par le système de cache est conséquent. Et par expérience, je peux assurer que le cache PHP est véritablement pertinent et efficace.

Domaine d'application

De mon point de vue, la question de le mettre en place ou non ne se pose pas. Etant donné la simplicité et le fait que, quoi qu'il arrive, son utilisation est bénéfique, j'aurais tendance à dire que pour toute donnée qui s'y prête, la mise en cache doit être systématique.

Donc maintenant reste à savoir quand et sur quel type de données l'utiliser. Premièrement, il faut l'utiliser sur des données dynamiques, qui nécessitent des requêtes en bases de données, voire des traitements PHP lourds. En effet, il n'y a aucun intérêt à mettre en cache des données statiques, qui peuvent être directement intégrées dans votre code HTML.

Ensuite, il faut que ce soient des données purement informatives (pour l'affichage) dont la valeur et la mise à jour n'impactent pas sur le bon fonctionnement du site (à l'inverse de données fonctionnelles qui doivent être justes et à jour en permanence). Par exemple, l'affichage du nombre de messages ou de membres d'un forum, l'affichage d'une liste d'articles, le contenu d'un article, ...

Enfin, il faut juger de la fréquence de mise à jour des données pour être le plus pertinent et efficace possible. Plus la durée de vie du cache est importante, plus l'économie de ressources réalisée est conséquente. Tout en sachant que cette durée peut être définie distinctement pour chaque fichier de cache.

Pour être plus concret, prenons l'exemple de ce blog. J'ai notamment mis en place un système de cache PHP pour mes listes d'article.
Sur la page d'accueil, le code HTML présentant la liste des articles est stocké dans un fichier cache dont la durée de vie est fixée à 1 heure. En effet, je n'ai pas la capacité d'écrire des nouveaux articles toutes les heures, donc potentiellement cette liste et son contenu n'évolueront pas en 1 heure, ce qui justifie tout l'intérêt de passer par le cache. Je n'ai donc qu'une seule requête toutes les heures dans ma base de données MySQL de mes articles pour restituer la liste en page d'accueil. Autrement ce ne sont que des lectures du fichier de cache.
Et si jamais cette liste vient à évoluer dans cette intervalle de temps, soit j'estime que je peux attendre la mise à jour du cache pour que cette liste s'actualise, soit je peux intervenir directement en supprimant le fichier de cache sur le serveur, forçant ainsi son rafraichissement à l'affichage de la page et la réinitialisation du cycle de mise à jour.

Je l'ai également mis en place pour les listes dans les différentes rubriques, pour la gestion de la pagination, pour l'affichage du contenu des articles, pour le plan du site, ...

Mise en place

Le système de cache fait appel aux fonctions PHP de gestion des tampons : ob_start(), ob_get_contents() et ob_end_clean(). Et étant donné que l'on passe par des fichiers de cache, les fonctions file_put_contents() et readfile() de lecture/écriture de fichiers avec PHP seront également utilisées.

Il convient tout d'abord de vérifier si le fichier de cache existe et si sa durée de vie n'est pas dépassée. Pour cela, j'ai écrit une fonction check_cache() que je réutilise systématiquement.

function tep_check_cache($cache,$delai = "")
{
     if($delai == "") $delai = CACHE_EXPIRE;

    if(is_file($cache) && filemtime($cache) >= mktime(date("G"),(int)date("i")-CACHE_EXPIRE,date("s"),date("m"),date("d"),date("Y")))
     {
          return true;
     }
     else
     {
          return false;
     }
}

Elle prend en premier paramètre le chemin du fichier cache, et en second, sa durée de vie en minutes.

Dans mon test, j'utilise la fonction is_file() pour tester l'existence du fichier, on peut également utiliser file_exists(). Il faut cependant savoir que en fonction de la configuration du PHP sur le serveur, le résultat de chacune de ces deux fonctions peut être mis en cache. Il faut alors passer par la fonction clearstatcache() pour passer outre.

A noter que si le second paramètre n'est pas précisé, la valeur de la constante CACHE_EXPIRE que j'ai définie préalablement sera utilisée. Cela permet de gérer rapidement une durée de vie identique pour les fichiers de cache.

define("CACHE_EXPIRE", 60); // durée de vie de 60 minutes

L'appel à cette fonction permet donc de contrôler la présence et la validité du fichier de cache. Si le fichier de cache est utilisable, alors on lit son contenu pour afficher les données à afficher :

$cache = "/chemin_absolu_vers_mon_fichier_cache/nom_du_fichier_cache.html";

if(check_cache($cache,15) == true) // on teste le fichier cache sur une durée de vie de 15 minutes
{
    readfile($cache);
}

NB : veillez à ce que le répertoire qui stocke les fichiers de cache ait les bons droits de lecture et d'écriture.

Si le fichier n'est pas valable, on utilise les fonctions de gestion du tampon PHP, pour mettre en cache le contenu restitué par le script PHP. On commence par ouvrir le tampon :

ob_start();

L'astuce est que une fois le tampon ouvert, toute donnée sensée être affichée sur la sortie standard (le navigateur) sera enregistrée dans le tampon.

Il convient donc ensuite de faire son traitement PHP et d'exploiter classiquement les données et leur affichage. En l'état, les données ne sont pas affichées et potentiellement ne sont pas exploitables. Elles sont dans le tampon, en attente d'utilisation.

On va ensuite stocker ces données dans une variable pour pouvoir les exploiter :

$cachecontent = ob_get_contents();

Les données sont exploitables, le tampon n'est plus d'aucune utilité, on le ferme et on l'efface :

ob_end_clean();

Il ne reste plus maintenant qu'à enregistrer les données dans le fichier cache :

file_put_contents($cache,$cachecontent);

Mais ce n'est pas fini, nous avons vu que les données avait été rédirigées dans le tampon PHP et n'apparaissaient donc pas sur le navigateur. Il faut donc les afficher. Et tant qu'à faire autant exploiter et lire dès maintenant le fichier cache :

readfile($cache);

Le processus est terminé, les données sont affichées et en parallèle ont été stockées en cache.

Pour être plus explicite, voici un exemple de mise en pratique pour la gestion en cache de l'affichage d'une liste de 10 articles :

$cache = "/chemin_absolu_du_site/CACHE/liste-10-articles.html";

if(check_cache($cache,30) == true)
{
     readfile($cache);
}
else
{
     ob_start();

     // le traitement PHP de restitution et d'affichage des données
     $articles_query = mysql_query("SELECT article_id, titre, introduction FROM articles WHERE etat = 1 ORDER BY date_publication DESC LIMIT 0,10");
     while($articles = mysql_fetch_array($articles_query))
     {
          echo '<h1><a href="article.php?id=' . $articles['article_id'] . '">' . htmlentities($article['titre']) . '</a></h1>';
          echo '<p>' . $article['introduction'] . '</p>';
     }

     $cachecontent = ob_get_contents();

     ob_end_clean();

     file_put_contents($cache,$cachecontent);

     readfile($cache);
}

Certes on aurait plus simplifier ce script en testant check_cache() sur false et en n'exécutant le readfile() qu'à la fin en dehors du test, mais j'aime bien cette écriture, sa logique facilite la lecture et la compréhension.

Avertissements techniques

L'utilisation de la fonction file_put_contents() nécessite PHP5. Assurez-vous bien de la version de PHP qui tourne sur votre serveur.

Etant donné que l'on passe par des fichiers physiques sur le serveur pour gérer le cache, la problématique de l'espace disque que cela utilise se pose. Là encore, c'est un point à intégrer dans votre réflexion avant la mise en oeuvre : est-ce que ces données ont besoin d'être stockées en cache, car cela prend de la place sur mes disques ? Néanmoins, étant donné que dans la majorité des cas, ce qui va être stocké dans ces fichiers, va être du code HTML, une astuce consiste à alléger le fichier en supprimant tous les espaces, tabulations et retours à la ligne superflus entre les balises HTML. Ca fait toujours quelques octets de gagnés et sur un grand nombre de fichiers, ça représente un certain volume.

Partager :