[script] php class cache : accélérez vos pages !

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

[script] php class cache : accélérez vos pages !

Message le Mar Mar 08, 2011 14:06

Alors voila, j'ai écris une classe qui gère le cache avec une utilisation simple :
Code: Tout sélectionner
$cache= new start_cache();


  • le cache démarre lors de l'appel a la classe
  • le cache s'arrête lorsque la classe meure : en bas de la page
  • Vous devez juste regler le repertoire ou attérit votre cache
    Code: Tout sélectionner
    var $cache_base='/mon/repertoire/physique/de/cache/'; // base path with / ending
  • le délai d'expiration par défaut est de 24h, mais on peut spécifier des délais d'expiration
    Code: Tout sélectionner
    $cache= new start_cache("monthly");

    autres délais disponibles :
    Code: Tout sélectionner
    array( "hourly" => 3600, "daily" => 3600*24,"weekly" => 3600*24*7, "monthly" => 3600*24*30, "yearly" => 3600*24*365 )
  • pour faire un test sans cache en appelant la page avec le paramètre "reload" :
    http://mon.site.fr/page.php?reload
  • on peut vider le cache avec une url:
    http://mon.site.fr/page.php?clear_cache=daily ,
    à utiliser avec un webcron ...
  • les logs de cache sont disponibles aussi avec ces paramètres :
    Code: Tout sélectionner
    var $log_file="log.txt"; // append will be done with $cache_base
    var $log_activated=false;


Code: Tout sélectionner
<?PHP
class start_cache {
var $cache_base='/mon/repertoire/physique/de/cache/'; // base path with / ending
var $log_file="log.txt"; // append will be done with $cache_base
var $log_activated=false;

   function __construct($planing="daily") {
      if (isset($_GET['clear_cache'])) $this->clear_cache($this->escape_string($_GET['clear_cache']));
      $schedules = array( "hourly" => 3600, "daily" => 3600*24,"weekly" => 3600*24*7, "monthly" => 3600*24*30, "yearly" => 3600*24*365 ); // list of expiration time
      $requested_url=$_SERVER['REQUEST_URI']; //read page addresse
      $requested_url=ereg_replace('/','-',$requested_url); // URI 2 filename
      if($requested_url=="-") $requested_url="-index.html"; // if url=/ rewrite in index.html
      $this->cache_dir=$this->cache_base.$planing;
      $this->cache_file=$this->cache_base.$planing."/cache".$requested_url; // build full cache file path
      $expire=$schedules[$planing]; // get expiration time
      $this->cache_activated=@filemtime($this->cache_file)< (time()- $expire) || isset($_GET['reload']) ; //if not exist or expired or forced
      if ($this->cache_activated) {
         ob_start(); // start buffering for the page nothing is sent to the browser
         $this->logging(" cache started for file ".$this->cache_file, "start");
      } else { // file exist
         include ($this->cache_file); // on le copie ici
         $this->logging($this->cache_file , "read");
         die();
      }
   }
   
   // log event used like this -> argument : Message , [Group]
   // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
   function logging($msg, $group="DEFAULT")
   {
      if($this->log_activated) {
         // upper case
         $group=strtoupper ($group);
         // prepare message
         $msg= str_replace("\n"," ",$msg);
         $msg= str_replace("\r"," ",$msg);
         // open file
         $fd = fopen($this->cache_base.$this->log_file, "a");
         // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
         fwrite($fd, date("d/m/Y H:i:s")." -> ". $group. ": ".$msg . "\n");
         // close file
         fclose($fd);
      }
   }

   function clear_cache($planing="daily") {
      $this->logging("$planing called from ip ".$_SERVER['REMOTE_ADDR'], "clear");
      if (is_dir($this->cache_base.$planing)) $this->del_tree($this->cache_base.$planing);
      die ($planing." cache cleared !");
   }
   
      function del_tree($dir) 
   {
      $current_dir = opendir($dir);
      while($entryname = readdir($current_dir)) {
         if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) 
         {
            del_tree("${dir}/${entryname}");
         }  elseif($entryname != "." and $entryname!="..") {
            unlink("${dir}/${entryname}");
         }
      } 
      closedir($current_dir);
      rmdir(${dir});
      $this->logging("remove dir ${dir}", "clear");

   }

   // samll function to protect from script attack or SQL injections
   function escape_string($uvar){
   $uvar=preg_replace("/((\%3C)|<)[^\n]+((\%3E)|>)/","",$uvar); // Prevent script CSS attack
   return mysql_escape_string($uvar); // prevent mysql attack
   }
   
   function __destruct() {
      if ($this->cache_activated) {
          $contenuCache = ob_get_contents(); //get buffer
          ob_end_flush();// end buffer
         if (!is_dir($this->cache_dir)) {
            mkdir($this->cache_dir); // create dir if needed
            $this->logging($this->cache_dir, "create_dir");
         }
         $fd = fopen($this->cache_file, "w"); // open cache file and clear it
         if ($fd) {
            fwrite($fd,$contenuCache); // Write cache file
            fclose($fd);
            $this->logging(" cache ended for file ".$this->cache_file."(".strlen($contenuCache).")", "stop");
         }
      }
   }

}


$cache= new start_cache("yearly");
?>

Votre page hmtl ici
<?php
echo" et vos codes php qui rament... ";
sleep(4);
?>

et tout ce que vous voulez mettre en cache


Ce code est inspiré de l'idée de fandecine ici :
http://forum.webrankinfo.com/mise-cache-des-pages-php-t28614.html
que je remercie au passage. Son code me plaisait beaucoup mais difficile à intégrer sur un gros projet.

Dites moi si ça marche pour vous ...

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mar Mar 08, 2011 14:38

j ai oublié de dire un truc :
ne pas utiliser de cache sur les pages de destination de vos formulaires, surtout les post ou encore si vous offrez du contenu diffèrent pour chaque visiteur !!!


spout
WRInaute accro
WRInaute accro
 
Messages: 4382
Inscription: 14 Mai 2003

Re: [script] php class cache : accélérez vos pages !

Message le Mar Mar 08, 2011 17:23

Il suffit de vérifier si le script reçoit des données en _POST et/ou si le membre est connecté pour activer le cache ou pas.

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mar Mar 08, 2011 21:44

Merci pour le complement,
tu as besoin que je te rajoute ça dans mon code ou tu le feras ?


spout
WRInaute accro
WRInaute accro
 
Messages: 4382
Inscription: 14 Mai 2003

Re: [script] php class cache : accélérez vos pages !

Message le Mar Mar 08, 2011 22:17

C'est plus à faire dans la façon d'utiliser la classe que de l'intégrer dedans... j'ai donné l'exemple avec _POST et membre connecté, mais ça peut être différent dans d'autres applications. De plus il pourrait il y avoir d'autres conditions (isAjax, ...)

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 9:35

vu que la classe démarre le cache et que si on a du cache on fait un kill, on va pas passer dans le code du coup, la seule façon de neutraliser le cache c'est de regarder si on a des POST avant de démarrer le cache
Code: Tout sélectionner
if (!(count($_POST)>0))
$cache= new start_cache();

ça vaut le coup de mettre le test dans la classe à ton avis ? ou en paramètre de classe ?
Code: Tout sélectionner
$cache= new start_cache("hourly",!(count($_POST)>0));

je vais rajouter une fonction clean_page tout à l'heure au cas ou on en est besoin.

Je modifierais mon premier message

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 12:50

ps:Je n'arrive pas éditer mon premier post !

Alors voila, la class cache php supporte maintenant le nettoyage d'un fichier dans n'importe quelle planning de cache
à travers les urls comme les autres fonctions, exemple :
http://mon.site.fr/page.php?clear_cache_file=/mon/uri/page.php

Voici la nouvelle version de code de la class cache php :
Code: Tout sélectionner
<?php
class start_cache {
var $cache_base='/mon/repertoire/physique/de/cache/'; // base path with / ending
var $log_file="log.txt"; // append will be done with $cache_base
var $log_activated=false;

   function __construct($planing="daily") {
      if (isset($_GET['clear_cache'])) $this->clear_cache($this->escape_string($_GET['clear_cache']));
      if (isset($_GET['clear_cache_file'])) $this->del_file($this->make_name($this->escape_string($_GET['clear_cache_file'])));
      $schedules = array( "hourly" => 3600, "daily" => 3600*24,"weekly" => 3600*24*7, "monthly" => 3600*24*30, "yearly" => 3600*24*365 ); // list of expiration time
      $requested_url=$this->make_name($_SERVER['REQUEST_URI']); //make page addresse
      $this->cache_dir=$this->cache_base.$planing;
      $this->cache_file=$this->cache_base.$planing."/cache".$requested_url; // build full cache file path
      $expire=$schedules[$planing]; // get expiration time
      $this->cache_activated=@filemtime($this->cache_file)< (time()- $expire) || isset($_GET['reload']) ; //if not exist or expired or forced
      if ($this->cache_activated) {
         ob_start(); // start buffering for the page nothing is sent to the browser
         $this->logging(" cache started for file ".$this->cache_file, "start");
      } else { // file exist
         include ($this->cache_file); // on le copie ici
         $this->logging($this->cache_file , "read");
         die();
      }
   }
// create a name like this : cache
   function make_name($address) {
      $address=ereg_replace('/','-',$address); // URI 2 filename
      if($address=="-") $address="-index.html"; // if url=/ rewrite in index.html
      return $address;
   }

   // log event used like this -> argument : Message , [Group]
   // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
   function logging($msg, $group="DEFAULT")
   {
      if($this->log_activated) {
         // upper case
         $group=strtoupper ($group);
         // prepare message
         $msg= str_replace("\n"," ",$msg);
         $msg= str_replace("\r"," ",$msg);
         // open file
         $fd = fopen($this->cache_base.$this->log_file, "a");
         // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
         fwrite($fd, date("d/m/Y H:i:s")." -> ". $group. ": ".$msg . "\n");
         // close file
         fclose($fd);
      }
   }

   function clear_cache($planing="daily") {
      $this->logging("$planing called from ip ".$_SERVER['REMOTE_ADDR'], "clear_dir");
      if (is_dir($this->cache_base.$planing)) $this->del_tree($this->cache_base.$planing);
      die ($planing." cache cleared !");
   }
   
      function del_tree($dir) 
   {
      $current_dir = opendir($dir);
      while($entryname = readdir($current_dir)) {
         if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) 
         {
            del_tree("${dir}/${entryname}");
         }  elseif($entryname != "." and $entryname!="..") {
            unlink("${dir}/${entryname}");
         }
      } 
      closedir($current_dir);
      rmdir(${dir});
      $this->logging("remove dir ${dir}", "clear_dir");

   }

      function del_file($file) 
   {
      $file="cache".$file;
      $this->logging("$file called from ip ".$_SERVER['REMOTE_ADDR'], "clear_file");
      $current_dir = opendir($this->cache_base);
      while($entryname = readdir($current_dir)) {
         if(is_dir($this->cache_base."/$entryname") and ($entryname != "." and $entryname!="..")) 
         {
            $current_dir2 = opendir($this->cache_base."/$entryname");
            while($entryname2 = readdir($current_dir2)) {
               if(is_file($this->cache_base."/$entryname/".$entryname2) and $entryname2 == $file ) {
                  unlink($this->cache_base."/$entryname/".$entryname2);
                  $this->logging("remove file ".$this->cache_base."/$entryname/".$entryname2, "clear_file");
               }
            }
            closedir($current_dir2);
         } 
      }
      closedir($current_dir);
      die ($file." cache cleared !"); 
   }

   // samll function to protect from script attack or SQL injections
   function escape_string($uvar){
   $uvar=preg_replace("/((\%3C)|<)[^\n]+((\%3E)|>)/","",$uvar); // Prevent script CSS attack
   return mysql_escape_string($uvar); // prevent mysql attack
   }
   
   function __destruct() {
      if ($this->cache_activated) {
          $contenuCache = ob_get_contents(); //get buffer
          ob_end_flush();// end buffer
         if (!is_dir($this->cache_dir)) {
            mkdir($this->cache_dir); // create dir if needed
            $this->logging($this->cache_dir, "create_dir");
         }
         $fd = fopen($this->cache_file, "w"); // open cache file and clear it
         if ($fd) {
            fwrite($fd,$contenuCache); // Write cache file
            fclose($fd);
            $this->logging(" cache ended for file ".$this->cache_file."(".strlen($contenuCache).")", "stop");
         }
      }
   }

}


$cache= new start_cache("daily");
?>

Votre page hmtl ici
<?php
echo" et vos codes php qui rament... ";
sleep(4);?>

et tout ce que vous voulez y mettre en cache


Blount
WRInaute occasionnel
WRInaute occasionnel
 
Messages: 430
Inscription: 18 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 14:32

L'instruction "var" n'est plus d'actualité.
De même, tu devrais définir la visibilité de tes méthodes (public, protected, private).

Comme PHP4 n'est plus supporté, il est inutile de maintenir un code pour ce dernier.

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 15:25

super, merci pour les commentaires de codage !

mais des questions se posent à moi :
  • quelle visibilité pour __constructor et __destructor ?
  • quelle difference entre private et protected ? ça passe au classe extend en protected ?

et sinon l'interet de la classe ? tu trouves ça utile ?


Blount
WRInaute occasionnel
WRInaute occasionnel
 
Messages: 430
Inscription: 18 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 15:56

Le constructeur a en général une visibilité public. Sinon, tu ne peux l'instancié de cette manière "new ClassName();" hors de la class. Elle est mise en protected ou private pour créer un singleton en général.

La différence entre protected et private est que :
* protected : empèche l'accès au propriété et méthode hors de la classe
* private : pareil que protected sauffe qu'en plus, la propriété et la méthode ne peut être accédé dans les classes filles.

Je n'ai pas du tout examiné la classe, je ne jugerai donc pas son utilité.

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mer Mar 09, 2011 16:12

Merci pour la doc en tous cas, je mettrais ça dans la prochaine version

focoweb.fr
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 46
Inscription: 23 Nov 2010

Re: [script] php class cache : accélérez vos pages !

Message le Mar Mar 15, 2011 16:46

Finalement, j'ai du mettre cette classe sur un hébergement PHP4. Alors j'ai du faire pas mal de modif si ça peut servir à quelqu'un voici une class php4 de cache obsolète :(
Code: Tout sélectionner
<?php
    class start_cache {
    var $cache_base="/mon/repertoire/cache/";  //'/mon/repertoire/physique/de/cache/'; // base path with / ending
    var $log_file="log.txt"; // append will be done with $cache_base
    var $log_activated=true;
   function start_cache() {
    //destructor not working with ob_get_contents
    //register_shutdown_function(array(&$this, '__destruct'));
    // must call $this->save(); manually at the end
   
    //constructor
    $argcv = func_get_args();
    call_user_func_array(array(&$this, '__construct'), $argcv);
   }

      function save() {
      $this->__destruct();
      }
      
       function __construct($planning="daily") {
          if (isset($_GET['clear_cache'])) $this->clear_cache($this->escape_string($_GET['clear_cache']));
          if (isset($_GET['clear_cache_file'])) $this->del_file($this->make_name($this->escape_string($_GET['clear_cache_file'])));
          $schedules = array( "minute"=>60 ,"hourly" => 3600, "daily" => 3600*24,"weekly" => 3600*24*7, "monthly" => 3600*24*30, "yearly" => 3600*24*365 ); // list of expiration time
          $requested_url=$this->make_name($_SERVER['REQUEST_URI']); //make page addresse
          $this->cache_dir=$this->cache_base.$planning;
          $this->cache_file=$this->cache_base.$planning."/cache".$requested_url; // build full cache file path
          $expire=$schedules[$planning]; // get expiration time
          $this->cache_activated=@filemtime($this->cache_file)< (time()- $expire) || isset($_GET['reload']) ; //if not exist or expired or forced
          if ($this->cache_activated) {
             // start buffering for the page nothing is sent to the browser
         ob_start();
         $this->logging("cache started for file ".$this->cache_file."($planning)", "start");
          } else { // file exist
             include ($this->cache_file); // on le copie ici
             $this->logging($this->cache_file , "read");
             die();
          }
       }
   //singleton detector   
      function &getInstance() {
            static $instance = null;
            if (null === $instance) {
                $instance = new start_cache();
            }
            return $instance;
        }

    // create a name like this : cache
       function make_name($address) {
          $address=ereg_replace('/','-',$address); // URI 2 filename
          if($address=="-") $address="-index.html"; // if url=/ rewrite in index.html
          return $address;
       }

       // log event used like this -> argument : Message , [Group]
       // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
       function logging($msg, $group="DEFAULT")
       {
          if($this->log_activated) {
             // upper case
             $group=strtoupper ($group);
             // prepare message
             $msg= str_replace("\n"," ",$msg);
             $msg= str_replace("\r"," ",$msg);
             // open file
             $fd = fopen($this->cache_base.$this->log_file, "a");
             // write string 18/01/2011 11:45:16 -> MYSQL: SELECT * FROM table
             fwrite($fd, date("d/m/Y H:i:s")." -> ". $group. ": ".$msg . "\n");
             // close file
             fclose($fd);
          }
       }

       function clear_cache($planning="daily") {
          $this->logging("$planning called from ip ".$_SERVER['REMOTE_ADDR'], "clear_dir");
          if (is_dir($this->cache_base.$planning)) $this->del_tree($this->cache_base.$planning);
          die ($planning." cache cleared !");
       }
       
          function del_tree($dir)
       {
          $current_dir = opendir($dir);
          while($entryname = readdir($current_dir)) {
             if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!=".."))
             {
                del_tree("${dir}/${entryname}");
             }  elseif($entryname != "." and $entryname!="..") {
                unlink("${dir}/${entryname}");
             }
          }
          closedir($current_dir);
          rmdir(${dir});
          $this->logging("remove dir ${dir}", "clear_dir");

       }

          function del_file($file)
       {
          $file="cache".$file;
          $this->logging("$file called from ip ".$_SERVER['REMOTE_ADDR'], "clear_file");
          $current_dir = opendir($this->cache_base);
          while($entryname = readdir($current_dir)) {
             if(is_dir($this->cache_base."/$entryname") and ($entryname != "." and $entryname!=".."))
             {
                $current_dir2 = opendir($this->cache_base."/$entryname");
                while($entryname2 = readdir($current_dir2)) {
                   if(is_file($this->cache_base."/$entryname/".$entryname2) and $entryname2 == $file ) {
                      unlink($this->cache_base."/$entryname/".$entryname2);
                      $this->logging("remove file ".$this->cache_base."/$entryname/".$entryname2, "clear_file");
                   }
                }
                closedir($current_dir2);
             }
          }
          closedir($current_dir);
          die ($file." cache cleared !");
       }

       // samll function to protect from script attack or SQL injections
       function escape_string($uvar){
       $uvar=preg_replace("/((\%3C)|<)[^\n]+((\%3E)|>)/","",$uvar); // Prevent script CSS attack
       return mysql_escape_string($uvar); // prevent mysql attack
       }
       
       function __destruct() {
          if ($this->cache_activated) {
              $contenuCache = ob_get_contents(); //get buffer
              ob_end_flush();// end buffer
             if (!is_dir($this->cache_dir)) {
                mkdir($this->cache_dir); // create dir if needed
                $this->logging($this->cache_dir, "create_dir");
             }
          if(!$contenuCache===false) {
             $fd = fopen($this->cache_file, "w"); // open cache file and clear it
             if ($fd) {
               fwrite($fd,$contenuCache); // Write cache file
               fclose($fd);
               $this->logging("cache ended for file ".$this->cache_file."(".strlen($contenuCache).")", "stop");
             }
         } else{
               $this->logging("cache ended without content", "warning");
         }
          }
       }

    }
?>


qui s'utilise ainsi en header :
Code: Tout sélectionner
<?php include('includes/class_cache.inc.php'); if (!(count($_POST)>0)) $cache= new start_cache("yearly"); //can  be hourly, daily, weekly, monthly, yearly ?>

et ainsi en footer :
Code: Tout sélectionner
<?php $cache->save(); ?>

Merci PHP4 qui ne supporte pas les fonction ob_get_contents sur les function activé en __destruct :(


Si vous avez aimé cette discussion, partagez-la sur vos réseaux sociaux préférés :

Lectures recommandées sur ce thème :



Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 0 invités