File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/api/class.cache.php
<?php
/**
* This file contains the iwp_cache class
*
* @version $Id$
*
*
* @package IWP
* @subpackage IWP_API
*/
/**
* IWP Cache Class
* This is the class that handles all caching functions within the application
*
* @package IWP
* @subpackage IWP_API
*/
class iwp_cache extends iwp_base {
/**
* An array for the list of cache directories available.
* Example format:
* $this->cacheDirs['cacheDirName'] = array('expires' => (3600 * 5), 'extension' => 'xml');
*
* @var array
*/
private $cacheDirs = array();
/**
* This the name of the current directory. It should related to a specific array key in $cacheDirs
*
* @var string
*/
private $currentDir = null;
/**
* This stores an array of all the content items or categories or users in each list
*
* @var array
*/
public $listsCache = array();
/**
* This stores a list of all the lists in their respective types, i.e. content, category, users
*/
public $listsTypes = array();
/**
* Instance
* This static variable holds the current instance of this object being loaded.
* So using the getInstance function anywhere will return the very same instance.
*
* @var iwp_cache Instance
*/
public static $Instance;
/**
* getInstance
* This is a static function that sets up the class instance and stores it to the static variable. It will then return that instantiation in the future.
*
* @return iwp_cache Returns the instantiated object
**/
public static function getInstance(){
if(!isset(self::$Instance)){
self::$Instance = new self();
}
return self::$Instance;
}
/**
* When initialized, load the cache directory structure
*
* @return void
*/
public function __construct(){
$this->LoadCacheDirs();
}
/**
* Sets up all the cache directories to be used with their extension and expiry times
*
* @return void
*
* @see ReadCacheConfig()
* @see $cacheDirs
*/
public function LoadCacheDirs(){
$timeMinute = 60;
$timeHour = 3600;
$timeDay = 86400;
// set default dirs
$this->cacheDirs = array();
//$this->cacheDirs['template'] = array('expires' => 315360000, 'extension' => 'html'); // 315360000 = 10 years
//$this->cacheDirs['sections'] = array('expires' => 315360000, 'extension' => 'php'); // 315360000 = 10 years
$this->cacheDirs['rss_in'] = array('expires' => ($timeHour * 5), 'extension' => 'xml');
$this->cacheDirs['rss_out'] = array('expires' => ($timeMinute * 30), 'extension' => 'xml');
$this->cacheDirs['categories'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['authors'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['lists'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['blocks'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['content'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['modules'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['other_day'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['search'] = array('expires' => $timeDay, 'extension' => 'html');
$this->cacheDirs['other_hour'] = array('expires' => $timeHour, 'extension' => 'html');
$this->cacheDirs['archive'] = array('expires' => $timeDay, 'extension' => 'html');
$cacheConfig = $this->ReadCacheConfig();
if(is_array($cacheConfig) && sizeof($cacheConfig) > 0){
foreach($cacheConfig as $key=>$val){
$this->cacheDirs[$key] = array('expires' => $val['expires']);
}
}
$modules = iwp_modules::getInstance();
$moduleList = $modules->ModuleList();
foreach($moduleList as $module) {
if(isset($modules->GetModule($module)->cacheDirs)) {
$this->cacheDirs = $this->cacheDirs + $modules->GetModule($module)->cacheDirs;
}
}
}
/**
* Reads the cache config file and returns it. The cache config file is used to set up cache directories for content types.
*
* @return array Dynamically created based on content types
*/
public function ReadCacheConfig(){
$cacheConfig = array();
if(file_exists(IWP_CONFIG_PATH . '/cacheconfig.php')){
// if we have a cached file
include_once(IWP_CONFIG_PATH . '/cacheconfig.php');
return $cacheConfig;
}
return array();
}
/**
* Reads in the lists cache if it exists and assigns the values of the arrays in the cache to class member variables
* The lists cache config file is used to know which lists contain each content item, so that when a content item is updated all the lists containing it can be cleared.
*
* @return void Doesn't return anything, it assigns the values of the member variables
*/
public function ReadListsCacheFile(){
$listsCache = $listsTypes = array();
if(!file_exists(IWP_CACHE_PATH . '/listscache.php')){
$this->ReloadListsCacheFile();
}
if(file_exists(IWP_CACHE_PATH . '/listscache.php')){
// if we have a cached file
include(IWP_CACHE_PATH . '/listscache.php');
$this->listsCache = $listsCache;
$this->listsTypes = $listsTypes;
return true;
}
return false;
}
/**
* This writes to the lists cache information file.
*
* The lists cache config file is used to know which lists contain each content item, so that when a content item is updated all the lists containing it can be cleared.
*
* @param array $listsCache An array of all lists containing the ID numbers of all their contents
* @param array $listsTypes An array of the different types of lists and the ID numbers of the lists in each type
*
* @return boolean True on success, false otherwise
*/
public function WriteListsCacheFile($listsCache, $listsTypes){
$status = @file_put_contents(IWP_CACHE_PATH . '/listscache.php', '<?php'."\n\n".
'// Warning: Do not edit this file. '."\n".'// This is an automatically generated file and any modifications will be overwritten.'."\n\n".
'$listsCache = '.var_export($listsCache, true).';'."\n".
'$listsTypes = '.var_export($listsTypes, true).';'."\n");
@chmod(IWP_CACHE_PATH . '/listscache.php', 0666);
return $status;
}
/**
* This reloads the cached lists information file. It loops over all the lists in the database and saves the data into a PHP array into a file.
*
* The lists cache config file is used to know which lists contain each content item, so that when a content item is updated all the lists containing it can be cleared.
*
* @param integer $listId The ID number of the list to reload
* @return mixed Null if successful, false otherwise. (The return result of @file_put_contents in WriteListsCacheFile())
*
* @see WriteListsCacheFile()
*/
public function ReloadListsCacheFile($listIds = 0){
$listsCache = $listsTypes = array();
if(!is_array($listIds)) {
$listIds = array($listIds);
}
foreach($listIds as $listId) {
if((int)$listId > 0 ){
// only refreshing one list, so we want to keep all exisiting data for other lists
$this->ReadListsCacheFile();
$listsCache = $this->listsCache;
$listsTypes = $this->listsTypes;
$resource = $this->db->Query('select * from ' . IWP_TABLE_LISTS . ' where listid=' . $listId);
} else {
// refreshing everything
$resource = $this->db->Query('select * from ' . IWP_TABLE_LISTS . ' where type="dynamic"');
}
while(($row = $this->db->Fetch($resource))) {
if($row['datatype'] == 'none'){
continue;
}
if(!isset($listsTypes[$row['datatype']])){
$listsTypes[$row['datatype']] = array();
}
$query = iwp_lists::getInstance()->LoadQuery(false, $row['querycache'], $row['datatype'], $row['options'], $row['listid']);
if(empty($query) || strlen($query) < 10){
continue;
}
$queryResource = $this->db->Query($query);
if(!$queryResource){
continue;
}
$listsCache[$row['listid']] = array();
while(($listRow = $this->db->Fetch($queryResource))) {
if(isset($listRow['rowid']) && !in_array((int)$listRow['rowid'], $listsCache[$row['listid']])) {
$listsCache[$row['listid']][] = (int)$listRow['rowid'];
}
}
if(sizeof($listsCache[$row['listid']]) < 1){
unset($listsCache[$row['listid']]);
unset($listsCache[$row['listid']]);
}else{
$listsTypes[$row['datatype']][] = $row['listid'];
$listsTypes[$row['datatype']] = array_unique($listsTypes[$row['datatype']]);
}
}
$this->listsCache = $listsCache;
$this->listsTypes = $listsTypes;
$this->WriteListsCacheFile($listsCache, $listsTypes);
}
return true;
}
public function GetListsTypes() {
return $this->listsTypes;
}
/**
* This function removes all cache files associated with lists displayed through OutputListByQuery. This could cover several types of lists, but there's no way to relate it back to the actual list type since they have no id / type information.
*
* @return void Doesn't return anything
*/
public function ClearQueryListsCache () {
if(!$this->ConfirmDir('lists')){
return false;
}
// clear all lists with an id of 0; these are generated by OutputListByQuery
$id = '0_';
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/lists');
foreach($dirObject as $fileName=>$objFile){
if($objFile->isFile()){
if(substr($objFile->getFilename(), 0, strlen($id)) === $id){
@unlink($objFile->getPath()."/". $objFile->getFilename());
}
}
}
}
/**
* This function clears all lists of a particular type.
*
* @param $listType string The type of lists that should be removed; 'categories', 'users' or 'content'
* @return void Doesn't return anything
*/
public function ClearListsCacheByType ($listType) {
$this->ReadListsCacheFile();
if(!isset($this->listsTypes[$listType])){
// there are no lists of this type
return;
}
if(!$this->ConfirmDir('lists')){
return false;
}
foreach ($this->listsTypes[$listType] as $listId) {
if(!isset($this->listsCache[$listId]) || !is_array($this->listsCache[$listId])){
continue;
}
$id = $listId .'_';
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/lists');
foreach ($dirObject as $fileName => $objFile) {
if ($objFile->isFile()) {
if (substr($objFile->getFilename(), 0, strlen($id)) === $id) {
unlink($objFile->getPath() ."/". $objFile->getFilename());
}
}
}
}
}
/**
* This function takes the ID number of a content item, category or user and deletes any list cache files that contain that ID number within the displayed list.
*
* @param string $listType The type of list that should be removed, 'categories', 'users', or 'content'
* @param integer $itemId The ID number of the item that should have all its caches deleted, this is used to check in the lists cache and delete any list cache that contains this item ID within the list.
*
* @return void Doesn't return anything
*/
public function ClearListsCacheById($listType, $itemId){
$listsToClear = array();
$this->ReadListsCacheFile();
if(!isset($this->listsTypes[$listType])){
// there are no lists of this type
return;
}
if(!$this->ConfirmDir('lists')){
return false;
}
foreach ($this->listsTypes[$listType] as $listId){
if(!isset($this->listsCache[$listId]) || !is_array($this->listsCache[$listId])){
continue;
}
if(in_array($itemId, $this->listsCache[(int)$listId])){
// clear the cache file for this list
$id = $listId . '_';
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/lists');
foreach($dirObject as $fileName=>$objFile){
if($objFile->isFile()){
if(substr($objFile->getFilename(), 0, strlen($id)) === $id){
@unlink($objFile->getPath()."/". $objFile->getFilename());
}
}
}
}
}
}
/**
* This function deletes all the cache files for a particular list
*
* @param integer $listId The ID number of the list that should have all its cache files deleted
*
* @return void Doesn't return anything
*/
public function ClearListsCacheByListId($listIds){
if(!is_array($listIds)) {
$listIds = array($listIds);
}
// clear the cache file for this list
if(!$this->ConfirmDir('lists')){
return false;
}
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/lists');
foreach($dirObject as $fileName=>$objFile){
if($objFile->isFile()){
foreach($listIds as $listId) {
if(substr($objFile->getFilename(), 0, strlen($listId . '_')) === $listId . '_'){
@unlink($objFile->getPath()."/". $objFile->getFilename());
}
}
}
}
}
/**
* This writes to the cache config file. The cache config file is used to set up cache directories for content types.
*
* @param array $cacheConfig An array of content types and their expiry time
*
* @return boolean True on success, false otherwise
*/
public function WriteCacheConfig($cacheConfig){
return @file_put_contents(IWP_CONFIG_PATH . '/cacheconfig.php', '<?php'."\n\n".'// Warning: Do not edit this file. '."\n".'// This is an automatically generated file and any modifications will be overwritten.'."\n\n".'$cacheConfig = '.var_export($cacheConfig, true).';');
}
/**
* This function takes a content type name and expires time and updates it in the cache config file. Used when content types are updated and the caching time has changed.
*
* @param $name The name of content type directory (normally html_content_{idnumber} )
* @param $expires The expiry time for the directory in seconds
*
* @return boolean True on success, false otherwise
*/
public function UpdateCacheConfig($name, $expires){
$cacheConfig = self::ReadCacheConfig();
$cacheConfig[$name] = array('expires' => (int)$expires);
return self::WriteCacheConfig($cacheConfig);
}
/**
* This function removes a specified content type's cache directory. This is only called when the content type is being deleted.
*
* @param $name The name of content type directory (normally html_content_{idnumber} )
*
* @return boolean True on success, false otherwise
*/
public function RemoveFromCacheConfig($name){
$cacheConfig = self::ReadCacheConfig();
if(isset($cacheConfig[$name])){
unset($cacheConfig[$name]);
}
return self::WriteCacheConfig($cacheConfig);
}
/**
* This function confirms that the current directory exists, and if not attempts to create it. If it fails, it returns false
*
* @return boolean True if the dir exists, false if not
*/
public function ConfirmDir($dir=null){
if($dir === null){
$dir = $this->currentDir;
}
$dir = str_replace(array('.','/','\\'), '', $dir);
if(!is_dir(IWP_CACHE_PATH . '/' . $dir)){
@mkdir(IWP_CACHE_PATH . '/' . $dir, 0777);
@chmod(IWP_CACHE_PATH . '/' . $dir, 0777);
if(!is_dir(IWP_CACHE_PATH . '/' . $dir)){
return false;
}
}
if(CheckDirWritable(IWP_CACHE_PATH . '/' . $dir)){
return true;
}
return false;
}
/**
* Sets the current working cache directory. Must correspond to one the array keys for $this->cacheDirs
*
* @param string $dir The name of the cache directory to set
*
* @return void
*/
public function SetDir($dir){
if($this->IsCacheDir($dir)){
$this->currentDir = $dir;
}
}
/**
* Checks if a specified cache directory name is a valid array key in $this->cacheDirs
*
* @param string $dir The name of the directory to check
*
* @return boolean True if the directory is valid, false otherwise
*/
public function IsCacheDir($dir){
return isset($this->cacheDirs[$dir]);
}
/**
* Returns the name of the current working cache directory
*
* @return string The name of the current working cache directory
*/
public function GetDir(){
return $this->currentDir;
}
/**
* This function reads a specified cache file from the current working directory
*
* @param string $cacheId The name of the cache file without its extension that should be read in
*
* @return string The contents of the cache file specified
*/
public function ReadCache($cacheId){
if(file_exists($this->GetFullFileName($cacheId))){
return file_get_contents($this->GetFullFileName($cacheId));
}
}
/**
* This function get the extension for a cache file in the current working directory
*
* @param boolean $withDot True if the return value should include the dot (default) or false to return without.
*
* @return string The extension for files in the current working directory
*/
public function GetExtension($withDot = true){
if($withDot === true){
return '.' . $this->cacheDirs[$this->currentDir]['extension'];
}
return $this->cacheDirs[$this->currentDir]['extension'];
}
/**
* Returns the expiry length in seconds for the current working cache directory
*
* @return integer The length of expiry in seconds
*/
public function GetExpiry(){
return $this->cacheDirs[$this->currentDir]['expires'];
}
/**
* This function writes to a specified cache file
*
* @param string $cacheId The name of the cache file to write to without it's extension
* @param string $data The data to write to the file
* @param int $expireTime Use to explicitly set the expiration time of this item to the given timestamp, will not be set > than the standard expiry time but can be used to set a shorter expiry
*
* @return boolean True if the write was successful, false otherwise
*/
public function WriteCache($cacheId, $data, $expireTime = false){
if(!iwp_config::Get('EnableCache')){
return true;
}
if(!$this->ConfirmDir()){
return false;
}
$filename = $this->GetFullFileName($cacheId);
// TODO: somehow flag that this dir doesn't exist and can't be created or isn't writable
$written = @file_put_contents($filename, $data);
if ($written !== false && $expireTime !== false) {
// file write was successful and a specific expiration time has been provided
$expireLength = $this->GetExpiry();
if ($expireLength > -1) {
// do not set the expiration time to longer than the expiration length
// do not set the expiration time so it expires immediately (useless caching)
if ($expireTime < time() + $expireLength && $expireTime > time() - $expireLength) {
// set the file modified time so it suits the desired expiry time (mtime + expiry length = expiry)
touch($filename, $expireTime - $expireLength);
}
}
}
return $written;
}
/**
* Checks if a specified cache file has expired or not
*
* @param string $cacheId The name of the cache file to check for expiry
*
* @return boolean True if the cache file has expired, false otherwise
*/
public function HasExpired($cacheId){
if(!iwp_config::Get('EnableCache')){
return true;
}
if(!$this->CacheExists($cacheId)){
return true;
}
$filetime = filemtime($this->GetFullFileName($cacheId));
if($this->GetExpiry() > -1){
if($filetime < (time() - $this->GetExpiry())){
return true;
}
}
return false;
}
/**
* Deletes a specified cache file
*
* @param string The name of the cache file to delete
*
* @return boolean True if the file could be deleted, false otherwise
*/
public function ClearCacheFile($cacheId){
if(!$this->CacheExists($cacheId)){
return true;
}
if(@unlink($this->GetFullFileName($cacheId))){
return true;
}
return false;
}
/**
* Deletes the entire contents of a cache directory
*
* @param string $dir An optional argument to specify a directory. By default it will use the current working directory
*
* @return boolean True on success, false otherwise
*/
public function ClearCacheDir($dir=null){
if($dir === null){
$dir = $this->currentDir;
}
if(!$this->ConfirmDir($dir)){
return false;
}
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/' .$dir);
foreach($dirObject as $fileName=>$objFile){
if($objFile->isFile()){
@unlink($objFile->getPath()."/". $objFile->getFilename());
}
}
return true;
}
/**
* This function removes a cache directory completely
*
* @param string $dir An optional argument to specify a directory. By default it will use the current working directory
*
* @return boolean True on success, false otherwise
*/
public function RemoveCacheDir($dir=null) {
if($dir === null){
$dir = $this->currentDir;
}
if(!$this->ConfirmDir($dir)){
return false;
}
$this->ClearCacheDir($dir);
$this->cache->RemoveFromCacheConfig($dir);
return @rmdir(IWP_CACHE_PATH .'/' .$dir);
}
/**
* Clears all the cache directories of all files
*
* @return true
*/
public function ClearCacheAll(){
foreach($this->cacheDirs as $cacheDir =>$options){
if(is_dir(IWP_CACHE_PATH .'/' .$cacheDir)){
$dirObject = new DirectoryIterator(IWP_CACHE_PATH .'/' .$cacheDir);
foreach($dirObject as $fileName=>$objFile){
if($objFile->isFile()){
@unlink($objFile->getPath()."/". $objFile->getFilename());
}
}
}
}
return true;
}
/**
* Takes in a cache ID and gets the full path to the file on the server
*
* @param string $cacheId The name of the file to get the path for
*
* @return string The full path to the cache file
*/
public function GetFullFileName($cacheId){
return IWP_CACHE_PATH .'/' . $this->currentDir .'/'. $cacheId . $this->GetExtension();
}
/**
* Checks to see if a specified cache file exists or not
*
* @param string $name The name of the cache file to check for
*
* @return boolean True if it exists, false otherwise
*/
public function CacheExists($cacheId){
return (@file_exists($this->GetFullFileName($cacheId)) && @is_file($this->GetFullFileName($cacheId)));
}
}