home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Cache / Lite.php < prev    next >
Encoding:
PHP Script  |  2006-04-07  |  25.5 KB  |  828 lines

  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.42 2006/02/04 17:08:22 fab 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 (($data) and ($this->_memoryCaching)) {
  344.                 $this->_memoryCacheAdd($data);
  345.             }
  346.             if (($this->_automaticSerialization) and (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->_file, time() - 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.     * @return boolean true if no problem
  414.     * @access public
  415.     */
  416.     function remove($id, $group = 'default')
  417.     {
  418.         $this->_setFileName($id, $group);
  419.         if ($this->_memoryCaching) {
  420.             if (isset($this->_memoryCachingArray[$this->_file])) {
  421.                 unset($this->_memoryCachingArray[$this->_file]);
  422.                 $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
  423.             }
  424.             if ($this->_onlyMemoryCaching) {
  425.                 return true;
  426.             }
  427.         }
  428.         return $this->_unlink($this->_file);
  429.     }
  430.  
  431.     /**
  432.     * Clean the cache
  433.     *
  434.     * if no group is specified all cache files will be destroyed
  435.     * else only cache files of the specified group will be destroyed
  436.     *
  437.     * @param string $group name of the cache group
  438.     * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', 
  439.     *                                        'callback_myFunction'
  440.     * @return boolean true if no problem
  441.     * @access public
  442.     */
  443.     function clean($group = false, $mode = 'ingroup')
  444.     {
  445.         return $this->_cleanDir($this->_cacheDir, $group, $mode);
  446.     }
  447.        
  448.     /**
  449.     * Set to debug mode
  450.     *
  451.     * When an error is found, the script will stop and the message will be displayed
  452.     * (in debug mode only). 
  453.     *
  454.     * @access public
  455.     */
  456.     function setToDebug()
  457.     {
  458.         $this->setOptions('pearErrorMode', CACHE_LITE_ERROR_DIE);
  459.     }
  460.  
  461.     /**
  462.     * Set a new life time
  463.     *
  464.     * @param int $newLifeTime new life time (in seconds)
  465.     * @access public
  466.     */
  467.     function setLifeTime($newLifeTime)
  468.     {
  469.         $this->_lifeTime = $newLifeTime;
  470.         $this->_setRefreshTime();
  471.     }
  472.  
  473.     /**
  474.     * Save the state of the caching memory array into a cache file cache
  475.     *
  476.     * @param string $id cache id
  477.     * @param string $group name of the cache group
  478.     * @access public
  479.     */
  480.     function saveMemoryCachingState($id, $group = 'default')
  481.     {
  482.         if ($this->_caching) {
  483.             $array = array(
  484.                 'counter' => $this->_memoryCachingCounter,
  485.                 'array' => $this->_memoryCachingState
  486.             );
  487.             $data = serialize($array);
  488.             $this->save($data, $id, $group);
  489.         }
  490.     }
  491.  
  492.     /**
  493.     * Load the state of the caching memory array from a given cache file cache
  494.     *
  495.     * @param string $id cache id
  496.     * @param string $group name of the cache group
  497.     * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
  498.     * @access public
  499.     */
  500.     function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
  501.     {
  502.         if ($this->_caching) {
  503.             if ($data = $this->get($id, $group, $doNotTestCacheValidity)) {
  504.                 $array = unserialize($data);
  505.                 $this->_memoryCachingCounter = $array['counter'];
  506.                 $this->_memoryCachingArray = $array['array'];
  507.             }
  508.         }
  509.     }
  510.     
  511.     /**
  512.     * Return the cache last modification time
  513.     *
  514.     * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
  515.     *
  516.     * @return int last modification time
  517.     */
  518.     function lastModified() 
  519.     {
  520.         return @filemtime($this->_file);
  521.     }
  522.     
  523.     /**
  524.     * Trigger a PEAR error
  525.     *
  526.     * To improve performances, the PEAR.php file is included dynamically.
  527.     * The file is so included only when an error is triggered. So, in most
  528.     * cases, the file isn't included and perfs are much better.
  529.     *
  530.     * @param string $msg error message
  531.     * @param int $code error code
  532.     * @access public
  533.     */
  534.     function raiseError($msg, $code)
  535.     {
  536.         include_once('PEAR.php');
  537.         return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
  538.     }
  539.     
  540.     /**
  541.      * Extend the life of a valid cache file
  542.      * 
  543.      * see http://pear.php.net/bugs/bug.php?id=6681
  544.      * 
  545.      * @access public
  546.      */
  547.     function extendLife()
  548.     {
  549.         @touch($this->_file);
  550.     }
  551.     
  552.     // --- Private methods ---
  553.     
  554.     /**
  555.     * Compute & set the refresh time
  556.     *
  557.     * @access private
  558.     */
  559.     function _setRefreshTime() 
  560.     {
  561.         if (is_null($this->_lifeTime)) {
  562.             $this->_refreshTime = null;
  563.         } else {
  564.             $this->_refreshTime = time() - $this->_lifeTime;
  565.         }
  566.     }
  567.     
  568.     /**
  569.     * Remove a file
  570.     * 
  571.     * @param string $file complete file path and name
  572.     * @return boolean true if no problem
  573.     * @access private
  574.     */
  575.     function _unlink($file)
  576.     {
  577.         if (!@unlink($file)) {
  578.             return $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
  579.         }
  580.         return true;        
  581.     }
  582.  
  583.     /**
  584.     * Recursive function for cleaning cache file in the given directory
  585.     *
  586.     * @param string $dir directory complete path (with a trailing slash)
  587.     * @param string $group name of the cache group
  588.     * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
  589.                                              'callback_myFunction'
  590.     * @return boolean true if no problem
  591.     * @access private
  592.     */
  593.     function _cleanDir($dir, $group = false, $mode = 'ingroup')     
  594.     {
  595.         if ($this->_fileNameProtection) {
  596.             $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
  597.         } else {
  598.             $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
  599.         }
  600.         if ($this->_memoryCaching) {
  601.             while (list($key, ) = each($this->_memoryCachingArray)) {
  602.                 if (strpos($key, $motif, 0)) {
  603.                     unset($this->_memoryCachingArray[$key]);
  604.                     $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
  605.                 }
  606.             }
  607.             if ($this->_onlyMemoryCaching) {
  608.                 return true;
  609.             }
  610.         }
  611.         if (!($dh = opendir($dir))) {
  612.             return $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
  613.         }
  614.         $result = true;
  615.         while ($file = readdir($dh)) {
  616.             if (($file != '.') && ($file != '..')) {
  617.                 if (substr($file, 0, 6)=='cache_') {
  618.                     $file2 = $dir . $file;
  619.                     if (is_file($file2)) {
  620.                         switch (substr($mode, 0, 9)) {
  621.                             case 'old':
  622.                                 // files older than lifeTime get deleted from cache
  623.                                 if (!is_null($this->_lifeTime)) {
  624.                                     if ((mktime() - @filemtime($file2)) > $this->_lifeTime) {
  625.                                         $result = ($result and ($this->_unlink($file2)));
  626.                                     }
  627.                                 }
  628.                                 break;
  629.                             case 'notingrou':
  630.                                 if (!strpos($file2, $motif, 0)) {
  631.                                     $result = ($result and ($this->_unlink($file2)));
  632.                                 }
  633.                                 break;
  634.                             case 'callback_':
  635.                                 $func = substr($mode, 9, strlen($mode) - 9);
  636.                                 if ($func($file2, $group)) {
  637.                                     $result = ($result and ($this->_unlink($file2)));
  638.                                 }
  639.                                 break;
  640.                             case 'ingroup':
  641.                             default:
  642.                                 if (strpos($file2, $motif, 0)) {
  643.                                     $result = ($result and ($this->_unlink($file2)));
  644.                                 }
  645.                                 break;
  646.                         }
  647.                     }
  648.                     if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) {
  649.                         $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode)));
  650.                     }
  651.                 }
  652.             }
  653.         }
  654.         return $result;
  655.     }
  656.       
  657.     /**
  658.     * Add some date in the memory caching array
  659.     *
  660.     * @param string $data data to cache
  661.     * @access private
  662.     */
  663.     function _memoryCacheAdd($data)
  664.     {
  665.         $this->_memoryCachingArray[$this->_file] = $data;
  666.         if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
  667.             list($key, ) = each($this->_memoryCachingArray);
  668.             unset($this->_memoryCachingArray[$key]);
  669.         } else {
  670.             $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
  671.         }
  672.     }
  673.  
  674.     /**
  675.     * Make a file name (with path)
  676.     *
  677.     * @param string $id cache id
  678.     * @param string $group name of the group
  679.     * @access private
  680.     */
  681.     function _setFileName($id, $group)
  682.     {
  683.         
  684.         if ($this->_fileNameProtection) {
  685.             $suffix = 'cache_'.md5($group).'_'.md5($id);
  686.         } else {
  687.             $suffix = 'cache_'.$group.'_'.$id;
  688.         }
  689.         $root = $this->_cacheDir;
  690.         if ($this->_hashedDirectoryLevel>0) {
  691.             $hash = md5($suffix);
  692.             for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
  693.                 $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
  694.             }   
  695.         }
  696.         $this->_fileName = $suffix;
  697.         $this->_file = $root.$suffix;
  698.     }
  699.     
  700.     /**
  701.     * Read the cache file and return the content
  702.     *
  703.     * @return string content of the cache file (else : false or a PEAR_Error object)
  704.     * @access private
  705.     */
  706.     function _read()
  707.     {
  708.         $fp = @fopen($this->_file, "rb");
  709.         if ($this->_fileLocking) @flock($fp, LOCK_SH);
  710.         if ($fp) {
  711.             $length = @filesize($this->_file);
  712.             $mqr = get_magic_quotes_runtime();
  713.             set_magic_quotes_runtime(0);
  714.             if ($this->_readControl) {
  715.                 $hashControl = @fread($fp, 32);
  716.                 $length = $length - 32;
  717.             } 
  718.             if ($length) {
  719.                 $data = @fread($fp, $length);
  720.             } else {
  721.                 $data = '';
  722.             }
  723.             set_magic_quotes_runtime($mqr);
  724.             if ($this->_fileLocking) @flock($fp, LOCK_UN);
  725.             @fclose($fp);
  726.             if ($this->_readControl) {
  727.                 $hashData = $this->_hash($data, $this->_readControlType);
  728.                 if ($hashData != $hashControl) {
  729.                     if (!(is_null($this->_lifeTime))) {
  730.                         @touch($this->_file, time() - 2*abs($this->_lifeTime)); 
  731.                     } else {
  732.                         @unlink($this->_file);
  733.                     }
  734.                     return false;
  735.                 }
  736.             }
  737.             return $data;
  738.         }
  739.         return $this->raiseError('Cache_Lite : Unable to read cache !', -2); 
  740.     }
  741.     
  742.     /**
  743.     * Write the given data in the cache file
  744.     *
  745.     * @param string $data data to put in cache
  746.     * @return boolean true if ok (a PEAR_Error object else)
  747.     * @access private
  748.     */
  749.     function _write($data)
  750.     {
  751.         $try = 1;
  752.         while ($try<=2) {
  753.             $fp = @fopen($this->_file, "wb");
  754.             if ($fp) {
  755.                 if ($this->_fileLocking) @flock($fp, LOCK_EX);
  756.                 if ($this->_readControl) {
  757.                     @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
  758.                 }
  759.                 $len = strlen($data);
  760.                 @fwrite($fp, $data, $len);
  761.                 if ($this->_fileLocking) @flock($fp, LOCK_UN);
  762.                 @fclose($fp);
  763.                 return true;
  764.             }
  765.             if (($try==1) and ($this->_hashedDirectoryLevel>0)) {
  766.                 $hash = md5($this->_fileName);
  767.                 $root = $this->_cacheDir;
  768.                 for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
  769.                     $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
  770.                     @mkdir($root, $this->_hashedDirectoryUmask);
  771.                 }
  772.                 $try = 2;
  773.             } else {
  774.                 $try = 999;
  775.             }            
  776.         }
  777.         return $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1);
  778.     }
  779.        
  780.     /**
  781.     * Write the given data in the cache file and control it just after to avoir corrupted cache entries
  782.     *
  783.     * @param string $data data to put in cache
  784.     * @return boolean true if the test is ok (else : false or a PEAR_Error object)
  785.     * @access private
  786.     */
  787.     function _writeAndControl($data)
  788.     {
  789.         $result = $this->_write($data);
  790.         if (is_object($result)) {
  791.             return $result; #┬áWe return the PEAR_Error object
  792.         }
  793.         $dataRead = $this->_read($data);
  794.         if (is_object($dataRead)) {
  795.             return $result; #┬áWe return the PEAR_Error object
  796.         }
  797.         if ((is_bool($dataRead)) && (!$dataRead)) {
  798.             return false; 
  799.         }
  800.         return ($dataRead==$data);
  801.     }
  802.     
  803.     /**
  804.     * Make a control key with the string containing datas
  805.     *
  806.     * @param string $data data
  807.     * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
  808.     * @return string control key
  809.     * @access private
  810.     */
  811.     function _hash($data, $controlType)
  812.     {
  813.         switch ($controlType) {
  814.         case 'md5':
  815.             return md5($data);
  816.         case 'crc32':
  817.             return sprintf('% 32d', crc32($data));
  818.         case 'strlen':
  819.             return sprintf('% 32d', strlen($data));
  820.         default:
  821.             return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
  822.         }
  823.     }
  824.     
  825.  
  826. ?>
  827.