Le site Fobec.com est hébergé sur un serveur mutualisé qui connait parfois quelques faiblesses. Le temps de chargement des pages devient long et peut atteindre 3 secondes aux heures de pointes. L'
analyse des scripts PHP a permis de déterminé l'origine des lenteurs :
les requêtes MySQL.
Mise en cacheLe plus souvent, les sites internet utilisent un système de cache pour réduire la charge serveur et améliorer le temps de chargement. Le principe est 'bufferiser' la sortie d'un script PHP, stocker le code HTML dans un fichier et charger la page à partir du cache.
Au lieu de réecrire une partie de l'architecture du site Fobec.com, nous avons décider de stocker uniquement le résultat de certaines requetes MySQL et non l'ensemble du code HTML d'une page.
Class LocalFileCache
Le but de la class est de charger et de stocker les requetes MySQL dans un fichier- Enregistrer: les données issues de la requête SQL sont sérialisées puis enregistrer dans un fichier.
- Charger: chargement du fichier cache puis desérialisation des données.
- le paramètre
$maxage fixe le délai maximal de validité des données mises en cache.
<?php
/**
* LocalFileCache: charger et enregistrer des requetes MySQL dans un fichier
*
* @author Fobec 2010
*/
class LocalFileCache {
/**
* Enregistrer le contenu d'un array dans un fichier
* @param array $resultset
* @param string $file fichier de destination
* @param boolean $error transmettre les erreurs
*/
public static function saveQuery(array $resultset, $file, $error=null) {
$data=serialize($resultset);
$fhandle=@fopen($file,'w');
if ($fhandle) {
fwrite($fhandle, $data);
fclose($fhandle);
} else if (isset($error)) {
throw new Exception("File writing denied to ".$file." !!!");
}
}
/**
* Charger le contenu d'un array à partir d'un fichier
* @param string $file fichier de cache
* @param int $maxage validité max. du cache en sec, 10800 => 3 heures
* @param boolean $error transmettre les erreurs
* @return array
*/
public static function loadQuery($file, $maxage=null, $error=null) {
if (!file_exists($file)) {
if (isset($error)) {
throw new Exception("Unknow file ".$file." !!!");
}
return null;
}
//hors delai, cache perimé
if (isset($maxage)) {
$filedate=filemtime($file);
if ((time()-$filedate)>$maxage) {
return null;
}
}
$fhandle=@fopen($file,'r');
if ($fhandle) {
$buf=stream_get_contents($fhandle);
return unserialize($buf);
fclose($fhandle);
} else if (isset($error)) {
throw new Exception("File reading denied to ".$file." !!!");
}
}
}
?>
Exemple d'utilisation dans une class ModelEn suivant le principe MVC, une class model a pour but d'acquérir et de formater des données. La mise en place du cache charge les données en priorité à partir d'un fichier au lieu d'effectuer systématiquement une requête MySQL.
/**
* Sélectionner TOP 5 articles populaires
* @return array
*/
public function Top5_article() {
$f=$_SERVER['DOCUMENT_ROOT'].'/cache/Top5MostView.dat';
/** Lecture à partir du fichier cache */
$validity=1*60*60; //1 heure
$rs=LocalFileCache::loadQuery($f, $validity);
if (isset($rs)) {
return $rs;
} else {
...
$rs=mysql_query ($SQL);
...
}
/* Ecriture du cache */
LocalFileCache::saveQuery($rs, $f);
return $rs;
}
}