home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Cache / Lite.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  25.6 KB  |  831 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.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 (($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.     * @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.  
  587.     /**
  588.     * Recursive function for cleaning cache file in the given directory
  589.     *
  590.     * @param string $dir directory complete path (with a trailing slash)
  591.     * @param string $group name of the cache group
  592.     * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
  593.                                              'callback_myFunction'
  594.     * @return boolean true if no problem
  595.     * @access private
  596.     */
  597.     function _cleanDir($dir, $group = false, $mode = 'ingroup')     
  598.     {
  599.         if ($this->_fileNameProtection) {
  600.             $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
  601.         } else {
  602.             $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
  603.         }
  604.         if ($this->_memoryCaching) {
  605.         foreach($this->_memoryCachingArray as $key => $v) {
  606.                 if (strpos($key, $motif) !== false) {
  607.                     unset($this->_memoryCachingArray[$key]);
  608.                     $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
  609.                 }
  610.             }
  611.             if ($this->_onlyMemoryCaching) {
  612.                 return true;
  613.             }
  614.         }
  615.         if (!($dh = opendir($dir))) {
  616.             return $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
  617.         }
  618.         $result = true;
  619.         while ($file = readdir($dh)) {
  620.             if (($file != '.') && ($file != '..')) {
  621.                 if (substr($file, 0, 6)=='cache_') {
  622.                     $file2 = $dir . $file;
  623.                     if (is_file($file2)) {
  624.                         switch (substr($mode, 0, 9)) {
  625.                             case 'old':
  626.                                 // files older than lifeTime get deleted from cache
  627.                                 if (!is_null($this->_lifeTime)) {
  628.                                     if ((mktime() - @filemtime($file2)) > $this->_lifeTime) {
  629.                                         $result = ($result and ($this->_unlink($file2)));
  630.                                     }
  631.                                 }
  632.                                 break;
  633.                             case 'notingrou':
  634.                                 if (strpos($file2, $motif) === false) {
  635.                                     $result = ($result and ($this->_unlink($file2)));
  636.                                 }
  637.                                 break;
  638.                             case 'callback_':
  639.                                 $func = substr($mode, 9, strlen($mode) - 9);
  640.                                 if ($func($file2, $group)) {
  641.                                     $result = ($result and ($this->_unlink($file2)));
  642.                                 }
  643.                                 break;
  644.                             case 'ingroup':
  645.                             default:
  646.                                 if (strpos($file2, $motif) !== false) {
  647.                                     $result = ($result and ($this->_unlink($file2)));
  648.                                 }
  649.                                 break;
  650.                         }
  651.                     }
  652.                     if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) {
  653.                         $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode)));
  654.                     }
  655.                 }
  656.             }
  657.         }
  658.         return $result;
  659.     }
  660.       
  661.     /**
  662.     * Add some date in the memory caching array
  663.     *
  664.     * @param string $data data to cache
  665.     * @access private
  666.     */
  667.     function _memoryCacheAdd($data)
  668.     {
  669.         $this->_memoryCachingArray[$this->_file] = $data;
  670.         if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
  671.             list($key, ) = each($this->_memoryCachingArray);
  672.             unset($this->_memoryCachingArray[$key]);
  673.         } else {
  674.             $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
  675.         }
  676.     }
  677.  
  678.     /**
  679.     * Make a file name (with path)
  680.     *
  681.     * @param string $id cache id
  682.     * @param string $group name of the group
  683.     * @access private
  684.     */
  685.     function _setFileName($id, $group)
  686.     {
  687.         
  688.         if ($this->_fileNameProtection) {
  689.             $suffix = 'cache_'.md5($group).'_'.md5($id);
  690.         } else {
  691.             $suffix = 'cache_'.$group.'_'.$id;
  692.         }
  693.         $root = $this->_cacheDir;
  694.         if ($this->_hashedDirectoryLevel>0) {
  695.             $hash = md5($suffix);
  696.             for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
  697.                 $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
  698.             }   
  699.         }
  700.         $this->_fileName = $suffix;
  701.         $this->_file = $root.$suffix;
  702.     }
  703.     
  704.     /**
  705.     * Read the cache file and return the content
  706.     *
  707.     * @return string content of the cache file (else : false or a PEAR_Error object)
  708.     * @access private
  709.     */
  710.     function _read()
  711.     {
  712.         $fp = @fopen($this->_file, "rb");
  713.         if ($this->_fileLocking) @flock($fp, LOCK_SH);
  714.         if ($fp) {
  715.             clearstatcache();
  716.             $length = @filesize($this->_file);
  717.             $mqr = get_magic_quotes_runtime();
  718.             set_magic_quotes_runtime(0);
  719.             if ($this->_readControl) {
  720.                 $hashControl = @fread($fp, 32);
  721.                 $length = $length - 32;
  722.             } 
  723.             if ($length) {
  724.                 $data = @fread($fp, $length);
  725.             } else {
  726.                 $data = '';
  727.             }
  728.             set_magic_quotes_runtime($mqr);
  729.             if ($this->_fileLocking) @flock($fp, LOCK_UN);
  730.             @fclose($fp);
  731.             if ($this->_readControl) {
  732.                 $hashData = $this->_hash($data, $this->_readControlType);
  733.                 if ($hashData != $hashControl) {
  734.                     if (!(is_null($this->_lifeTime))) {
  735.                         @touch($this->_file, time() - 2*abs($this->_lifeTime)); 
  736.                     } else {
  737.                         @unlink($this->_file);
  738.                     }
  739.                     return false;
  740.                 }
  741.             }
  742.             return $data;
  743.         }
  744.         return $this->raiseError('Cache_Lite : Unable to read cache !', -2); 
  745.     }
  746.     
  747.     /**
  748.     * Write the given data in the cache file
  749.     *
  750.     * @param string $data data to put in cache
  751.     * @return boolean true if ok (a PEAR_Error object else)
  752.     * @access private
  753.     */
  754.     function _write($data)
  755.     {
  756.         if ($this->_hashedDirectoryLevel > 0) {
  757.             $hash = md5($this->_fileName);
  758.             $root = $this->_cacheDir;
  759.             for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
  760.                 $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
  761.                 if (!(@is_dir($root))) {
  762.                     @mkdir($root, $this->_hashedDirectoryUmask);
  763.                 }
  764.             }
  765.         }
  766.         $fp = @fopen($this->_file, "wb");
  767.         if ($fp) {
  768.             if ($this->_fileLocking) @flock($fp, LOCK_EX);
  769.             if ($this->_readControl) {
  770.                 @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
  771.             }
  772.             $mqr = get_magic_quotes_runtime();
  773.             set_magic_quotes_runtime(0);
  774.             @fwrite($fp, $data);
  775.             set_magic_quotes_runtime($mqr);
  776.             if ($this->_fileLocking) @flock($fp, LOCK_UN);
  777.             @fclose($fp);
  778.             return true;
  779.         }      
  780.         return $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1);
  781.     }
  782.        
  783.     /**
  784.     * Write the given data in the cache file and control it just after to avoir corrupted cache entries
  785.     *
  786.     * @param string $data data to put in cache
  787.     * @return boolean true if the test is ok (else : false or a PEAR_Error object)
  788.     * @access private
  789.     */
  790.     function _writeAndControl($data)
  791.     {
  792.         $result = $this->_write($data);
  793.         if (is_object($result)) {
  794.             return $result; #┬áWe return the PEAR_Error object
  795.         }
  796.         $dataRead = $this->_read();
  797.         if (is_object($dataRead)) {
  798.             return $dataRead; #┬áWe return the PEAR_Error object
  799.         }
  800.         if ((is_bool($dataRead)) && (!$dataRead)) {
  801.             return false; 
  802.         }
  803.         return ($dataRead==$data);
  804.     }
  805.     
  806.     /**
  807.     * Make a control key with the string containing datas
  808.     *
  809.     * @param string $data data
  810.     * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
  811.     * @return string control key
  812.     * @access private
  813.     */
  814.     function _hash($data, $controlType)
  815.     {
  816.         switch ($controlType) {
  817.         case 'md5':
  818.             return md5($data);
  819.         case 'crc32':
  820.             return sprintf('% 32d', crc32($data));
  821.         case 'strlen':
  822.             return sprintf('% 32d', strlen($data));
  823.         default:
  824.             return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
  825.         }
  826.     }
  827.     
  828.  
  829. ?>
  830.