phpDocumentor Cache_Lite
[ class tree: Cache_Lite ] [ index: Cache_Lite ] [ all elements ]

Source for file Lite.php

Documentation is available at Lite.php

  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. * Memory Caching is from an original idea of
  14. * Mike BENOIT <ipso@snappymail.ca>
  15. *
  16. * Nota : A chinese documentation (thanks to RainX <china_1982@163.com>) is
  17. * available at :
  18. * http://rainx.phpmore.com/manual/cache_lite.html
  19. *
  20. @package Cache_Lite
  21. @category Caching
  22. @version $Id: Lite.php,v 1.51 2008/06/08 08:46:22 tacker Exp $
  23. @author Fabien MARTY <fab@php.net>
  24. */
  25.  
  26. define('CACHE_LITE_ERROR_RETURN'1);
  27. define('CACHE_LITE_ERROR_DIE'8);
  28.  
  29. class Cache_Lite
  30. {
  31.  
  32.     // --- Private properties ---
  33.  
  34.     /**
  35.     * Directory where to put the cache files
  36.     * (make sure to add a trailing slash)
  37.     *
  38.     * @var string $_cacheDir 
  39.     */
  40.     var $_cacheDir = '/tmp/';
  41.  
  42.     /**
  43.     * Enable / disable caching
  44.     *
  45.     * (can be very usefull for the debug of cached scripts)
  46.     *
  47.     * @var boolean $_caching 
  48.     */
  49.     var $_caching = true;
  50.  
  51.     /**
  52.     * Cache lifetime (in seconds)
  53.     *
  54.     * If null, the cache is valid forever.
  55.     *
  56.     * @var int $_lifeTime 
  57.     */
  58.     var $_lifeTime = 3600;
  59.  
  60.     /**
  61.     * Enable / disable fileLocking
  62.     *
  63.     * (can avoid cache corruption under bad circumstances)
  64.     *
  65.     * @var boolean $_fileLocking 
  66.     */
  67.     var $_fileLocking = true;
  68.  
  69.     /**
  70.     * Timestamp of the last valid cache
  71.     *
  72.     * @var int $_refreshTime 
  73.     */
  74.     var $_refreshTime;
  75.  
  76.     /**
  77.     * File name (with path)
  78.     *
  79.     * @var string $_file 
  80.     */
  81.     var $_file;
  82.     
  83.     /**
  84.     * File name (without path)
  85.     *
  86.     * @var string $_fileName 
  87.     */
  88.     var $_fileName;
  89.  
  90.     /**
  91.     * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
  92.     *
  93.     * Enable write control will lightly slow the cache writing but not the cache reading
  94.     * Write control can detect some corrupt cache files but maybe it's not a perfect control
  95.     *
  96.     * @var boolean $_writeControl 
  97.     */
  98.     var $_writeControl = true;
  99.  
  100.     /**
  101.     * Enable / disable read control
  102.     *
  103.     * If enabled, a control key is embeded in cache file and this key is compared with the one
  104.     * calculated after the reading.
  105.     *
  106.     * @var boolean $_writeControl 
  107.     */
  108.     var $_readControl = true;
  109.  
  110.     /**
  111.     * Type of read control (only if read control is enabled)
  112.     *
  113.     * Available values are :
  114.     * 'md5' for a md5 hash control (best but slowest)
  115.     * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
  116.     * 'strlen' for a length only test (fastest)
  117.     *
  118.     * @var boolean $_readControlType 
  119.     */
  120.     var $_readControlType = 'crc32';
  121.  
  122.     /**
  123.     * Pear error mode (when raiseError is called)
  124.     *
  125.     * (see PEAR doc)
  126.     *
  127.     * @see setToDebug()
  128.     * @var int $_pearErrorMode 
  129.     */
  130.     var $_pearErrorMode = CACHE_LITE_ERROR_RETURN;
  131.     
  132.     /**
  133.     * Current cache id
  134.     *
  135.     * @var string $_id 
  136.     */
  137.     var $_id;
  138.  
  139.     /**
  140.     * Current cache group
  141.     *
  142.     * @var string $_group 
  143.     */
  144.     var $_group;
  145.  
  146.     /**
  147.     * Enable / Disable "Memory Caching"
  148.     *
  149.     * NB : There is no lifetime for memory caching !
  150.     *
  151.     * @var boolean $_memoryCaching 
  152.     */
  153.     var $_memoryCaching = false;
  154.  
  155.     /**
  156.     * Enable / Disable "Only Memory Caching"
  157.     * (be carefull, memory caching is "beta quality")
  158.     *
  159.     * @var boolean $_onlyMemoryCaching 
  160.     */
  161.     var $_onlyMemoryCaching = false;
  162.  
  163.     /**
  164.     * Memory caching array
  165.     *
  166.     * @var array $_memoryCachingArray 
  167.     */
  168.     var $_memoryCachingArray = array();
  169.  
  170.     /**
  171.     * Memory caching counter
  172.     *
  173.     * @var int $memoryCachingCounter 
  174.     */
  175.     var $_memoryCachingCounter = 0;
  176.  
  177.     /**
  178.     * Memory caching limit
  179.     *
  180.     * @var int $memoryCachingLimit 
  181.     */
  182.     var $_memoryCachingLimit = 1000;
  183.     
  184.     /**
  185.     * File Name protection
  186.     *
  187.     * if set to true, you can use any cache id or group name
  188.     * if set to false, it can be faster but cache ids and group names
  189.     * will be used directly in cache file names so be carefull with
  190.     * special characters...
  191.     *
  192.     * @var boolean $fileNameProtection 
  193.     */
  194.     var $_fileNameProtection = true;
  195.     
  196.     /**
  197.     * Enable / disable automatic serialization
  198.     *
  199.     * it can be used to save directly datas which aren't strings
  200.     * (but it's slower)
  201.     *
  202.     * @var boolean $_serialize 
  203.     */
  204.     var $_automaticSerialization = false;
  205.     
  206.     /**
  207.     * Disable / Tune the automatic cleaning process
  208.     *
  209.     * The automatic cleaning process destroy too old (for the given life time)
  210.     * cache files when a new cache file is written.
  211.     * 0               => no automatic cache cleaning
  212.     * 1               => systematic cache cleaning
  213.     * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
  214.     *
  215.     * @var int $_automaticCleaning 
  216.     */
  217.     var $_automaticCleaningFactor = 0;
  218.     
  219.     /**
  220.     * Nested directory level
  221.     *
  222.     * Set the hashed directory structure level. 0 means "no hashed directory
  223.     * structure", 1 means "one level of directory", 2 means "two levels"...
  224.     * This option can speed up Cache_Lite only when you have many thousands of
  225.     * cache file. Only specific benchs can help you to choose the perfect value
  226.     * for you. Maybe, 1 or 2 is a good start.
  227.     *
  228.     * @var int $_hashedDirectoryLevel 
  229.     */
  230.     var $_hashedDirectoryLevel = 0;
  231.     
  232.     /**
  233.     * Umask for hashed directory structure
  234.     *
  235.     * @var int $_hashedDirectoryUmask 
  236.     */
  237.     var $_hashedDirectoryUmask = 0700;
  238.     
  239.     /**
  240.      * API break for error handling in CACHE_LITE_ERROR_RETURN mode
  241.      * 
  242.      * In CACHE_LITE_ERROR_RETURN mode, error handling was not good because
  243.      * for example save() method always returned a boolean (a PEAR_Error object
  244.      * would be better in CACHE_LITE_ERROR_RETURN mode). To correct this without
  245.      * breaking the API, this option (false by default) can change this handling.
  246.      * 
  247.      * @var boolean 
  248.      */
  249.     var $_errorHandlingAPIBreak = false;
  250.     
  251.     // --- Public methods ---
  252.  
  253.     /**
  254.     * Constructor
  255.     *
  256.     * $options is an assoc. Available options are :
  257.     * $options = array(
  258.     *     'cacheDir' => directory where to put the cache files (string),
  259.     *     'caching' => enable / disable caching (boolean),
  260.     *     'lifeTime' => cache lifetime in seconds (int),
  261.     *     'fileLocking' => enable / disable fileLocking (boolean),
  262.     *     'writeControl' => enable / disable write control (boolean),
  263.     *     'readControl' => enable / disable read control (boolean),
  264.     *     'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
  265.     *     'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
  266.     *     'memoryCaching' => enable / disable memory caching (boolean),
  267.     *     'onlyMemoryCaching' => enable / disable only memory caching (boolean),
  268.     *     'memoryCachingLimit' => max nbr of records to store into memory caching (int),
  269.     *     'fileNameProtection' => enable / disable automatic file name protection (boolean),
  270.     *     'automaticSerialization' => enable / disable automatic serialization (boolean),
  271.     *     'automaticCleaningFactor' => distable / tune automatic cleaning process (int),
  272.     *     'hashedDirectoryLevel' => level of the hashed directory system (int),
  273.     *     'hashedDirectoryUmask' => umask for hashed directory structure (int),
  274.     *     'errorHandlingAPIBreak' => API break for better error handling ? (boolean)
  275.     * );
  276.     *
  277.     * @param array $options options
  278.     * @access public
  279.     */
  280.     function Cache_Lite($options array(NULL))
  281.     {
  282.         foreach($options as $key => $value{
  283.             $this->setOption($key$value);
  284.         }
  285.     }
  286.     
  287.     /**
  288.     * Generic way to set a Cache_Lite option
  289.     *
  290.     * see Cache_Lite constructor for available options
  291.     *
  292.     * @var string $name name of the option
  293.     * @var mixed $value value of the option
  294.     * @access public
  295.     */
  296.     function setOption($name$value
  297.     {
  298.         $availableOptions array('errorHandlingAPIBreak''hashedDirectoryUmask''hashedDirectoryLevel''automaticCleaningFactor''automaticSerialization''fileNameProtection''memoryCaching''onlyMemoryCaching''memoryCachingLimit''cacheDir''caching''lifeTime''fileLocking''writeControl''readControl''readControlType''pearErrorMode');
  299.         if (in_array($name$availableOptions)) {
  300.             $property '_'.$name;
  301.             $this->$property $value;
  302.         }
  303.     }
  304.     
  305.     /**
  306.     * Test if a cache is available and (if yes) return it
  307.     *
  308.     * @param string $id cache id
  309.     * @param string $group name of the cache group
  310.     * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
  311.     * @return string data of the cache (else : false)
  312.     * @access public
  313.     */
  314.     function get($id$group 'default'$doNotTestCacheValidity false)
  315.     {
  316.         $this->_id = $id;
  317.         $this->_group = $group;
  318.         $data false;
  319.         if ($this->_caching{
  320.             $this->_setRefreshTime();
  321.             $this->_setFileName($id$group);
  322.             clearstatcache();
  323.             if ($this->_memoryCaching{
  324.                 if (isset($this->_memoryCachingArray[$this->_file])) {
  325.                     if ($this->_automaticSerialization{
  326.                         return unserialize($this->_memoryCachingArray[$this->_file]);
  327.                     }
  328.                     return $this->_memoryCachingArray[$this->_file];
  329.                 }
  330.                 if ($this->_onlyMemoryCaching{
  331.                     return false;
  332.                 }                
  333.             }
  334.             if (($doNotTestCacheValidity|| (is_null($this->_refreshTime))) {
  335.                 if (file_exists($this->_file)) {
  336.                     $data $this->_read();
  337.                 }
  338.             else {
  339.                 if ((file_exists($this->_file)) && (@filemtime($this->_file$this->_refreshTime)) {
  340.                     $data $this->_read();
  341.                 }
  342.             }
  343.             if (($dataand ($this->_memoryCaching)) {
  344.                 $this->_memoryCacheAdd($data);
  345.             }
  346.             if (($this->_automaticSerializationand (is_string($data))) {
  347.                 $data unserialize($data);
  348.             }
  349.             return $data;
  350.         }
  351.         return false;
  352.     }
  353.     
  354.     /**
  355.     * Save some data in a cache file
  356.     *
  357.     * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
  358.     * @param string $id cache id
  359.     * @param string $group name of the cache group
  360.     * @return boolean true if no problem (else : false or a PEAR_Error object)
  361.     * @access public
  362.     */
  363.     function save($data$id NULL$group 'default')
  364.     {
  365.         if ($this->_caching{
  366.             if ($this->_automaticSerialization{
  367.                 $data serialize($data);
  368.             }
  369.             if (isset($id)) {
  370.                 $this->_setFileName($id$group);
  371.             }
  372.             if ($this->_memoryCaching{
  373.                 $this->_memoryCacheAdd($data);
  374.                 if ($this->_onlyMemoryCaching{
  375.                     return true;
  376.                 }
  377.             }
  378.             if ($this->_automaticCleaningFactor>0{
  379.                 $rand rand(1$this->_automaticCleaningFactor);
  380.                 if ($rand==1{
  381.                     $this->clean(false'old');
  382.                 }
  383.             }
  384.             if ($this->_writeControl{
  385.                 $res $this->_writeAndControl($data);
  386.                 if (is_bool($res)) {
  387.                     if ($res{
  388.                         return true;  
  389.                     }
  390.                     // if $res if false, we need to invalidate the cache
  391.                     @touch($this->_filetime(2*abs($this->_lifeTime));
  392.                     return false;
  393.                 }            
  394.             else {
  395.                 $res $this->_write($data);
  396.             }
  397.             if (is_object($res)) {
  398.                 // $res is a PEAR_Error object 
  399.                 if (!($this->_errorHandlingAPIBreak)) {   
  400.                     return false// we return false (old API)
  401.                 }
  402.             }
  403.             return $res;
  404.         }
  405.         return false;
  406.     }
  407.  
  408.     /**
  409.     * Remove a cache file
  410.     *
  411.     * @param string $id cache id
  412.     * @param string $group name of the cache group
  413.     * @param boolean $checkbeforeunlink check if file exists before removing it
  414.     * @return boolean true if no problem
  415.     * @access public
  416.     */
  417.     function remove($id$group 'default'$checkbeforeunlink false)
  418.     {
  419.         $this->_setFileName($id$group);
  420.         if ($this->_memoryCaching{
  421.             if (isset($this->_memoryCachingArray[$this->_file])) {
  422.                 unset($this->_memoryCachingArray[$this->_file]);
  423.                 $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
  424.             }
  425.             if ($this->_onlyMemoryCaching{
  426.                 return true;
  427.             }
  428.         }
  429.         if $checkbeforeunlink {
  430.             if (!file_exists($this->_file)) return true;
  431.         }
  432.         return $this->_unlink($this->_file);
  433.     }
  434.  
  435.     /**
  436.     * Clean the cache
  437.     *
  438.     * if no group is specified all cache files will be destroyed
  439.     * else only cache files of the specified group will be destroyed
  440.     *
  441.     * @param string $group name of the cache group
  442.     * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
  443.     *                                         'callback_myFunction'
  444.     * @return boolean true if no problem
  445.     * @access public
  446.     */
  447.     function clean($group false$mode 'ingroup')
  448.     {
  449.         return $this->_cleanDir($this->_cacheDir$group$mode);
  450.     }
  451.        
  452.     /**
  453.     * Set to debug mode
  454.     *
  455.     * When an error is found, the script will stop and the message will be displayed
  456.     * (in debug mode only).
  457.     *
  458.     * @access public
  459.     */
  460.     function setToDebug()
  461.     {
  462.         $this->setOption('pearErrorMode'CACHE_LITE_ERROR_DIE);
  463.     }
  464.  
  465.     /**
  466.     * Set a new life time
  467.     *
  468.     * @param int $newLifeTime new life time (in seconds)
  469.     * @access public
  470.     */
  471.     function setLifeTime($newLifeTime)
  472.     {
  473.         $this->_lifeTime = $newLifeTime;
  474.         $this->_setRefreshTime();
  475.     }
  476.  
  477.     /**
  478.     * Save the state of the caching memory array into a cache file cache
  479.     *
  480.     * @param string $id cache id
  481.     * @param string $group name of the cache group
  482.     * @access public
  483.     */
  484.     function saveMemoryCachingState($id$group 'default')
  485.     {
  486.         if ($this->_caching{
  487.             $array array(
  488.                 'counter' => $this->_memoryCachingCounter,
  489.                 'array' => $this->_memoryCachingArray
  490.             );
  491.             $data serialize($array);
  492.             $this->save($data$id$group);
  493.         }
  494.     }
  495.  
  496.     /**
  497.     * Load the state of the caching memory array from a given cache file cache
  498.     *
  499.     * @param string $id cache id
  500.     * @param string $group name of the cache group
  501.     * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
  502.     * @access public
  503.     */
  504.     function getMemoryCachingState($id$group 'default'$doNotTestCacheValidity false)
  505.     {
  506.         if ($this->_caching{
  507.             if ($data $this->get($id$group$doNotTestCacheValidity)) {
  508.                 $array unserialize($data);
  509.                 $this->_memoryCachingCounter = $array['counter'];
  510.                 $this->_memoryCachingArray = $array['array'];
  511.             }
  512.         }
  513.     }
  514.     
  515.     /**
  516.     * Return the cache last modification time
  517.     *
  518.     * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
  519.     *
  520.     * @return int last modification time
  521.     */
  522.     function lastModified(
  523.     {
  524.         return @filemtime($this->_file);
  525.     }
  526.     
  527.     /**
  528.     * Trigger a PEAR error
  529.     *
  530.     * To improve performances, the PEAR.php file is included dynamically.
  531.     * The file is so included only when an error is triggered. So, in most
  532.     * cases, the file isn't included and perfs are much better.
  533.     *
  534.     * @param string $msg error message
  535.     * @param int $code error code
  536.     * @access public
  537.     */
  538.     function raiseError($msg$code)
  539.     {
  540.         include_once('PEAR.php');
  541.         return PEAR::raiseError($msg$code$this->_pearErrorMode);
  542.     }
  543.     
  544.     /**
  545.      * Extend the life of a valid cache file
  546.      * 
  547.      * see http://pear.php.net/bugs/bug.php?id=6681
  548.      * 
  549.      * @access public
  550.      */
  551.     function extendLife()
  552.     {
  553.         @touch($this->_file);
  554.     }
  555.     
  556.     // --- Private methods ---
  557.     
  558.     /**
  559.     * Compute & set the refresh time
  560.     *
  561.     * @access private
  562.     */
  563.     function _setRefreshTime(
  564.     {
  565.         if (is_null($this->_lifeTime)) {
  566.             $this->_refreshTime = null;
  567.         else {
  568.             $this->_refreshTime = time($this->_lifeTime;
  569.         }
  570.     }
  571.     
  572.     /**
  573.     * Remove a file
  574.     * 
  575.     * @param string $file complete file path and name
  576.     * @return boolean true if no problem
  577.     * @access private
  578.     */
  579.     function _unlink($file)
  580.     {
  581.         if (!@unlink($file)) {
  582.             return $this->raiseError('Cache_Lite : Unable to remove cache !'-3);
  583.         }
  584.         return true;        
  585.     }
  586.