| <?php |
| /** |
| * File containing the ezcCacheStorageFile class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Cache |
| * @version //autogentag// |
| * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved. |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| * @filesource |
| */ |
| |
| /** |
| * This class implements most of the methods which have been declared abstract |
| * in {@link ezcCacheStorage}, but also declares 2 new methods abstract, which |
| * have to be implemented by storage driver itself. |
| * |
| * This class is a common base class for all file system based storage classes. |
| * To implement a file system based cache storage, you simply have to derive |
| * from this class and implement the {@link ezcCacheStorageFile::fetchData()} |
| * and {@link ezcCacheStorageFile::prepareData()} methods. Everything else is |
| * done for you by the ezcCacheStorageFile base class. |
| * |
| * For example code of using a cache storage, see {@link ezcCacheManager}. |
| * |
| * The Cache package already contains several implementations of |
| * {@link ezcCacheStorageFile}. As there are: |
| * |
| * - ezcCacheStorageFileArray |
| * - ezcCacheStorageFileEvalArray |
| * - ezcCacheStorageFilePlain |
| * |
| * @package Cache |
| * @version //autogentag// |
| */ |
| abstract class ezcCacheStorageFile extends ezcCacheStorage implements ezcCacheStackableStorage, ezcCacheStackMetaDataStorage |
| { |
| /** |
| * Resource used for the lock file. |
| * |
| * @var resource(file) |
| */ |
| protected $lockResource = false; |
| |
| /** |
| * Creates a new cache storage in the given location. |
| * Creates a new cache storage for a given location. The location in case |
| * of this storage class is a valid file system directory. |
| * |
| * Options can contain the 'ttl' ( Time-To-Life ). This is per default set |
| * to 1 day. The option 'permissions' can be used to define the file |
| * permissions of created cache items. Specific ezcCacheStorageFile |
| * implementations can have additional options. |
| * |
| * For details about the options see {@link ezcCacheStorageFileOptions}. |
| * |
| * @param string $location Path to the cache location |
| * @param array(string=>string) $options Options for the cache. |
| * |
| * @throws ezcBaseFileNotFoundException |
| * If the storage location does not exist. This should usually not |
| * happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| * @throws ezcBaseFileNotFoundException |
| * If the storage location is not a directory. This should usually |
| * not happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| * @throws ezcBaseFilePermissionException |
| * If the storage location is not writeable. This should usually not |
| * happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| * @throws ezcBasePropertyNotFoundException |
| * If you tried to set a non-existent option value. The accepted |
| * options depend on the ezcCacheStorage implementation and may |
| * vary. |
| */ |
| public function __construct( $location, $options = array() ) |
| { |
| // Sanity check location |
| if ( !file_exists( $location ) || !is_dir( $location ) ) |
| { |
| throw new ezcBaseFileNotFoundException( |
| $location, |
| 'cache location', |
| 'Does not exist or is no directory.' |
| ); |
| } |
| if ( !is_readable( $location ) ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $location, |
| ezcBaseFileException::READ, |
| 'Cache location is not readable.' |
| ); |
| } |
| if ( !is_writeable( $location ) ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $location, |
| ezcBaseFileException::WRITE, |
| 'Cache location is not writeable.' |
| ); |
| } |
| |
| parent::__construct( $location ); |
| // Overwrite parent set options with new ezcCacheFileStorageOptions |
| $this->properties['options'] = new ezcCacheStorageFileOptions( $options ); |
| } |
| /** |
| * Fetch data from the cache. |
| * This method does the fetching of the data itself. In this case, the |
| * method simply includes the file and returns the value returned by the |
| * include ( or false on failure ). |
| * |
| * @param string $filename The file to fetch data from. |
| * @return mixed The fetched data or false on failure. |
| */ |
| abstract protected function fetchData( $filename ); |
| |
| /** |
| * Serialize the data for storing. |
| * Serializes a PHP variable ( except type resource and object ) to a |
| * executable PHP code representation string. |
| * |
| * @param mixed $data Simple type or array |
| * @return string The serialized data |
| * |
| * @throws ezcCacheInvalidDataException |
| * If the data submitted can not be handled by the implementation |
| * of {@link ezcCacheStorageFile}. Most implementations can not |
| * handle objects and resources. |
| */ |
| abstract protected function prepareData( $data ); |
| |
| /** |
| * Store data to the cache storage. |
| * This method stores the given cache data into the cache, assigning the |
| * ID given to it. |
| * |
| * The type of cache data which is expected by a ezcCacheStorage depends on |
| * its implementation. In most cases strings and arrays will be accepted, |
| * in some rare cases only strings might be accepted. |
| * |
| * Using attributes you can describe your cache data further. This allows |
| * you to deal with multiple cache data at once later. Some ezcCacheStorage |
| * implementations also use the attributes for storage purposes. Attributes |
| * form some kind of "extended ID". |
| * |
| * @param string $id Unique identifier for the data. |
| * @param mixed $data The data to store. |
| * @param array(string=>string) $attributes Attributes describing the |
| * cached data. |
| * |
| * @return string The ID string of the newly cached data. |
| * |
| * @throws ezcBaseFilePermissionException |
| * If an already existsing cache file could not be unlinked to |
| * store the new data (may occur, when a cache item's TTL |
| * has expired and the file should be stored with more actual |
| * data). This exception means most likely that your cache directory |
| * has been corrupted by external influences (file permission |
| * change). |
| * @throws ezcBaseFilePermissionException |
| * If the directory to store the cache file could not be created. |
| * This exception means most likely that your cache directory |
| * has been corrupted by external influences (file permission |
| * change). |
| * @throws ezcBaseFileIoException |
| * If an error occured while writing the data to the cache. If this |
| * exception occurs, a serious error occured and your storage might |
| * be corruped (e.g. broken network connection, file system broken, |
| * ...). |
| * @throws ezcCacheInvalidDataException |
| * If the data submitted can not be handled by the implementation |
| * of {@link ezcCacheStorageFile}. Most implementations can not |
| * handle objects and resources. |
| */ |
| public function store( $id, $data, $attributes = array() ) |
| { |
| $filename = $this->properties['location'] |
| . $this->generateIdentifier( $id, $attributes ); |
| if ( file_exists( $filename ) ) |
| { |
| if ( unlink( $filename ) === false ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $filename, |
| ezcBaseFileException::WRITE, |
| 'Could not delete existsing cache file.' |
| ); |
| } |
| } |
| $dataStr = $this->prepareData( $data ); |
| $dirname = dirname( $filename ); |
| if ( !is_dir( $dirname ) && !mkdir( $dirname, 0777, true ) ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $dirname, |
| ezcBaseFileException::WRITE, |
| 'Could not create directory to stor cache file.' |
| ); |
| } |
| |
| $this->storeRawData( $filename, $dataStr ); |
| |
| if ( ezcBaseFeatures::os() !== "Windows" ) |
| { |
| chmod( $filename, $this->options->permissions ); |
| } |
| return $id; |
| } |
| |
| /** |
| * Actually stores the given data. |
| * |
| * @param string $filename |
| * @param string $data |
| * @return void |
| * |
| * @throws ezcBaseFileIoException |
| * if the store fails. |
| */ |
| protected function storeRawData( $filename, $data ) |
| { |
| if ( file_put_contents( $filename, $data ) !== strlen( $data ) ) |
| { |
| throw new ezcBaseFileIoException( |
| $filename, |
| ezcBaseFileException::WRITE, |
| 'Could not write data to cache file.' |
| ); |
| } |
| } |
| |
| /** |
| * Restore data from the cache. |
| * Restores the data associated with the given cache and |
| * returns it. Please see {@link ezcCacheStorage::store()} |
| * for more detailed information of cachable datatypes. |
| * |
| * During access to cached data the caches are automatically |
| * expired. This means, that the ezcCacheStorage object checks |
| * before returning the data if it's still actual. If the cache |
| * has expired, data will be deleted and false is returned. |
| * |
| * You should always provide the attributes you assigned, although |
| * the cache storages must be able to find a cache ID even without |
| * them. BEWARE: Finding cache data only by ID can be much |
| * slower than finding it by ID and attributes. |
| * |
| * Note that with the {@link ezcCacheStorageFilePlain} all restored data |
| * will be of type string. If you expect a different data type you need to |
| * perform a cast after restoring. |
| * |
| * @param string $id The item ID to restore. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @param bool $search Whether to search for items |
| * if not found directly. |
| * |
| * @return mixed|bool The cached data on success, otherwise false. |
| * |
| * @throws ezcBaseFilePermissionException |
| * If an already existsing cache file could not be unlinked. |
| * This exception means most likely that your cache directory |
| * has been corrupted by external influences (file permission |
| * change). |
| */ |
| public function restore( $id, $attributes = array(), $search = false ) |
| { |
| $filename = $this->properties['location'] |
| . $this->generateIdentifier( $id, $attributes ); |
| if ( file_exists( $filename ) === false ) |
| { |
| if ( $search === true |
| && count( $files = $this->search( $id, $attributes ) ) === 1 ) |
| { |
| $filename = $files[0]; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| // No cached data |
| if ( file_exists( $filename ) === false ) |
| { |
| return false; |
| } |
| // Cached data outdated, purge it. |
| if ( $this->calcLifetime( $filename ) == 0 |
| && $this->properties['options']['ttl'] !== false ) |
| { |
| $this->delete( $id, $attributes ); |
| return false; |
| } |
| return ( $this->fetchData( $filename ) ); |
| } |
| |
| /** |
| * Delete data from the cache. |
| * Purges the cached data for a given ID and or attributes. Using an ID |
| * purges only the cache data for just this ID. |
| * |
| * Additional attributes provided will matched additionally. This can give |
| * you an immense speed improvement against just searching for ID ( see |
| * {@link ezcCacheStorage::restore()} ). |
| * |
| * If you only provide attributes for deletion of cache data, all cache |
| * data matching these attributes will be purged. |
| * |
| * @param string $id The item ID to purge. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @param bool $search Whether to search for items |
| * if not found directly. |
| * @return void |
| * |
| * @throws ezcBaseFilePermissionException |
| * If an already existsing cache file could not be unlinked. |
| * This exception means most likely that your cache directory |
| * has been corrupted by external influences (file permission |
| * change). |
| */ |
| public function delete( $id = null, $attributes = array(), $search = false ) |
| { |
| $filename = $this->properties['location'] |
| . $this->generateIdentifier( $id, $attributes ); |
| |
| $filesToDelete = array(); |
| if ( file_exists( $filename ) ) |
| { |
| $filesToDelete[] = $filename; |
| } |
| else if ( $search === true ) |
| { |
| $filesToDelete = $this->search( $id, $attributes ); |
| } |
| |
| $deletedIds = array(); |
| foreach ( $filesToDelete as $filename ) |
| { |
| if ( unlink( $filename ) === false ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $filename, |
| ezcBaseFileException::WRITE, |
| 'Could not unlink cache file.' |
| ); |
| } |
| $deleted = $this->extractIdentifier( $filename ); |
| $deletedIds[] = $deleted['id']; |
| } |
| return $deletedIds; |
| } |
| |
| /** |
| * Return the number of items in the cache matching a certain criteria. |
| * This method determines if cache data described by the given ID and/or |
| * attributes exists. It returns the number of cache data items found. |
| * |
| * @param string $id The item ID. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @return int Number of data items matching the criteria. |
| */ |
| public function countDataItems( $id = null, $attributes = array() ) |
| { |
| return count( $this->search( $id, $attributes ) ); |
| } |
| |
| /** |
| * Returns the time ( in seconds ) which remains for a cache object, |
| * before it gets outdated. In case the cache object is already |
| * outdated or does not exist, this method returns 0. |
| * |
| * @param string $id The item ID. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @access public |
| * @return int The remaining lifetime (0 if nonexists or oudated). |
| */ |
| public function getRemainingLifetime( $id, $attributes = array() ) |
| { |
| if ( count( $objects = $this->search( $id, $attributes ) ) > 0 ) |
| { |
| return $this->calcLifetime( $objects[0] ); |
| } |
| return 0; |
| } |
| |
| /** |
| * Purges the given number of cache items. |
| * |
| * This method minimally purges the $limit number of outdated cache items |
| * from the storage. If limit is left out, all outdated items are purged. |
| * The purged item IDs are returned. |
| * |
| * @param int $limit |
| * @return array(string) |
| */ |
| public function purge( $limit = null ) |
| { |
| $purgeCount = 0; |
| return $this->purgeRecursive( $this->properties['location'], $limit, $purgeCount ); |
| } |
| |
| /** |
| * Recursively purge cache items. |
| * |
| * Recursively purges $dir until $limit is reached. $purgeCount is the |
| * number of already purged items. |
| * |
| * @param string $dir |
| * @param int $limit |
| * @param int $purgeCount |
| */ |
| private function purgeRecursive( $dir, $limit, &$purgeCount ) |
| { |
| $purgedIds = array(); |
| |
| // Deal with files in the directory |
| if ( ( $files = glob( "{$dir}*{$this->properties['options']->extension}" ) ) === false ) |
| { |
| throw new ezcBaseFileNotFoundException( |
| $dir, |
| 'cache location', |
| 'Produced an error while globbing for files.' |
| ); |
| } |
| |
| foreach ( $files as $file ) |
| { |
| if ( $this->calcLifetime( $file ) == 0 ) |
| { |
| if ( @unlink( $file ) === false ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $file, |
| ezcBaseFileException::WRITE, |
| 'Could not unlink cache file.' |
| ); |
| } |
| $fileInfo = $this->extractIdentifier( $file ); |
| $purgedIds[] = $fileInfo['id']; |
| ++$purgeCount; |
| } |
| // Stop purging if limit is reached |
| if ( $limit !== null && $purgeCount >= $limit ) |
| { |
| return $purgedIds; |
| } |
| } |
| |
| // Deal with sub dirs, this function expects them to be marked with a |
| // slash because of the property $location |
| if ( ( $dirs = glob( "$dir*", GLOB_ONLYDIR | GLOB_MARK ) ) === false ) |
| { |
| throw new ezcBaseFileNotFoundException( |
| $dir, |
| 'cache location', |
| 'Produced an error while globbing for directories.' |
| ); |
| } |
| foreach ( $dirs as $dir ) |
| { |
| $purgedIds = array_merge( |
| $purgedIds, |
| $this->purgeRecursive( $dir, $limit, $purgeCount ) |
| ); |
| // Stop purging if limit is reached |
| if ( $limit !== null && $purgeCount >= $limit ) |
| { |
| return $purgedIds; |
| } |
| } |
| |
| // Finished purging, return IDs. |
| return $purgedIds; |
| } |
| |
| /** |
| * Resets the whole storage. |
| * |
| * Deletes all data in the storage including {@link ezcCacheStackMetaData} |
| * that was stored using {@link storeMetaData()}. |
| */ |
| public function reset() |
| { |
| $files = glob( "{$this->properties['location']}*" ); |
| foreach ( $files as $file ) |
| { |
| if ( is_dir( $file ) ) |
| { |
| ezcBaseFile::removeRecursive( $file ); |
| } |
| else |
| { |
| if ( @unlink( $file ) === false ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $file, |
| ezcBaseFileException::REMOVE, |
| 'Could not unlink cache file.' |
| ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Search the storage for data. |
| * |
| * @param string $id An item ID. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @return array(int=>string) Found cache items. |
| */ |
| protected function search( $id = null, $attributes = array() ) |
| { |
| $globArr = explode( "-", $this->generateIdentifier( $id, $attributes ), 2 ); |
| if ( sizeof( $globArr ) > 1 ) |
| { |
| $glob = $globArr[0] . "-" . strtr( $globArr[1], array( '-' => '*', '.' => '*' ) ); |
| } |
| else |
| { |
| $glob = strtr( $globArr[0], array( '-' => '*', '.' => '*' ) ); |
| } |
| $glob = ( $id === null ? '*' : '' ) . $glob; |
| return $this->searchRecursive( $glob, $this->properties['location'] ); |
| } |
| |
| /** |
| * Search the storage for data recursively. |
| * |
| * @param string $pattern Pattern used with {@link glob()}. |
| * @param mixed $directory Directory to search in. |
| * @return array(int=>string) Found cache items. |
| */ |
| protected function searchRecursive( $pattern, $directory ) |
| { |
| $itemArr = glob( $directory . $pattern ); |
| $dirArr = glob( $directory . "*", GLOB_ONLYDIR ); |
| foreach ( $dirArr as $dirEntry ) |
| { |
| $result = $this->searchRecursive( $pattern, "$dirEntry/" ); |
| $itemArr = array_merge( $itemArr, $result ); |
| } |
| return $itemArr; |
| } |
| |
| /** |
| * Checks the path in the location property exists, and is read-/writable. It |
| * throws an exception if not. |
| * |
| * @throws ezcBaseFileNotFoundException |
| * If the storage location does not exist. This should usually not |
| * happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| * @throws ezcBaseFileNotFoundException |
| * If the storage location is not a directory. This should usually |
| * not happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| * @throws ezcBaseFilePermissionException |
| * If the storage location is not writeable. This should usually not |
| * happen, since {@link ezcCacheManager::createCache()} already |
| * performs sanity checks for the cache location. In case this |
| * exception is thrown, your cache location has been corrupted |
| * after the cache was configured. |
| */ |
| protected function validateLocation() |
| { |
| if ( file_exists( $this->properties['location'] ) === false ) |
| { |
| throw new ezcBaseFileNotFoundException( |
| $this->properties['location'], |
| 'cache location' |
| ); |
| } |
| |
| if ( is_dir( $this->properties['location'] ) === false ) |
| { |
| throw new ezcBaseFileNotFoundException( |
| $this->properties['location'], |
| 'cache location', |
| 'Cache location not a directory.' |
| ); |
| } |
| |
| if ( is_writeable( $this->properties['location'] ) === false ) |
| { |
| throw new ezcBaseFilePermissionException( |
| $this->properties['location'], |
| ezcBaseFileException::WRITE, |
| 'Cache location is not a directory.' |
| ); |
| } |
| } |
| |
| /** |
| * Generate the storage internal identifier from ID and attributes. |
| * |
| * Generates the storage internal identifier out of the provided ID and the |
| * attributes. This is the default implementation and can be overloaded if |
| * necessary. |
| * |
| * @param string $id The ID. |
| * @param array(string=>string) $attributes Attributes describing the |
| * data to restore. |
| * @return string The generated identifier |
| */ |
| public function generateIdentifier( $id, $attributes = null ) |
| { |
| $filename = (string) $id; |
| $illegalFileNameChars = array( |
| ' ' => '_', |
| '/' => DIRECTORY_SEPARATOR, |
| '\\' => DIRECTORY_SEPARATOR, |
| ); |
| $filename = strtr( $filename, $illegalFileNameChars ); |
| |
| // Chars used for filename concatination |
| $illegalChars = array( |
| '-' => '#', |
| ' ' => '%', |
| '=' => '+', |
| '.' => '+', |
| ); |
| if ( is_array( $attributes ) && count( $attributes ) > 0 ) |
| { |
| ksort( $attributes ); |
| foreach ( $attributes as $key => $val ) |
| { |
| $attrStr = '-' . strtr( $key, $illegalChars ) |
| . '=' . strtr( $val, $illegalChars ); |
| if ( strlen( $filename . $attrStr ) > 250 ) |
| { |
| // Max filename length |
| break; |
| } |
| $filename .= $attrStr; |
| } |
| } |
| else |
| { |
| $filename .= '-'; |
| } |
| return $filename . $this->properties['options']['extension']; |
| } |
| |
| /** |
| * Restores and returns the meta data struct. |
| * |
| * This method fetches the meta data stored in the storage and returns the |
| * according struct of type {@link ezcCacheStackMetaData}. The meta data |
| * must be stored inside the storage, but should not be visible as normal |
| * cache items to the user. |
| * |
| * @return ezcCacheStackMetaData|null |
| */ |
| public function restoreMetaData() |
| { |
| // Silence require warnings. It's ok that meta data does not exist. |
| $dataArr = @$this->fetchData( |
| $this->properties['location'] . $this->properties['options']->metaDataFile |
| ); |
| |
| $result = null; |
| if ( $dataArr !== false ) |
| { |
| $result = new $dataArr['class'](); |
| $result->setState( $dataArr['data'] ); |
| } |
| return $result; |
| } |
| |
| /** |
| * Stores the given meta data struct. |
| * |
| * This method stores the given $metaData inside the storage. The data must |
| * be stored with the same mechanism that the storage itself uses. However, |
| * it should not be stored as a normal cache item, if possible, to avoid |
| * accedental user manipulation. |
| * |
| * @param ezcCacheStackMetaData $metaData |
| * @return void |
| */ |
| public function storeMetaData( ezcCacheStackMetaData $metaData ) |
| { |
| $dataArr = array( |
| 'class' => get_class( $metaData ), |
| 'data' => $metaData->getState(), |
| ); |
| $this->storeRawData( |
| $this->properties['location'] . $this->properties['options']->metaDataFile, |
| $this->prepareData( $dataArr ) |
| ); |
| } |
| |
| /** |
| * Acquire a lock on the storage. |
| * |
| * This method acquires a lock on the storage. If locked, the storage must |
| * block all other method calls until the lock is freed again using {@link |
| * ezcCacheStackMetaDataStorage::unlock()}. Methods that are called within |
| * the request that successfully acquired the lock must succeed as usual. |
| * |
| * @return void |
| */ |
| public function lock() |
| { |
| $lockFile = $this->properties['location'] . $this->properties['options']->lockFile; |
| |
| while ( $this->lockResource === false ) |
| { |
| clearstatcache(); |
| $this->lockResource = @fopen( $lockFile, 'x' ); |
| |
| // Wait for lock to get freed |
| if ( $this->lockResource === false ) |
| { |
| usleep( $this->properties['options']->lockWaitTime ); |
| } |
| |
| // Check if lock is to be considered dead. Might result in a |
| // nonrelevant race condition if the lock file disappears between |
| // fs calls. To avoid warnings in this case, the calls are |
| // silenced. |
| if ( file_exists( $lockFile ) && ( time() - @filemtime( $lockFile ) ) > $this->properties['options']->maxLockTime ) |
| { |
| @unlink( $lockFile ); |
| } |
| } |
| } |
| |
| /** |
| * Release a lock on the storage. |
| * |
| * This method releases the lock of the storage, that has been acquired via |
| * {@link ezcCacheStackMetaDataStorage::lock()}. After this method has been |
| * called, blocked method calls (including calls to lock()) can suceed |
| * again. |
| * |
| * @return void |
| */ |
| public function unlock() |
| { |
| // If the resource is already removed, nothing to do |
| if ( $this->lockResource !== false ) |
| { |
| fclose( $this->lockResource ); |
| @unlink( |
| $this->properties['location'] . $this->properties['options']->lockFile |
| ); |
| $this->lockResource = false; |
| } |
| } |
| |
| /** |
| * Set new options. |
| * This method allows you to change the options of a cache file storage. Change |
| * of options take effect directly after this method has been called. The |
| * available options depend on the ezcCacheStorageFile implementation. All |
| * implementations have to offer the following options: |
| * |
| * - ttl The time-to-life. After this time span, a cache item becomes |
| * invalid and will be purged. The |
| * {@link ezcCacheStorage::restore()} method will then return |
| * false. |
| * - extension The "extension" for your cache items. This is usually the |
| * file name extension, when you deal with file system based |
| * caches or e.g. a database ID extension. |
| * - permissions The file permissions to set for new files. |
| * |
| * The usage of ezcCacheStorageOptions and arrays for setting options is |
| * deprecated, but still supported. You should migrate to |
| * ezcCacheStorageFileOptions. |
| * |
| * @param ezcCacheStorageFileOptions $options The options to set (accepts |
| * ezcCacheStorageOptions or |
| * array for compatibility |
| * reasons, too). |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * If you tried to set a non-existent option value. The accepted |
| * options depend on the ezcCacheStorage implementation and may |
| * vary. |
| * @throws ezcBaseValueException |
| * If the value is not valid for the desired option. |
| * @throws ezcBaseValueException |
| * If you submit neither an instance of ezcCacheStorageFileOptions, |
| * nor an instance of ezcCacheStorageOptions nor an array. |
| */ |
| public function setOptions( $options ) |
| { |
| if ( is_array( $options ) ) |
| { |
| $this->properties['options']->merge( $options ); |
| } |
| else if ( $options instanceof ezcCacheStorageFileOptions ) |
| { |
| $this->properties['options'] = $options; |
| } |
| else if ( $options instanceof ezcCacheStorageOptions ) |
| { |
| $this->properties['options']->mergeStorageOptions( $options ); |
| } |
| else |
| { |
| throw new ezcBaseValueException( |
| 'options', |
| $options, |
| 'instance of ezcCacheStorageFileOptions or (deprecated) ezcCacheStorageOptions' |
| ); |
| } |
| } |
| |
| /** |
| * Property write access. |
| * |
| * @param string $propertyName Name of the property. |
| * @param mixed $val The value for the property. |
| * |
| * @throws ezcBaseValueException |
| * If the value for the property options is not an instance of |
| * ezcCacheStorageOptions. |
| * @ignore |
| */ |
| public function __set( $propertyName, $val ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'options': |
| if ( $val instanceof ezcCacheStorageFileOptions ) |
| { |
| $this->properties['options'] = $val; |
| return; |
| } |
| if ( $val instanceof ezcCacheStorageOptions ) |
| { |
| $this->properties['options']->mergeStorageOptions( $val ); |
| return; |
| } |
| throw new ezcBaseValueException( |
| $propertyName, |
| $val, |
| 'instance of ezcCacheStorageFileOptions' |
| ); |
| } |
| throw new ezcBasePropertyNotFoundException( $propertyName ); |
| } |
| |
| /** |
| * Calculates the lifetime remaining for a cache object. |
| * |
| * This calculates the time a cached object stays valid and returns it. In |
| * case the TTL is set to false, this method always returns a value of 1. |
| * |
| * @param string $file The file to calculate the remaining lifetime for. |
| * @return int The remaining lifetime in seconds (0 if no time remaining). |
| */ |
| protected function calcLifetime( $file ) |
| { |
| $ttl = $this->options->ttl; |
| if ( file_exists( $file ) && ( $modTime = filemtime( $file ) ) !== false ) |
| { |
| if ( $ttl === false ) |
| { |
| return 1; |
| } |
| return ( |
| ( $lifeTime = time() - $modTime ) < $ttl |
| ? $ttl - $lifeTime |
| : 0 |
| ); |
| } |
| return 0; |
| } |
| |
| /** |
| * Extracts ID, attributes and the file extension from a filename. |
| * |
| * @param string $filename |
| * @return array('id'=>string,'attributes'=>string,'ext'=>string) |
| */ |
| private function extractIdentifier( $filename ) |
| { |
| // Regex to split up the file name into id, attributes and extension |
| $regex = '( |
| (?:' . preg_quote( $this->properties['location'] ) . ') |
| (?P<id>.*) |
| (?P<attr>(?:-[^-=]+=[^-]+)*) |
| -? # This is added if no attributes are supplied. For whatever reason... |
| (?P<ext>' . preg_quote( $this->options->extension ) . ') |
| )Ux'; |
| |
| if ( preg_match( $regex, $filename, $matches ) !== 1 ) |
| { |
| // @TODO: Should this be an exception? |
| return array( |
| 'id' => '', |
| 'attributes' => '', |
| 'extension' => $this->options->extension, |
| ); |
| } |
| else |
| { |
| // Successfully split |
| return array( |
| 'id' => $matches['id'], |
| 'attributes' => $matches['attr'], |
| 'extension' => $matches['ext'], |
| ); |
| } |
| } |
| } |
| ?> |