|
Server IP : 10.2.73.233 / Your IP : 216.73.216.59 Web Server : Apache/2.4.59 (Debian) System : Linux polon 4.19.0-27-amd64 #1 SMP Debian 4.19.316-1 (2024-06-25) x86_64 User : www-data ( 33) PHP Version : 5.6.40-64+0~20230107.71+debian10~1.gbp673146 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, MySQL : ON | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0755) : /home/ifk/web.back/framework/Caching/ |
| [ Home ] | [ C0mmand ] | [ Upload File ] |
|---|
<?php
/**
* TCache and cache dependency classes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2014 PradoSoft
* @license http://www.pradosoft.com/license/
* @package System.Caching
*/
Prado::using('System.Collections.TList');
/**
* TCache class
*
* TCache is the base class for cache classes with different cache storage implementation.
*
* TCache implements the interface {@link ICache} with the following methods,
* - {@link get} : retrieve the value with a key (if any) from cache
* - {@link set} : store the value with a key into cache
* - {@link add} : store the value only if cache does not have this key
* - {@link delete} : delete the value with the specified key from cache
* - {@link flush} : delete all values from cache
*
* Each value is associated with an expiration time. The {@link get} operation
* ensures that any expired value will not be returned. The expiration time by
* the number of seconds. A expiration time 0 represents never expire.
*
* By definition, cache does not ensure the existence of a value
* even if it never expires. Cache is not meant to be an persistent storage.
*
* Child classes must implement the following methods:
* - {@link getValue}
* - {@link setValue}
* - {@link addValue}
* - {@link deleteValue}
* and optionally {@link flush}
*
* Since version 3.1.2, TCache implements the ArrayAccess interface such that
* the cache acts as an array.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.0
*/
abstract class TCache extends TModule implements ICache, ArrayAccess
{
private $_prefix=null;
private $_primary=true;
/**
* Initializes the cache module.
* This method initializes the cache key prefix and registers the cache module
* with the application if the cache is primary.
* @param TXmlElement the module configuration
*/
public function init($config)
{
if($this->_prefix===null)
$this->_prefix=$this->getApplication()->getUniqueID();
if($this->_primary)
{
if($this->getApplication()->getCache()===null)
$this->getApplication()->setCache($this);
else
throw new TConfigurationException('cache_primary_duplicated',get_class($this));
}
}
/**
* @return boolean whether this cache module is used as primary/system cache.
* A primary cache is used by PRADO core framework to cache data such as
* parsed templates, themes, etc.
*/
public function getPrimaryCache()
{
return $this->_primary;
}
/**
* @param boolean whether this cache module is used as primary/system cache. Defaults to false.
* @see getPrimaryCache
*/
public function setPrimaryCache($value)
{
$this->_primary=TPropertyValue::ensureBoolean($value);
}
/**
* @return string a unique prefix for the keys of cached values.
* If it is not explicitly set, it will take the value of {@link TApplication::getUniqueID}.
*/
public function getKeyPrefix()
{
return $this->_prefix;
}
/**
* @param string a unique prefix for the keys of cached values
*/
public function setKeyPrefix($value)
{
$this->_prefix=$value;
}
/**
* @param string a key identifying a value to be cached
* @return sring a key generated from the provided key which ensures the uniqueness across applications
*/
protected function generateUniqueKey($key)
{
return md5($this->_prefix.$key);
}
/**
* Retrieves a value from cache with a specified key.
* @param string a key identifying the cached value
* @return mixed the value stored in cache, false if the value is not in the cache or expired.
*/
public function get($id)
{
if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
{
if(!is_array($data))
return false;
if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
return $data[0];
}
return false;
}
/**
* Stores a value identified by a key into cache.
* If the cache already contains such a key, the existing value and
* expiration time will be replaced with the new ones. If the value is
* empty, the cache key will be deleted.
*
* @param string the key identifying the value to be cached
* @param mixed the value to be cached
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
* @param ICacheDependency dependency of the cached item. If the dependency changes, the item is labeled invalid.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
public function set($id,$value,$expire=0,$dependency=null)
{
if(empty($value) && $expire === 0)
$this->delete($id);
else
{
$data=array($value,$dependency);
return $this->setValue($this->generateUniqueKey($id),$data,$expire);
}
}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* Nothing will be done if the cache already contains the key or if value is empty.
* @param string the key identifying the value to be cached
* @param mixed the value to be cached
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
* @param ICacheDependency dependency of the cached item. If the dependency changes, the item is labeled invalid.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
public function add($id,$value,$expire=0,$dependency=null)
{
if(empty($value) && $expire === 0)
return false;
$data=array($value,$dependency);
return $this->addValue($this->generateUniqueKey($id),$data,$expire);
}
/**
* Deletes a value with the specified key from cache
* @param string the key of the value to be deleted
* @return boolean if no error happens during deletion
*/
public function delete($id)
{
return $this->deleteValue($this->generateUniqueKey($id));
}
/**
* Deletes all values from cache.
* Be careful of performing this operation if the cache is shared by multiple applications.
* Child classes may implement this method to realize the flush operation.
* @throws TNotSupportedException if this method is not overridden by child classes
*/
public function flush()
{
throw new TNotSupportedException('cache_flush_unsupported');
}
/**
* Retrieves a value from cache with a specified key.
* This method should be implemented by child classes to store the data
* in specific cache storage. The uniqueness and dependency are handled
* in {@link get()} already. So only the implementation of data retrieval
* is needed.
* @param string a unique key identifying the cached value
* @return string the value stored in cache, false if the value is not in the cache or expired.
*/
abstract protected function getValue($key);
/**
* Stores a value identified by a key in cache.
* This method should be implemented by child classes to store the data
* in specific cache storage. The uniqueness and dependency are handled
* in {@link set()} already. So only the implementation of data storage
* is needed.
*
* @param string the key identifying the value to be cached
* @param string the value to be cached
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
abstract protected function setValue($key,$value,$expire);
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This method should be implemented by child classes to store the data
* in specific cache storage. The uniqueness and dependency are handled
* in {@link add()} already. So only the implementation of data storage
* is needed.
*
* @param string the key identifying the value to be cached
* @param string the value to be cached
* @param integer the number of seconds in which the cached value will expire. 0 means never expire.
* @return boolean true if the value is successfully stored into cache, false otherwise
*/
abstract protected function addValue($key,$value,$expire);
/**
* Deletes a value with the specified key from cache
* This method should be implemented by child classes to delete the data from actual cache storage.
* @param string the key of the value to be deleted
* @return boolean if no error happens during deletion
*/
abstract protected function deleteValue($key);
/**
* Returns whether there is a cache entry with a specified key.
* This method is required by the interface ArrayAccess.
* @param string a key identifying the cached value
* @return boolean
*/
public function offsetExists($id)
{
return $this->get($id) !== false;
}
/**
* Retrieves the value from cache with a specified key.
* This method is required by the interface ArrayAccess.
* @param string a key identifying the cached value
* @return mixed the value stored in cache, false if the value is not in the cache or expired.
*/
public function offsetGet($id)
{
return $this->get($id);
}
/**
* Stores the value identified by a key into cache.
* If the cache already contains such a key, the existing value will be
* replaced with the new ones. To add expiration and dependencies, use the set() method.
* This method is required by the interface ArrayAccess.
* @param string the key identifying the value to be cached
* @param mixed the value to be cached
*/
public function offsetSet($id, $value)
{
$this->set($id, $value);
}
/**
* Deletes the value with the specified key from cache
* This method is required by the interface ArrayAccess.
* @param string the key of the value to be deleted
* @return boolean if no error happens during deletion
*/
public function offsetUnset($id)
{
$this->delete($id);
}
}
/**
* TCacheDependency class.
*
* TCacheDependency is the base class implementing {@link ICacheDependency} interface.
* Descendant classes must implement {@link getHasChanged()} to provide
* actual dependency checking logic.
*
* The property value of {@link getHasChanged HasChanged} tells whether
* the dependency is changed or not.
*
* You may disable the dependency checking by setting {@link setEnabled Enabled}
* to false.
*
* Note, since the dependency objects often need to be serialized so that
* they can persist across requests, you may need to implement __sleep() and
* __wakeup() if the dependency objects contain resource handles which are
* not serializable.
*
* Currently, the following dependency classes are provided in the PRADO release:
* - {@link TFileCacheDependency}: checks whether a file is changed or not
* - {@link TDirectoryCacheDependency}: checks whether a directory is changed or not
* - {@link TGlobalStateCacheDependency}: checks whether a global state is changed or not
* - {@link TChainedCacheDependency}: checks whether any of a list of dependencies is changed or not
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
abstract class TCacheDependency extends TComponent implements ICacheDependency
{
}
/**
* TFileCacheDependency class.
*
* TFileCacheDependency performs dependency checking based on the
* last modification time of the file specified via {@link setFileName FileName}.
* The dependency is reported as unchanged if and only if the file's
* last modification time remains unchanged.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TFileCacheDependency extends TCacheDependency
{
private $_fileName;
private $_timestamp;
/**
* Constructor.
* @param string name of the file whose change is to be checked.
*/
public function __construct($fileName)
{
$this->setFileName($fileName);
}
/**
* @return string the name of the file whose change is to be checked
*/
public function getFileName()
{
return $this->_fileName;
}
/**
* @param string the name of the file whose change is to be checked
*/
public function setFileName($value)
{
$this->_fileName=$value;
$this->_timestamp=@filemtime($value);
}
/**
* @return int the last modification time of the file
*/
public function getTimestamp()
{
return $this->_timestamp;
}
/**
* Performs the actual dependency checking.
* This method returns true if the last modification time of the file is changed.
* @return boolean whether the dependency is changed or not.
*/
public function getHasChanged()
{
return @filemtime($this->_fileName)!==$this->_timestamp;
}
}
/**
* TDirectoryCacheDependency class.
*
* TDirectoryCacheDependency performs dependency checking based on the
* modification time of the files contained in the specified directory.
* The directory being checked is specified via {@link setDirectory Directory}.
*
* By default, all files under the specified directory and subdirectories
* will be checked. If the last modification time of any of them is changed
* or if different number of files are contained in a directory, the dependency
* is reported as changed. By specifying {@link setRecursiveCheck RecursiveCheck}
* and {@link setRecursiveLevel RecursiveLevel}, one can limit the checking
* to a certain depth of the subdirectories.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TDirectoryCacheDependency extends TCacheDependency
{
private $_recursiveCheck=true;
private $_recursiveLevel=-1;
private $_timestamps;
private $_directory;
/**
* Constructor.
* @param string the directory to be checked
*/
public function __construct($directory)
{
$this->setDirectory($directory);
}
/**
* @return string the directory to be checked
*/
public function getDirectory()
{
return $this->_directory;
}
/**
* @param string the directory to be checked
* @throws TInvalidDataValueException if the directory does not exist
*/
public function setDirectory($directory)
{
if(($path=realpath($directory))===false || !is_dir($path))
throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
$this->_directory=$path;
$this->_timestamps=$this->generateTimestamps($path);
}
/**
* @return boolean whether the subdirectories of the directory will also be checked.
* It defaults to true.
*/
public function getRecursiveCheck()
{
return $this->_recursiveCheck;
}
/**
* @param boolean whether the subdirectories of the directory will also be checked.
*/
public function setRecursiveCheck($value)
{
$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
}
/**
* @return int the depth of the subdirectories to be checked.
* It defaults to -1, meaning unlimited depth.
*/
public function getRecursiveLevel()
{
return $this->_recursiveLevel;
}
/**
* Sets a value indicating the depth of the subdirectories to be checked.
* This is meaningful only when {@link getRecursiveCheck RecursiveCheck}
* is true.
* @param int the depth of the subdirectories to be checked.
* If the value is less than 0, it means unlimited depth.
* If the value is 0, it means checking the files directly under the specified directory.
*/
public function setRecursiveLevel($value)
{
$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
}
/**
* Performs the actual dependency checking.
* This method returns true if the directory is changed.
* @return boolean whether the dependency is changed or not.
*/
public function getHasChanged()
{
return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
}
/**
* Checks to see if the file should be checked for dependency.
* This method is invoked when dependency of the whole directory is being checked.
* By default, it always returns true, meaning the file should be checked.
* You may override this method to check only certain files.
* @param string the name of the file that may be checked for dependency.
* @return boolean whether this file should be checked.
*/
protected function validateFile($fileName)
{
return true;
}
/**
* Checks to see if the specified subdirectory should be checked for dependency.
* This method is invoked when dependency of the whole directory is being checked.
* By default, it always returns true, meaning the subdirectory should be checked.
* You may override this method to check only certain subdirectories.
* @param string the name of the subdirectory that may be checked for dependency.
* @return boolean whether this subdirectory should be checked.
*/
protected function validateDirectory($directory)
{
return true;
}
/**
* Determines the last modification time for files under the directory.
* This method may go recursively into subdirectories if
* {@link setRecursiveCheck RecursiveCheck} is set true.
* @param string the directory name
* @param int level of the recursion
* @return array list of file modification time indexed by the file path
*/
protected function generateTimestamps($directory,$level=0)
{
if(($dir=opendir($directory))===false)
throw new TIOException('directorycachedependency_directory_invalid',$directory);
$timestamps=array();
while(($file=readdir($dir))!==false)
{
$path=$directory.DIRECTORY_SEPARATOR.$file;
if($file==='.' || $file==='..')
continue;
else if(is_dir($path))
{
if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
$timestamps=array_merge($this->generateTimestamps($path,$level+1));
}
else if($this->validateFile($path))
$timestamps[$path]=filemtime($path);
}
closedir($dir);
return $timestamps;
}
}
/**
* TGlobalStateCacheDependency class.
*
* TGlobalStateCacheDependency checks if a global state is changed or not.
* If the global state is changed, the dependency is reported as changed.
* To specify which global state this dependency should check with,
* set {@link setStateName StateName} to the name of the global state.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TGlobalStateCacheDependency extends TCacheDependency
{
private $_stateName;
private $_stateValue;
/**
* Constructor.
* @param string the name of the global state
*/
public function __construct($name)
{
$this->setStateName($name);
}
/**
* @return string the name of the global state
*/
public function getStateName()
{
return $this->_stateName;
}
/**
* @param string the name of the global state
* @see TApplication::setGlobalState
*/
public function setStateName($value)
{
$this->_stateName=$value;
$this->_stateValue=Prado::getApplication()->getGlobalState($value);
}
/**
* Performs the actual dependency checking.
* This method returns true if the specified global state is changed.
* @return boolean whether the dependency is changed or not.
*/
public function getHasChanged()
{
return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
}
}
/**
* TChainedCacheDependency class.
*
* TChainedCacheDependency represents a list of cache dependency objects
* and performs the dependency checking based on the checking results of
* these objects. If any of them reports a dependency change, TChainedCacheDependency
* will return true for the checking.
*
* To add dependencies to TChainedCacheDependency, use {@link getDependencies Dependencies}
* which gives a {@link TCacheDependencyList} instance and can be used like an array
* (see {@link TList} for more details}).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TChainedCacheDependency extends TCacheDependency
{
private $_dependencies=null;
/**
* @return TCacheDependencyList list of dependency objects
*/
public function getDependencies()
{
if($this->_dependencies===null)
$this->_dependencies=new TCacheDependencyList;
return $this->_dependencies;
}
/**
* Performs the actual dependency checking.
* This method returns true if any of the dependency objects
* reports a dependency change.
* @return boolean whether the dependency is changed or not.
*/
public function getHasChanged()
{
if($this->_dependencies!==null)
{
foreach($this->_dependencies as $dependency)
if($dependency->getHasChanged())
return true;
}
return false;
}
}
/**
* TApplicationStateCacheDependency class.
*
* TApplicationStateCacheDependency performs dependency checking based on
* the mode of the currently running PRADO application.
* The dependency is reportedly as unchanged if and only if the application
* is running in performance mode.
*
* You may chain this dependency together with other dependencies
* so that only when the application is not in performance mode the other dependencies
* will be checked.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TApplicationStateCacheDependency extends TCacheDependency
{
/**
* Performs the actual dependency checking.
* This method returns true if the currently running application is not in performance mode.
* @return boolean whether the dependency is changed or not.
*/
public function getHasChanged()
{
return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
}
}
/**
* TCacheDependencyList class.
*
* TCacheDependencyList represents a list of cache dependency objects.
* Only objects implementing {@link ICacheDependency} can be added into this list.
*
* TCacheDependencyList can be used like an array. See {@link TList}
* for more details.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package System.Caching
* @since 3.1.0
*/
class TCacheDependencyList extends TList
{
/**
* Inserts an item at the specified position.
* This overrides the parent implementation by performing additional type checking
* for each newly added item.
* @param integer the specified position.
* @param mixed new item
* @throws TInvalidDataTypeException if the item to be inserted is not a dependency instance
*/
public function insertAt($index,$item)
{
if($item instanceof ICacheDependency)
parent::insertAt($index,$item);
else
throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
}
}