Location: PHPKode > scripts > phpSuperCache > phpsupercache/cache.class.php
<?php
/*--------------------------------------------------------------------------------


  Application: phpSuperCache
  ==========================
  
  
  Archivo: cache.class.php
  Autor: Francisco Echarte [hide@address.com]
  Fecha: 2001-08-23
  Version: 0.2

  Clases:
     cacheManager => guarda en cache y recupera, páginas enteras o bloques


  LICENCIA
  ========
	copyright (c) 2001 Francisco Echarte [hide@address.com]

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public License
	version 2.1 as published by the Free Software Foundation.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details at 
	http://www.gnu.org/copyleft/lgpl.html
  
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  

  Modificaciones:
     .- Se añade el manejo de CACHE_QUERYS para decidir mediante expresiones
	    regulares que URIS se cachean

  Observaciones:
     .- Desarrollado tomando como base toncarta, de heyes-computing.net
     .- Utiliza únicamente el filesystem, por se lo más rápido. No se usa una BD,
        con el fin de evitar el cuello de botella que implica la solicitud continua
        de conexiones.
     .- Las páginas son almacenadas en texto plano y en comprimido (gzip), con el fin
        de ofrecer el contenido de la cache comprimido, si el navegador del usuario
        lo soporta.

  --------------------------------------------------------------------------------*/



include_once(dirname(__FILE__).'/cache.config.php');
include_once(dirname(__FILE__).'/cache.timings.php');


class cacheManager{

   var $request_uri; //Para guardar solicitdud del usuario
   var $query_string; //Para guardar la query solicitada
   var $php_self; //Para guardar página solicitada
   var $gzip_supported; //Para indicar si en la petición, el navegador del
                        //usuario soporta información en formato gzip

   var $genereting_output; //Para indicar cuando se está generando output para
                           //guardar en cache
   
      
   /*---------------------------------------------------------------------------
     Entrada:
     Salida :
     Efecto : Construtcr de la clase, inicializa las variables. Ejecuta la autolimpieza
              con cierta probabilidad, si la opción está activada
     ---------------------------------------------------------------------------*/
   function cacheManager(){
   	  global $CACHE_CONFIG;

      $this->gzip_supported = 0;
      $this->genereting_output = 0;
      $this->request_uri = $GLOBALS[REQUEST_URI];
	  $this->query_string = $GLOBALS[QUERY_STRING];
	  $this->php_self = basename($GLOBALS[PHP_SELF]);

      $CACHE_CONFIG['run_cleanup'] == 1? $this->cacheCleanup() : NULL;

      // Miro si el navegador del usuario permite envío de información comprimida

      if(strpos(" ".$GLOBALS[HTTP_ACCEPT_ENCODING],'gzip') !== 0)
         $this->gzip_supported = 1;
      else
         $this->gzip_supported = 0;

   }

   
   /*---------------------------------------------------------------------------
     Entrada:
     Salida : Si la página existe en cache, devuelve el contenido y finaliza el script.
     Efecto : Si la página solicitada por el usuario está entre las que hay
              que cachear, comprueba si hay una copia disponible y la envía,
              finalizándose la ejecución. Si no hay una copia disponible, se
              inicializa el output buffer, para poder luego capturar la salida
              generada por el script.
     ---------------------------------------------------------------------------*/
   function startCachingPage(){
      global $CACHE_TIMINGS, $CACHE_CONFIG, $CACHE_QUERYS;

      if($CACHE_TIMINGS[$this->php_self] > 0 
	     && ($this->query_string == '' 
		     || ereg($CACHE_QUERYS[$this->php_self],$this->query_string) ) ){

         //
         // Está la página cacheada ?
         //

         list($cached_page,$gzip) = $this->checkCache($this->request_uri,$CACHE_TIMINGS[$this->php_self]);

         if($cached_page != ''){

            // Compressed?
            if($CACHE_CONFIG['return_compressed'] == 1 AND $gzip== 1){
               header ("Content-Encoding: gzip");
            }

            echo $cached_page;

            $this->logVisit($this->request_uri, 'HIT', $gzip);
            exit;
         }
         else{
            ob_start();
            $this->genereting_output = 1;
            $this->logVisit($this->request_uri, 'MISS', $gzip);
         }
   
      }
      else{
         $this->logVisit($this->request_uri, 'EXCL', $gzip);
      }
   }


   /*---------------------------------------------------------------------------
     Entrada:
     Salida :
     Efecto : Si la página solicitada por el usuario está entre las que hay
              que cachear, comprueba si hay una copia disponible y la envía,
              finalizándose la ejecución. Si no hay una copia disponible, se
              inicializa el output buffer, para poder luego capturar la salida
              generada por el script.
     ---------------------------------------------------------------------------*/
   function endCachingPage(){
      global $CACHE_CONFIG;
      
      if($this->genereting_output == 1){

         $output = ob_get_contents();
         ob_end_clean();

         $this->insertIntoCache($output, $this->request_uri);

      }
   }
      
   /*----------------------------------------------------------------------
     Entrada: $request => indica la página (uri) o bloque que se quiere comprobar
              $refresh => indica el tiempo de permanencia en cache de la solicitud
              $compressed => indica si se prefiere salida comprimida. Si la
                             solicitud es para un bloque debe ser false!!!
     Salida : Si se consigue obtener (HIT) la solicitud de cache, se devuelve
             un array con el contenido y true o false indicando si
             está comprimido o no. Si no se puede realizar la solicitud (MISS)
             se devuelve un array con FALSE y false como comprimido
    Efecto : a partir de la solicitud y compressed, con md5 se crea el nombre de
             que tendría en cache. Si el archivo existe se compara su fecha con el
             tiempo de permanencia. En el caso de que se solicite comprimido
             y este no exista, se intenta obtener la versión sin comprimir.
    ----------------------------------------------------------------------*/
   function checkCache($request,$refresh,$compressed = '-1'){

      global $CACHE_CONFIG;

      $filename = $CACHE_CONFIG['data_dir'].md5($request);

      if($compressed == '-1') $compressed = $this->gzip_supported;

      if($CACHE_CONFIG['return_compressed'] == 1 && $compressed == 1)
         $filename .= ".gz";

      if(file_exists($filename)){
         if(filemtime($filename) > time()-$refresh){
            $data = fread($fp = fopen($filename, 'r'), filesize($filename));
            fclose($fp);

            return array($data,$compressed);
         }
         else
            return array(0,1);
         
      }
      else if($compressed == 1)
         $this->checkCache($request,$refresh,0);
      else
         return array(0,0);
      
   }

   /*----------------------------------------------------------------------
     Entrada: $content => el contenido
           $request => la solicitud
     Salida : se imprime el contenido que se ha metido en cache
     Efecto : se crea un archivo en el filesystem en base al nombre de la solicitud
           codificándolo con md5. Además si está habilitada la opción de
           guardar comprimido, se guarda el mismo archivo con extensión gz. Esto
           se puede realizar exista o no la función gzcompress, utilizando una
           llamada al shell para gzip.
    ----------------------------------------------------------------------*/
   function insertIntoCache($content, $request){

      global $CACHE_CONFIG;
      
      $content .= "\n<!-- CACHED AT: " . date('Y/m/d : H:m:s') . " BY phpSuperCache -->\n";
      
      $nombre = $CACHE_CONFIG['data_dir'].md5($request);
      
      if($fp = fopen($nombre, 'w')){
         flock($fp, LOCK_EX);
         fwrite($fp,$content);
         flock($fp, LOCK_UN);
         fclose($fp);
         
         if($CACHE_CONFIG['compress_output'] == 1){
         
            if(function_exists('gzcompress')){
               $gzcontent =  "\x1f\x8b\x08\x00\x00\x00\x00\x00";
               $Size = strlen($content); 
               $Crc = crc32($content); 
               $aux = gzcompress($content,$level); 
               $gzcontent .= substr($aux, 0, strlen($aux) - 4); 
               $gzcontent .= pack('V',$Crc); 
               $gzcontent .= pack('V',$Size); 

               $fp = fopen("$nombre.gz",'w');
               flock($fp, LOCK_EX);
               fwrite($fp,$gzcontent);
               flock($fp, LOCK_UN);
               fclose($fp);
            }
            else{
               exec("cp $nombre $nombre.bak;gzip $nombre.bak;mv $nombre.bak.gz $nombre.gz");
			}
         }
         
      }

      echo $content;
      
   }

    /*----------------------------------------------------------------------
      Entrada: $request => indica la solicitud realizada
           $type => el resultado de la solicitud (HIT, MISS, EXCL)
           $compressed => si se ha devuelto el resultado comprimido o no
      Salida : nada
      Efecto : añade una línea al log, si la opción esta activa.
      ----------------------------------------------------------------------*/
   function logVisit($request, $type, $compressed){

      global $CACHE_CONFIG;

      if(!$CACHE_CONFIG['save_stats']) return;

	  if($compressed == 1) $compressed = 'true';
	  else $compressed = 'false';

      $logfile = $CACHE_CONFIG['data_dir'].'stats.log';
      $fp = fopen($logfile, 'a');
      flock($fp, LOCK_EX);
      fseek($fp, filesize($logfile));
	  $salida = sprintf("%-10s %-74s %-4s %-5s\r\n",time(),$request,$type,$compressed);
      //fwrite($fp, time().' '.urlencode($request).' '.$type.' '.$compressed."\r\n");
	  fwrite($fp, $salida);
      flock($fp, LOCK_UN);
      fclose($fp);
   }

   /*----------------------------------------------------------------------
     Entrada: nada
     Salida : nada
     Efecto : elimina los archivos del filesystem correspondientes a cachings viejos
     ----------------------------------------------------------------------*/
   function cacheCleanup(){

      global $CACHE_CONFIG;

      srand((double)microtime()*1000000);
      $num = rand(1,100);
      if($num <= $CACHE_CONFIG['cleanup_freq']){

         $dh = opendir($CACHE_CONFIG['data_dir']);
         while($filename = readdir($dh)){
            if($filename === '.' OR $filename === '..') continue;
            if(filemtime($CACHE_CONFIG['data_dir'].$filename) < time() - $CACHE_CONFIG['max_age'])
               unlink($CACHE_CONFIG['data_dir'].$filename);
         }
      }
      
   }


   /*----------------------------------------------------------------------
     Entrada: un string correspondiente a un nombre de bloque
     Salida : false si el bloque no está en cache y true si lo está. Además en caso
              de que esté en cache, se muestra.
     ----------------------------------------------------------------------*/
   function getCachedBlock($block){
      global $CACHE_TIMINGS;

      list($cached_contents,$gzip) = $this->checkCache($block,$CACHE_TIMINGS[$block],0);

      if($cached_contents){
         
         echo $cached_contents;
         
         $this->logVisit($block, 'HIT', $gzip);
         
         return true;
      }
      else
         return false;
   }

   /*----------------------------------------------------------------------
     Entrada: $block => nombre de bloque
              $contents => el contenido del bloque
     Salida : imprime el contenido
     Efecto : guarda el contenido del bloque en cache y lo imprime. Si el bloque
              no tiene asignado un tiempo de permanencia, se muestra un error.
     ----------------------------------------------------------------------*/
   function setCachedBlock($block,$contents){
      global $CACHE_TIMINGS;

      if(!isset($CACHE_TIMINGS[$block])){
         $this->logVisit($block, 'EXCL', 0);
         return;
      }
      else{
         $this->insertIntoCache($contents,$block);       
         $this->logVisit($block, 'MISS', 0);
     }
      
   }

}

?>
Return current item: phpSuperCache