[ Index ]
 

Code source de Joomla 1.0.13

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/includes/Cache/ -> Lite.php (source)

   1  <?php
   2  
   3  /**
   4  * Fast, light and safe Cache Class
   5  *
   6  * Cache_Lite is a fast, light and safe cache system. It's optimized
   7  * for file containers. It is fast and safe (because it uses file
   8  * locking and/or anti-corruption tests).
   9  *
  10  * There are some examples in the 'docs/examples' file
  11  * Technical choices are described in the 'docs/technical' file
  12  *
  13  * A tutorial is available in english at this url :
  14  * http://www.pearfr.org/index.php/en/article/cache_lite
  15  * (big thanks to Pierre-Alain Joye for the translation)
  16  *
  17  * The same tutorial is also available in french at this url :
  18  * http://www.pearfr.org/index.php/fr/article/cache_lite
  19  *
  20  * Memory Caching is from an original idea of
  21  * Mike BENOIT <ipso@snappymail.ca>
  22  *
  23  * @package Cache_Lite
  24  * @category Caching
  25  * @version $Id: Lite.php 3315 2006-04-26 19:43:05Z stingrey $
  26  * @author Fabien MARTY <fab@php.net>
  27  */
  28  
  29  define('CACHE_LITE_ERROR_RETURN', 1);
  30  define('CACHE_LITE_ERROR_DIE', 8);
  31  
  32  class Cache_Lite
  33  {
  34  
  35      // --- Private properties ---
  36  
  37      /**
  38      * Directory where to put the cache files
  39      * (make sure to add a trailing slash)
  40      *
  41      * @var string $_cacheDir
  42      */
  43      var $_cacheDir = '/tmp/';
  44  
  45      /**
  46      * Enable / disable caching
  47      *
  48      * (can be very usefull for the debug of cached scripts)
  49      *
  50      * @var boolean $_caching
  51      */
  52      var $_caching = true;
  53  
  54      /**
  55      * Cache lifetime (in seconds)
  56      *
  57      * @var int $_lifeTime
  58      */
  59      var $_lifeTime = 3600;
  60  
  61      /**
  62      * Enable / disable fileLocking
  63      *
  64      * (can avoid cache corruption under bad circumstances)
  65      *
  66      * @var boolean $_fileLocking
  67      */
  68      var $_fileLocking = true;
  69  
  70      /**
  71      * Timestamp of the last valid cache
  72      *
  73      * @var int $_refreshTime
  74      */
  75      var $_refreshTime;
  76  
  77      /**
  78      * File name (with path)
  79      *
  80      * @var string $_file
  81      */
  82      var $_file;
  83  
  84      /**
  85      * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
  86      *
  87      * Enable write control will lightly slow the cache writing but not the cache reading
  88      * Write control can detect some corrupt cache files but maybe it's not a perfect control
  89      *
  90      * @var boolean $_writeControl
  91      */
  92      var $_writeControl = true;
  93  
  94      /**
  95      * Enable / disable read control
  96      *
  97      * If enabled, a control key is embeded in cache file and this key is compared with the one
  98      * calculated after the reading.
  99      *
 100      * @var boolean $_writeControl
 101      */
 102      var $_readControl = true;
 103  
 104      /**
 105      * Type of read control (only if read control is enabled)
 106      *
 107      * Available values are :
 108      * 'md5' for a md5 hash control (best but slowest)
 109      * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
 110      * 'strlen' for a length only test (fastest)
 111      *
 112      * @var boolean $_readControlType
 113      */
 114      var $_readControlType = 'crc32';
 115  
 116      /**
 117      * Pear error mode (when raiseError is called)
 118      *
 119      * (see PEAR doc)
 120      *
 121      * @see setToDebug()
 122      * @var int $_pearErrorMode
 123      */
 124      var $_pearErrorMode = CACHE_LITE_ERROR_RETURN;
 125  
 126      /**
 127      * Current cache id
 128      *
 129      * @var string $_id
 130      */
 131      var $_id;
 132  
 133      /**
 134      * Current cache group
 135      *
 136      * @var string $_group
 137      */
 138      var $_group;
 139  
 140      /**
 141      * Enable / Disable "Memory Caching"
 142      *
 143      * NB : There is no lifetime for memory caching !
 144      *
 145      * @var boolean $_memoryCaching
 146      */
 147      var $_memoryCaching = false;
 148  
 149      /**
 150      * Enable / Disable "Only Memory Caching"
 151      * (be carefull, memory caching is "beta quality")
 152      *
 153      * @var boolean $_onlyMemoryCaching
 154      */
 155      var $_onlyMemoryCaching = false;
 156  
 157      /**
 158      * Memory caching array
 159      *
 160      * @var array $_memoryCachingArray
 161      */
 162      var $_memoryCachingArray = array();
 163  
 164      /**
 165      * Memory caching counter
 166      *
 167      * @var int $memoryCachingCounter
 168      */
 169      var $_memoryCachingCounter = 0;
 170  
 171      /**
 172      * Memory caching limit
 173      *
 174      * @var int $memoryCachingLimit
 175      */
 176      var $_memoryCachingLimit = 1000;
 177  
 178      /**
 179      * File Name protection
 180      *
 181      * if set to true, you can use any cache id or group name
 182      * if set to false, it can be faster but cache ids and group names
 183      * will be used directly in cache file names so be carefull with
 184      * special characters...
 185      *
 186      * @var boolean $fileNameProtection
 187      */
 188      var $_fileNameProtection = true;
 189  
 190      /**
 191      * Enable / disable automatic serialization
 192      *
 193      * it can be used to save directly datas which aren't strings
 194      * (but it's slower)
 195      *
 196      * @var boolean $_serialize
 197      */
 198      var $_automaticSerialization = false;
 199  
 200      // --- Public methods ---
 201  
 202      /**
 203      * Constructor
 204      *
 205      * $options is an assoc. Available options are :
 206      * $options = array(
 207      *     'cacheDir' => directory where to put the cache files (string),
 208      *     'caching' => enable / disable caching (boolean),
 209      *     'lifeTime' => cache lifetime in seconds (int),
 210      *     'fileLocking' => enable / disable fileLocking (boolean),
 211      *     'writeControl' => enable / disable write control (boolean),
 212      *     'readControl' => enable / disable read control (boolean),
 213      *     'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
 214      *     'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
 215      *     'memoryCaching' => enable / disable memory caching (boolean),
 216      *     'onlyMemoryCaching' => enable / disable only memory caching (boolean),
 217      *     'memoryCachingLimit' => max nbr of records to store into memory caching (int),
 218      *     'fileNameProtection' => enable / disable automatic file name protection (boolean),
 219      *     'automaticSerialization' => enable / disable automatic serialization (boolean)
 220      * );
 221      *
 222      * @param array $options options
 223      * @access public
 224      */
 225  	function Cache_Lite($options = array(NULL))
 226      {
 227          $availableOptions = array('automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
 228          foreach($options as $key => $value) {
 229              if(in_array($key, $availableOptions)) {
 230                  $property = '_'.$key;
 231                  $this->$property = $value;
 232              }
 233          }
 234          $this->_refreshTime = time() - $this->_lifeTime;
 235      }
 236  
 237      /**
 238      * Test if a cache is available and (if yes) return it
 239      *
 240      * @param string $id cache id
 241      * @param string $group name of the cache group
 242      * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
 243      * @return string data of the cache (or false if no cache available)
 244      * @access public
 245      */
 246  	function get($id, $group = 'default', $doNotTestCacheValidity = false)
 247      {
 248          $this->_id = $id;
 249          $this->_group = $group;
 250          $data = false;
 251          if ($this->_caching) {
 252              $this->_setFileName($id, $group);
 253              if ($this->_memoryCaching) {
 254                  if (isset($this->_memoryCachingArray[$this->_file])) {
 255                      if ($this->_automaticSerialization) {
 256                          return unserialize($this->_memoryCachingArray[$this->_file]);
 257                      } else {
 258                          return $this->_memoryCachingArray[$this->_file];
 259                      }
 260                  } else {
 261                      if ($this->_onlyMemoryCaching) {
 262                          return false;
 263                      }
 264                  }
 265              }
 266              if ($doNotTestCacheValidity) {
 267                  if (file_exists($this->_file)) {
 268                      $data = $this->_read();
 269                  }
 270              } else {
 271                  if (@filemtime($this->_file) > $this->_refreshTime) {
 272                      $data = $this->_read();
 273                  }
 274              }
 275              if (($data) and ($this->_memoryCaching)) {
 276                  $this->_memoryCacheAdd($this->_file, $data);
 277              }
 278              if (($this->_automaticSerialization) and (is_string($data))) {
 279                  $data = unserialize($data);
 280              }
 281              return $data;
 282          }
 283          return false;
 284      }
 285  
 286      /**
 287      * Save some data in a cache file
 288      *
 289      * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
 290      * @param string $id cache id
 291      * @param string $group name of the cache group
 292      * @return boolean true if no problem
 293      * @access public
 294      */
 295  	function save($data, $id = NULL, $group = 'default')
 296      {
 297          if ($this->_caching) {
 298              if ($this->_automaticSerialization) {
 299                  $data = serialize($data);
 300              }
 301              if (isset($id)) {
 302                  $this->_setFileName($id, $group);
 303              }
 304              if ($this->_memoryCaching) {
 305                  $this->_memoryCacheAdd($this->_file, $data);
 306                  if ($this->_onlyMemoryCaching) {
 307                      return true;
 308                  }
 309              }
 310              if ($this->_writeControl) {
 311                  if (!$this->_writeAndControl($data)) {
 312                      @touch($this->_file, time() - 2*abs($this->_lifeTime));
 313                      return false;
 314                  } else {
 315                      return true;
 316                  }
 317              } else {
 318                  return $this->_write($data);
 319              }
 320          }
 321          return false;
 322      }
 323  
 324      /**
 325      * Remove a cache file
 326      *
 327      * @param string $id cache id
 328      * @param string $group name of the cache group
 329      * @return boolean true if no problem
 330      * @access public
 331      */
 332  	function remove($id, $group = 'default')
 333      {
 334          $this->_setFileName($id, $group);
 335          if (!@unlink($this->_file)) {
 336              $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
 337              return false;
 338          }
 339          return true;
 340      }
 341  
 342      /**
 343      * Clean the cache
 344      *
 345      * if no group is specified all cache files will be destroyed
 346      * else only cache files of the specified group will be destroyed
 347      *
 348      * @param string $group name of the cache group
 349      * @return boolean true if no problem
 350      * @access public
 351      */
 352  	function clean($group = false)
 353      {
 354          if ($this->_fileNameProtection) {
 355              $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
 356          } else {
 357              $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
 358          }
 359          if ($this->_memoryCaching) {
 360              while (list($key, $value) = each($this->_memoryCaching)) {
 361                  if (strpos($key, $motif, 0)) {
 362                      unset($this->_memoryCaching[$key]);
 363                      $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
 364                  }
 365              }
 366              if ($this->_onlyMemoryCaching) {
 367                  return true;
 368              }
 369          }
 370          if (!($dh = opendir($this->_cacheDir))) {
 371              $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
 372              return false;
 373          }
 374          while ($file = readdir($dh)) {
 375              if (($file != '.') && ($file != '..')) {
 376                  $file = $this->_cacheDir . $file;
 377                  if (is_file($file)) {
 378                      if (strpos($file, $motif, 0)) {
 379                          if (!@unlink($file)) {
 380                              $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
 381                              return false;
 382                          }
 383                      }
 384                  }
 385              }
 386          }
 387          return true;
 388      }
 389  
 390      /**
 391      * Set to debug mode
 392      *
 393      * When an error is found, the script will stop and the message will be displayed
 394      * (in debug mode only).
 395      *
 396      * @access public
 397      */
 398  	function setToDebug()
 399      {
 400          $this->_pearErrorMode = CACHE_LITE_ERROR_DIE;
 401      }
 402  
 403      /**
 404      * Set a new life time
 405      *
 406      * @param int $newLifeTime new life time (in seconds)
 407      * @access public
 408      */
 409  	function setLifeTime($newLifeTime)
 410      {
 411          $this->_lifeTime = $newLifeTime;
 412          $this->_refreshTime = time() - $newLifeTime;
 413      }
 414  
 415      /**
 416      *
 417      * @access public
 418      */
 419  	function saveMemoryCachingState($id, $group = 'default')
 420      {
 421          if ($this->_caching) {
 422              $array = array(
 423                  'counter' => $this->_memoryCachingCounter,
 424                  'array' => $this->_memoryCachingState
 425              );
 426              $data = serialize($array);
 427              $this->save($data, $id, $group);
 428          }
 429      }
 430  
 431      /**
 432      *
 433      * @access public
 434      */
 435  	function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
 436      {
 437          if ($this->_caching) {
 438              if ($data = $this->get($id, $group, $doNotTestCacheValidity)) {
 439                  $array = unserialize($data);
 440                  $this->_memoryCachingCounter = $array['counter'];
 441                  $this->_memoryCachingArray = $array['array'];
 442              }
 443          }
 444      }
 445  
 446      /**
 447      * Return the cache last modification time
 448      *
 449      * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
 450      *
 451      * @return int last modification time
 452      */
 453  	function lastModified() {
 454          return filemtime($this->_file);
 455      }
 456  
 457      /**
 458      * Trigger a PEAR error
 459      *
 460      * To improve performances, the PEAR.php file is included dynamically.
 461      * The file is so included only when an error is triggered. So, in most
 462      * cases, the file isn't included and perfs are much better.
 463      *
 464      * @param string $msg error message
 465      * @param int $code error code
 466      * @access public
 467      */
 468  	function raiseError($msg, $code) {
 469          $path = dirname( __FILE__ ) . DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'PEAR'. DIRECTORY_SEPARATOR .'PEAR.php';
 470          
 471          if ( file_exists( $path ) ) {            
 472              include_once( $path );
 473              PEAR::raiseError($msg, $code, $this->_pearErrorMode);
 474          }
 475      }
 476  
 477      // --- Private methods ---
 478  
 479      /**
 480      *
 481      * @access private
 482      */
 483  	function _memoryCacheAdd($id, $data)
 484      {
 485          $this->_memoryCachingArray[$this->_file] = $data;
 486          if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
 487              list($key, $value) = each($this->_memoryCachingArray);
 488              unset($this->_memoryCachingArray[$key]);
 489          } else {
 490              $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
 491          }
 492      }
 493  
 494      /**
 495      * Make a file name (with path)
 496      *
 497      * @param string $id cache id
 498      * @param string $group name of the group
 499      * @access private
 500      */
 501  	function _setFileName($id, $group)
 502      {
 503          if ($this->_fileNameProtection) {
 504              $this->_file = ($this->_cacheDir.'cache_'.md5($group).'_'.md5($id));
 505          } else {
 506              $this->_file = $this->_cacheDir.'cache_'.$group.'_'.$id;
 507          }
 508      }
 509  
 510      /**
 511      * Read the cache file and return the content
 512      *
 513      * @return string content of the cache file
 514      * @access private
 515      */
 516  	function _read()
 517      {
 518          $fp = @fopen($this->_file, "rb");
 519          if ($this->_fileLocking) @flock($fp, LOCK_SH);
 520          if ($fp) {
 521              clearstatcache(); // because the filesize can be cached by PHP itself...
 522              $length = @filesize($this->_file);
 523              $mqr = get_magic_quotes_runtime();
 524              set_magic_quotes_runtime(0);
 525              if ($this->_readControl) {
 526                  $hashControl = @fread($fp, 32);
 527                  $length = $length - 32;
 528              }
 529              $data = @fread($fp, $length);
 530              set_magic_quotes_runtime($mqr);
 531              if ($this->_fileLocking) @flock($fp, LOCK_UN);
 532              @fclose($fp);
 533              if ($this->_readControl) {
 534                  $hashData = $this->_hash($data, $this->_readControlType);
 535                  if ($hashData != $hashControl) {
 536                      @touch($this->_file, time() - 2*abs($this->_lifeTime));
 537                      return false;
 538                  }
 539              }
 540              return $data;
 541          }
 542          $this->raiseError('Cache_Lite : Unable to read cache !', -2);
 543          return false;
 544      }
 545  
 546      /**
 547      * Write the given data in the cache file
 548      *
 549      * @param string $data data to put in cache
 550      * @return boolean true if ok
 551      * @access private
 552      */
 553  	function _write($data)
 554      {
 555          $fp = @fopen($this->_file, "wb");
 556          if ($fp) {
 557              if ($this->_fileLocking) @flock($fp, LOCK_EX);
 558              if ($this->_readControl) {
 559                  @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
 560              }
 561              $len = strlen($data);
 562              @fwrite($fp, $data, $len);
 563              if ($this->_fileLocking) @flock($fp, LOCK_UN);
 564              @fclose($fp);
 565              return true;
 566          }
 567          $this->raiseError('Cache_Lite : Unable to write cache !', -1);
 568          return false;
 569      }
 570  
 571      /**
 572      * Write the given data in the cache file and control it just after to avoir corrupted cache entries
 573      *
 574      * @param string $data data to put in cache
 575      * @return boolean true if the test is ok
 576      * @access private
 577      */
 578  	function _writeAndControl($data)
 579      {
 580          $this->_write($data);
 581          $dataRead = $this->_read($data);
 582          return ($dataRead==$data);
 583      }
 584  
 585      /**
 586      * Make a control key with the string containing datas
 587      *
 588      * @param string $data data
 589      * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
 590      * @return string control key
 591      * @access private
 592      */
 593  	function _hash($data, $controlType)
 594      {
 595          switch ($controlType) {
 596          case 'md5':
 597              return md5($data);
 598          case 'crc32':
 599              return sprintf('% 32d', crc32($data));
 600          case 'strlen':
 601              return sprintf('% 32d', strlen($data));
 602          default:
 603              $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
 604          }
 605      }
 606  
 607  }
 608  
 609  ?>


Généré le : Wed Nov 21 14:43:32 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics