* @copyright Copyright © 2006 - 2011 Peter Adams * @license http://www.gnu.org/copyleft/gpl.html GPL v2.0 * @category owa * @package owa * @version $Revision$ * @since owa 1.4.0 */ class owa_fileCache extends owa_cache { var $cache_dir; var $lock_file_name = 'cache.lock'; var $cache_file_header = ''; var $file_perms = 0750; var $dir_perms = 0750; var $mutex; /** * Constructor * * Takes cache directory as param * * @param $cache_dir string */ function __construct($cache_dir = '') { if ($cache_dir) { $this->cache_dir = $cache_dir; } else { $this->cache_dir = OWA_CACHE_DIR; } return parent::__construct(); } function getItemFromCacheStore($collection, $id) { $cache_file = $this->makeCollectionDirPath($collection).$id.'.php'; $this->debug("check cache file: ".$cache_file); // if no cache file then return false if (!file_exists($cache_file)) { $this->debug(sprintf('Cache File not found for Collection: %s, id: %s, file: %s', $collection, $id, $cache_file)); return false; // cache object has expired } elseif ((filectime($cache_file) + $this->getCollectionExpirationPeriod($collection)) < time()) { $this->debug("time: ".time()); $this->debug("ctime: ".filectime($cache_file)); $this->debug("diff: ".(time() - filectime($cache_file))); $this->debug("exp period: ".$this->getCollectionExpirationPeriod($collection)); $this->removeCacheFile($this->makeCollectionDirPath($collection).$id.'.php'); $this->debug(sprintf('Cache Object has expired for Collection: %s, id: %s', $collection, $id)); return false; // load from cache file } else { return unserialize(base64_decode(substr(@ file_get_contents($cache_file), strlen($this->cache_file_header), -strlen($this->cache_file_footer)))); } } function putItemToCacheStore($collection, $id) { owa_coreAPI::debug('put id: '.$id); if ( $this->acquire_lock() ) { $this->makeCacheCollectionDir($collection); $this->debug(' writing file for: '.$collection.$id); // create collection dir $collection_dir = $this->makeCollectionDirPath($collection); // asemble cache file name $cache_file = $collection_dir.$id.'.php'; $this->removeCacheFile($cache_file); $temp_cache_file = tempnam($collection_dir, 'tmp_'.$id); $data = $this->cache_file_header.base64_encode(serialize($this->cache[$collection][$id])).$this->cache_file_footer; // open the temp cache file for writing $tcf_handle = @fopen($temp_cache_file, 'w'); if ( false === $tcf_handle ) { $this->debug('could not acquire temp file handler'); } else { fputs($tcf_handle, $data); fclose($tcf_handle); if (!@ rename($temp_cache_file, $cache_file)) { if (!@ copy($temp_cache_file, $cache_file)) { $this->debug('could not rename or copy temp file to cache file'); } else { @ unlink($temp_cache_file); $this->debug('removing temp cache file'); } } @ chmod($cache_file, $this->file_perms); $this->debug('changing file permissions on cache file'); } $this->release_lock(); } else { $this->debug("could not persist item to cache due to failure acquiring lock."); } } function removeItemFromCacheStore($collection, $id) { return $this->removeCacheFile($this->makeCollectionDirPath($collection).$id.'.php'); } function makeCollectionDirPath($collection) { if (!in_array($collection, $this->global_collections)) { return $this->cache_dir.$this->cache_id.DIRECTORY_SEPARATOR.$collection.DIRECTORY_SEPARATOR; } else { return $this->cache_dir.$collection.DIRECTORY_SEPARATOR; } } function makeCacheCollectionDir($collection) { // check to see if the caches directory is writable, return if not. if (!is_writable($this->cache_dir)) { return; } // localize the cache directory based on some id passed from caller if (!file_exists($this->cache_dir.$this->cache_id)) { mkdir($this->cache_dir.$this->cache_id); chmod($this->cache_dir.$this->cache_id, $this->dir_perms); } $collection_dir = $this->makeCollectionDirPath($collection); if (!file_exists($collection_dir)) { mkdir($collection_dir); chmod($collection_dir, $this->dir_perms); } if (!file_exists($collection_dir."index.php")) { touch($collection_dir."index.php"); chmod($collection_dir."index.php", $this->file_perms); } } function removeCacheFile($cache_file) { // Remove the cache file if (file_exists($cache_file)) { @ unlink($cache_file); $this->debug('Cache File Removed: '.$cache_file); $this->statistics['removed']++; return true; } else { return false; } } function flush() { $tld = $this->readDir($this->cache_dir); $this->debug("Reading cache file list from: ". $this->cache_dir); $this->deleteFiles($tld['files']); foreach ($tld['dirs'] as $k => $dir) { $sld = $this->readDir($dir); $this->debug("Reading cache file list from: ". $dir); if (array_key_exists('files', $sld)) { $this->deleteFiles($sld['files']); } foreach ($sld['dirs'] as $sk => $sdir) { $ssld = $this->readDir($sdir); $this->debug("Reading cache file list from: ". $sdir); $this->deleteFiles($ssld['files']); rmdir($sdir); } rmdir($dir); } } function setCacheDir($dir) { $this->cache_dir = $dir; } function acquire_lock() { // Acquire a write lock. $this->mutex = @fopen($this->cache_dir.$this->lock_file_name, 'w'); if (false == $this->mutex) { return false; } else { flock($this->mutex, LOCK_EX); return true; } } function release_lock() { // Release write lock. flock($this->mutex, LOCK_UN); fclose($this->mutex); } function readDir($dir) { if ($handle = opendir($dir)) { while (($file = readdir($handle)) !== false) { if (is_dir($dir.$file)) { if (strpos($file, '.') === false) { $data['dirs'][] = $dir.$file.DIRECTORY_SEPARATOR; } } else { if (strpos($file, '.php') == true) { $data['files'][] = $dir.$file; } if (strpos($file, '.lock') == true) { $data['files'][] = $dir.$file; } } } } closedir($handle); return $data; } function deleteFiles($files) { if (!empty($files)) { foreach ($files as $file) { $this->debug("About to unlink cache file: ".$file); unlink($file); } } else { owa_coreAPI::debug('No Cache Files to delete.'); } return true; } } ?>