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

Discussion dans 'Développement d'un site Web ou d'une appli mobile' créé par focoweb.fr, 8 Mars 2011.

  1. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    Alors voila, j'ai écris une classe qui gère le cache avec une utilisation simple :
    Code:
    $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:
      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:
      $cache= new start_cache("monthly");
      autres délais disponibles :
      Code:
       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:
      var $log_file="log.txt"; // append will be done with $cache_base
      var $log_activated=false;


    Code:
    <?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 :
    https://www.webrankinfo.com/forum/t/script-mise-en-cache-des-pages-php.28614/
    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 ...
     
  2. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    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 !!!
     
  3. spout
    spout WRInaute accro
    Inscrit:
    14 Mai 2003
    Messages:
    9 179
    J'aime reçus:
    330
    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.
     
  4. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    Merci pour le complement,
    tu as besoin que je te rajoute ça dans mon code ou tu le feras ?
     
  5. spout
    spout WRInaute accro
    Inscrit:
    14 Mai 2003
    Messages:
    9 179
    J'aime reçus:
    330
    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, ...)
     
  6. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    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:
    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:
    $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
     
  7. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    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:
    <?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
    
     
  8. Blount
    Blount WRInaute impliqué
    Inscrit:
    18 Novembre 2010
    Messages:
    701
    J'aime reçus:
    0
    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.
     
  9. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    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 ?
     
  10. Blount
    Blount WRInaute impliqué
    Inscrit:
    18 Novembre 2010
    Messages:
    701
    J'aime reçus:
    0
    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é.
     
  11. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    Merci pour la doc en tous cas, je mettrais ça dans la prochaine version
     
  12. focoweb.fr
    focoweb.fr Nouveau WRInaute
    Inscrit:
    23 Novembre 2010
    Messages:
    46
    J'aime reçus:
    0
    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:
    <?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 :
    PHP:
    <span class="syntaxdefault"><?php include</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'includes/class_cache.inc.php'</span><span class="syntaxkeyword">);</span><span class="syntaxdefault"> if </span><span class="syntaxkeyword">(!(</span><span class="syntaxdefault">count</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$_POST</span><span class="syntaxkeyword">)></span><span class="syntaxdefault">0</span><span class="syntaxkeyword">))</span><span class="syntaxdefault"> $cache</span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> new start_cache</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"yearly"</span><span class="syntaxkeyword">);</span><span class="syntaxdefault"> </span><span class="syntaxcomment">//can  be hourly, daily, weekly, monthly, yearly </span><span class="syntaxdefault">?></span>
    et ainsi en footer :
    PHP:
    <span class="syntaxdefault"><?php $cache</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">save</span><span class="syntaxkeyword">();</span><span class="syntaxdefault"> ?></span>
    Merci PHP4 qui ne supporte pas les fonction ob_get_contents sur les function activé en __destruct :(
     
Chargement...
Similar Threads - [script] php class Forum Date
[script] Oméga-Annonces 1.5.1 - Php/MySqL Développement d'un site Web ou d'une appli mobile 4 Septembre 2012
[Script] - Interroger et manipuler Wordpress directement via un script PHP en crontab Développement d'un site Web ou d'une appli mobile 26 Avril 2012
[script] probleme confirm() javascript+ PHP Développement d'un site Web ou d'une appli mobile 7 Juin 2011
Gestion des Majuscules [script] - PHP / javascript Développement d'un site Web ou d'une appli mobile 9 Mars 2011
[script] anti spam referrer Développement d'un site Web ou d'une appli mobile 20 Août 2015
[script] miniature et cache d'image à la volée Développement d'un site Web ou d'une appli mobile 13 Décembre 2013
[script] changer un texte en images Développement d'un site Web ou d'une appli mobile 10 Décembre 2013
[Script] Ajouter les boutons de partage des réseaux sociaux sans le tracking Développement d'un site Web ou d'une appli mobile 25 Août 2013
[Script] Clone légal? Développement d'un site Web ou d'une appli mobile 7 Avril 2013
[script] Comment charger un script différent suivant l'heure ? Help ! Développement d'un site Web ou d'une appli mobile 4 Octobre 2012