Source code for file /pear/cache/Lite.php
Documentation is available at Lite.php
* Fast, light and safe Cache Class
* Cache_Lite is a fast, light and safe cache system. It's optimized
* for file containers. It is fast and safe (because it uses file
* locking and/or anti-corruption tests).
* There are some examples in the 'docs/examples' file
* Technical choices are described in the 'docs/technical' file
* Memory Caching is from an original idea of
* http://rainx.phpmore.com/manual/cache_lite.html
* @version $Id: Lite.php,v 1.45 2006/06/03 08:10:33 fab Exp $
define('CACHE_LITE_ERROR_RETURN', 1);
define('CACHE_LITE_ERROR_DIE', 8);
// --- Private properties ---
* Directory where to put the cache files
* (make sure to add a trailing slash)
* Enable / disable caching
* (can be very usefull for the debug of cached scripts)
* Cache lifetime (in seconds)
* If null, the cache is valid forever.
* Enable / disable fileLocking
* (can avoid cache corruption under bad circumstances)
* @var boolean $_fileLocking
* Timestamp of the last valid cache
* File name (without path)
* Enable / disable write control (the cache is read just after writing to detect corrupt entries)
* Enable write control will lightly slow the cache writing but not the cache reading
* Write control can detect some corrupt cache files but maybe it's not a perfect control
* @var boolean $_writeControl
* Enable / disable read control
* If enabled, a control key is embeded in cache file and this key is compared with the one
* calculated after the reading.
* @var boolean $_writeControl
* Type of read control (only if read control is enabled)
* 'md5' for a md5 hash control (best but slowest)
* 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
* 'strlen' for a length only test (fastest)
* @var boolean $_readControlType
* Pear error mode (when raiseError is called)
* @var int $_pearErrorMode
* Enable / Disable "Memory Caching"
* NB : There is no lifetime for memory caching !
* @var boolean $_memoryCaching
* Enable / Disable "Only Memory Caching"
* (be carefull, memory caching is "beta quality")
* @var boolean $_onlyMemoryCaching
* @var array $_memoryCachingArray
* @var int $memoryCachingCounter
* @var int $memoryCachingLimit
* if set to true, you can use any cache id or group name
* if set to false, it can be faster but cache ids and group names
* will be used directly in cache file names so be carefull with
* @var boolean $fileNameProtection
* Enable / disable automatic serialization
* it can be used to save directly datas which aren't strings
* @var boolean $_serialize
* Disable / Tune the automatic cleaning process
* The automatic cleaning process destroy too old (for the given life time)
* cache files when a new cache file is written.
* 0 => no automatic cache cleaning
* 1 => systematic cache cleaning
* x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
* @var int $_automaticCleaning
* Set the hashed directory structure level. 0 means "no hashed directory
* structure", 1 means "one level of directory", 2 means "two levels"...
* This option can speed up Cache_Lite only when you have many thousands of
* cache file. Only specific benchs can help you to choose the perfect value
* for you. Maybe, 1 or 2 is a good start.
* @var int $_hashedDirectoryLevel
* Umask for hashed directory structure
* @var int $_hashedDirectoryUmask
* API break for error handling in CACHE_LITE_ERROR_RETURN mode
* In CACHE_LITE_ERROR_RETURN mode, error handling was not good because
* for example save() method always returned a boolean (a PEAR_Error object
* would be better in CACHE_LITE_ERROR_RETURN mode). To correct this without
* breaking the API, this option (false by default) can change this handling.
// --- Public methods ---
* $options is an assoc. Available options are :
* 'cacheDir' => directory where to put the cache files (string),
* 'caching' => enable / disable caching (boolean),
* 'lifeTime' => cache lifetime in seconds (int),
* 'fileLocking' => enable / disable fileLocking (boolean),
* 'writeControl' => enable / disable write control (boolean),
* 'readControl' => enable / disable read control (boolean),
* 'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
* 'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
* 'memoryCaching' => enable / disable memory caching (boolean),
* 'onlyMemoryCaching' => enable / disable only memory caching (boolean),
* 'memoryCachingLimit' => max nbr of records to store into memory caching (int),
* 'fileNameProtection' => enable / disable automatic file name protection (boolean),
* 'automaticSerialization' => enable / disable automatic serialization (boolean),
* 'automaticCleaningFactor' => distable / tune automatic cleaning process (int),
* 'hashedDirectoryLevel' => level of the hashed directory system (int),
* 'hashedDirectoryUmask' => umask for hashed directory structure (int),
* 'errorHandlingAPIBreak' => API break for better error handling ? (boolean)
* @param array $options options
foreach($options as $key =>
$value) {
* Generic way to set a Cache_Lite option
* see Cache_Lite constructor for available options
* @var string $name name of the option
* @var mixed $value value of the option
$availableOptions =
array('errorHandlingAPIBreak', 'hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
if (in_array($name, $availableOptions)) {
$this->$property =
$value;
* Test if a cache is available and (if yes) return it
* @param string $id cache id
* @param string $group name of the cache group
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string data of the cache (else : false)
function get($id, $group =
'default', $doNotTestCacheValidity =
false)
$this->_setRefreshTime();
$this->_setFileName($id, $group);
$this->_memoryCacheAdd($data);
* Save some data in a cache file
* @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
* @param string $id cache id
* @param string $group name of the cache group
* @return boolean true if no problem (else : false or a PEAR_Error object)
function save($data, $id =
NULL, $group =
'default')
$this->_setFileName($id, $group);
$this->_memoryCacheAdd($data);
$this->clean(false, 'old');
$res =
$this->_writeAndControl($data);
// if $res if false, we need to invalidate the cache
$res =
$this->_write($data);
// $res is a PEAR_Error object
return false; // we return false (old API)
* @param string $id cache id
* @param string $group name of the cache group
* @return boolean true if no problem
function remove($id, $group =
'default')
$this->_setFileName($id, $group);
return $this->_unlink($this->_file);
* if no group is specified all cache files will be destroyed
* else only cache files of the specified group will be destroyed
* @param string $group name of the cache group
* @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
* @return boolean true if no problem
function clean($group =
false, $mode =
'ingroup')
return $this->_cleanDir($this->_cacheDir, $group, $mode);
* When an error is found, the script will stop and the message will be displayed
* @param int $newLifeTime new life time (in seconds)
$this->_setRefreshTime();
* Save the state of the caching memory array into a cache file cache
* @param string $id cache id
* @param string $group name of the cache group
'array' =>
$this->_memoryCachingState
$this->save($data, $id, $group);
* Load the state of the caching memory array from a given cache file cache
* @param string $id cache id
* @param string $group name of the cache group
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
if ($data =
$this->get($id, $group, $doNotTestCacheValidity)) {
* Return the cache last modification time
* BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
* @return int last modification time
* To improve performances, the PEAR.php file is included dynamically.
* The file is so included only when an error is triggered. So, in most
* cases, the file isn't included and perfs are much better.
* @param string $msg error message
* @param int $code error code
* Extend the life of a valid cache file
* see http://pear.php.net/bugs/bug.php?id=6681
// --- Private methods ---
* Compute & set the refresh time
function _setRefreshTime()
* @param string $file complete file path and name
* @return boolean true if no problem
return $this->raiseError('Cache_Lite : Unable to remove cache !', -
3);
* Recursive function for cleaning cache file in the given directory
* @param string $dir directory complete path (with a trailing slash)
* @param string $group name of the cache group
* @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
* @return boolean true if no problem
function _cleanDir($dir, $group =
false, $mode =
'ingroup')
$motif =
($group) ?
'cache_'.
md5($group).
'_' :
'cache_';
$motif =
($group) ?
'cache_'.
$group.
'_' :
'cache_';
if (strpos($key, $motif, 0)) {
return $this->raiseError('Cache_Lite : Unable to open cache directory !', -
4);
if (($file !=
'.') &&
($file !=
'..')) {
if (substr($file, 0, 6)==
'cache_') {
switch (substr($mode, 0, 9)) {
// files older than lifeTime get deleted from cache
$result =
($result and ($this->_unlink($file2)));
if (!strpos($file2, $motif, 0)) {
$result =
($result and ($this->_unlink($file2)));
if ($func($file2, $group)) {
$result =
($result and ($this->_unlink($file2)));
if (strpos($file2, $motif, 0)) {
$result =
($result and ($this->_unlink($file2)));
$result =
($result and ($this->_cleanDir($file2 .
'/', $group, $mode)));
* Add some date in the memory caching array
* @param string $data data to cache
function _memoryCacheAdd($data)
* Make a file name (with path)
* @param string $id cache id
* @param string $group name of the group
function _setFileName($id, $group)
$suffix =
'cache_'.
md5($group).
'_'.
md5($id);
$suffix =
'cache_'.
$group.
'_'.
$id;
$root =
$root .
'cache_' .
substr($hash, 0, $i +
1) .
'/';
$this->_file =
$root.
$suffix;
* Read the cache file and return the content
* @return string content of the cache file (else : false or a PEAR_Error object)
$hashControl =
@fread($fp, 32);
$data =
@fread($fp, $length);
if ($hashData !=
$hashControl) {
return $this->raiseError('Cache_Lite : Unable to read cache !', -
2);
* Write the given data in the cache file
* @param string $data data to put in cache
* @return boolean true if ok (a PEAR_Error object else)
$root =
$root .
'cache_' .
substr($hash, 0, $i +
1) .
'/';
return $this->raiseError('Cache_Lite : Unable to write cache file : '.
$this->_file, -
1);
* Write the given data in the cache file and control it just after to avoir corrupted cache entries
* @param string $data data to put in cache
* @return boolean true if the test is ok (else : false or a PEAR_Error object)
function _writeAndControl($data)
$result =
$this->_write($data);
return $result; # We return the PEAR_Error object
$dataRead =
$this->_read();
return $result; # We return the PEAR_Error object
if ((is_bool($dataRead)) &&
(!$dataRead)) {
return ($dataRead==
$data);
* Make a control key with the string containing datas
* @param string $data data
* @param string $controlType type of control 'md5', 'crc32' or 'strlen'
* @return string control key
function _hash($data, $controlType)
return $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -
5);