File indexing completed on 2025-01-19 05:20:57
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Cache 0017 * @subpackage Zend_Cache_Backend 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Cache_Backend_Interface 0025 */ 0026 // require_once 'Zend/Cache/Backend/ExtendedInterface.php'; 0027 0028 /** 0029 * @see Zend_Cache_Backend 0030 */ 0031 // require_once 'Zend/Cache/Backend.php'; 0032 0033 0034 /** 0035 * @package Zend_Cache 0036 * @subpackage Zend_Cache_Backend 0037 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0038 * @license http://framework.zend.com/license/new-bsd New BSD License 0039 */ 0040 class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface 0041 { 0042 /** 0043 * Available options 0044 * 0045 * =====> (string) cache_dir : 0046 * - Directory where to put the cache files 0047 * 0048 * =====> (boolean) file_locking : 0049 * - Enable / disable file_locking 0050 * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread 0051 * webservers and on NFS filesystems for example 0052 * 0053 * =====> (boolean) read_control : 0054 * - Enable / disable read control 0055 * - If enabled, a control key is embeded in cache file and this key is compared with the one 0056 * calculated after the reading. 0057 * 0058 * =====> (string) read_control_type : 0059 * - Type of read control (only if read control is enabled). Available values are : 0060 * 'md5' for a md5 hash control (best but slowest) 0061 * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice) 0062 * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32) 0063 * 'strlen' for a length only test (fastest) 0064 * 0065 * =====> (int) hashed_directory_level : 0066 * - Hashed directory level 0067 * - Set the hashed directory structure level. 0 means "no hashed directory 0068 * structure", 1 means "one level of directory", 2 means "two levels"... 0069 * This option can speed up the cache only when you have many thousands of 0070 * cache file. Only specific benchs can help you to choose the perfect value 0071 * for you. Maybe, 1 or 2 is a good start. 0072 * 0073 * =====> (int) hashed_directory_umask : 0074 * - deprecated 0075 * - Permissions for hashed directory structure 0076 * 0077 * =====> (int) hashed_directory_perm : 0078 * - Permissions for hashed directory structure 0079 * 0080 * =====> (string) file_name_prefix : 0081 * - prefix for cache files 0082 * - be really carefull with this option because a too generic value in a system cache dir 0083 * (like /tmp) can cause disasters when cleaning the cache 0084 * 0085 * =====> (int) cache_file_umask : 0086 * - deprecated 0087 * - Permissions for cache files 0088 * 0089 * =====> (int) cache_file_perm : 0090 * - Permissions for cache files 0091 * 0092 * =====> (int) metatadatas_array_max_size : 0093 * - max size for the metadatas array (don't change this value unless you 0094 * know what you are doing) 0095 * 0096 * @var array available options 0097 */ 0098 protected $_options = array( 0099 'cache_dir' => null, 0100 'file_locking' => true, 0101 'read_control' => true, 0102 'read_control_type' => 'crc32', 0103 'hashed_directory_level' => 0, 0104 'hashed_directory_perm' => 0700, 0105 'file_name_prefix' => 'zend_cache', 0106 'cache_file_perm' => 0600, 0107 'metadatas_array_max_size' => 100 0108 ); 0109 0110 /** 0111 * Array of metadatas (each item is an associative array) 0112 * 0113 * @var array 0114 */ 0115 protected $_metadatasArray = array(); 0116 0117 0118 /** 0119 * Constructor 0120 * 0121 * @param array $options associative array of options 0122 * @throws Zend_Cache_Exception 0123 */ 0124 public function __construct(array $options = array()) 0125 { 0126 parent::__construct($options); 0127 if ($this->_options['cache_dir'] !== null) { // particular case for this option 0128 $this->setCacheDir($this->_options['cache_dir']); 0129 } else { 0130 $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false); 0131 } 0132 if (isset($this->_options['file_name_prefix'])) { // particular case for this option 0133 if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) { 0134 Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]'); 0135 } 0136 } 0137 if ($this->_options['metadatas_array_max_size'] < 10) { 0138 Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10'); 0139 } 0140 0141 if (isset($options['hashed_directory_umask'])) { 0142 // See #ZF-12047 0143 trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE); 0144 if (!isset($options['hashed_directory_perm'])) { 0145 $options['hashed_directory_perm'] = $options['hashed_directory_umask']; 0146 } 0147 } 0148 if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) { 0149 // See #ZF-4422 0150 $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']); 0151 } 0152 0153 if (isset($options['cache_file_umask'])) { 0154 // See #ZF-12047 0155 trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE); 0156 if (!isset($options['cache_file_perm'])) { 0157 $options['cache_file_perm'] = $options['cache_file_umask']; 0158 } 0159 } 0160 if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) { 0161 // See #ZF-4422 0162 $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']); 0163 } 0164 } 0165 0166 /** 0167 * Set the cache_dir (particular case of setOption() method) 0168 * 0169 * @param string $value 0170 * @param boolean $trailingSeparator If true, add a trailing separator is necessary 0171 * @throws Zend_Cache_Exception 0172 * @return void 0173 */ 0174 public function setCacheDir($value, $trailingSeparator = true) 0175 { 0176 if (!is_dir($value)) { 0177 Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value)); 0178 } 0179 if (!is_writable($value)) { 0180 Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value)); 0181 } 0182 if ($trailingSeparator) { 0183 // add a trailing DIRECTORY_SEPARATOR if necessary 0184 $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR; 0185 } 0186 $this->_options['cache_dir'] = $value; 0187 } 0188 0189 /** 0190 * Test if a cache is available for the given id and (if yes) return it (false else) 0191 * 0192 * @param string $id cache id 0193 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested 0194 * @return string|false cached datas 0195 */ 0196 public function load($id, $doNotTestCacheValidity = false) 0197 { 0198 if (!($this->_test($id, $doNotTestCacheValidity))) { 0199 // The cache is not hit ! 0200 return false; 0201 } 0202 $metadatas = $this->_getMetadatas($id); 0203 $file = $this->_file($id); 0204 $data = $this->_fileGetContents($file); 0205 if ($this->_options['read_control']) { 0206 $hashData = $this->_hash($data, $this->_options['read_control_type']); 0207 $hashControl = $metadatas['hash']; 0208 if ($hashData != $hashControl) { 0209 // Problem detected by the read control ! 0210 $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match'); 0211 $this->remove($id); 0212 return false; 0213 } 0214 } 0215 return $data; 0216 } 0217 0218 /** 0219 * Test if a cache is available or not (for the given id) 0220 * 0221 * @param string $id cache id 0222 * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record 0223 */ 0224 public function test($id) 0225 { 0226 clearstatcache(); 0227 return $this->_test($id, false); 0228 } 0229 0230 /** 0231 * Save some string datas into a cache record 0232 * 0233 * Note : $data is always "string" (serialization is done by the 0234 * core not by the backend) 0235 * 0236 * @param string $data Datas to cache 0237 * @param string $id Cache id 0238 * @param array $tags Array of strings, the cache record will be tagged by each string entry 0239 * @param boolean|int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) 0240 * @return boolean true if no problem 0241 */ 0242 public function save($data, $id, $tags = array(), $specificLifetime = false) 0243 { 0244 clearstatcache(); 0245 $file = $this->_file($id); 0246 $path = $this->_path($id); 0247 if ($this->_options['hashed_directory_level'] > 0) { 0248 if (!is_writable($path)) { 0249 // maybe, we just have to build the directory structure 0250 $this->_recursiveMkdirAndChmod($id); 0251 } 0252 if (!is_writable($path)) { 0253 return false; 0254 } 0255 } 0256 if ($this->_options['read_control']) { 0257 $hash = $this->_hash($data, $this->_options['read_control_type']); 0258 } else { 0259 $hash = ''; 0260 } 0261 $metadatas = array( 0262 'hash' => $hash, 0263 'mtime' => time(), 0264 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)), 0265 'tags' => $tags 0266 ); 0267 $res = $this->_setMetadatas($id, $metadatas); 0268 if (!$res) { 0269 $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata'); 0270 return false; 0271 } 0272 $res = $this->_filePutContents($file, $data); 0273 return $res; 0274 } 0275 0276 /** 0277 * Remove a cache record 0278 * 0279 * @param string $id cache id 0280 * @return boolean true if no problem 0281 */ 0282 public function remove($id) 0283 { 0284 $file = $this->_file($id); 0285 $boolRemove = $this->_remove($file); 0286 $boolMetadata = $this->_delMetadatas($id); 0287 return $boolMetadata && $boolRemove; 0288 } 0289 0290 /** 0291 * Clean some cache records 0292 * 0293 * Available modes are : 0294 * 0295 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) 0296 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) 0297 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags 0298 * ($tags can be an array of strings or a single string) 0299 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} 0300 * ($tags can be an array of strings or a single string) 0301 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags 0302 * ($tags can be an array of strings or a single string) 0303 * 0304 * @param string $mode clean mode 0305 * @param array $tags array of tags 0306 * @return boolean true if no problem 0307 */ 0308 public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) 0309 { 0310 // We use this protected method to hide the recursive stuff 0311 clearstatcache(); 0312 return $this->_clean($this->_options['cache_dir'], $mode, $tags); 0313 } 0314 0315 /** 0316 * Return an array of stored cache ids 0317 * 0318 * @return array array of stored cache ids (string) 0319 */ 0320 public function getIds() 0321 { 0322 return $this->_get($this->_options['cache_dir'], 'ids', array()); 0323 } 0324 0325 /** 0326 * Return an array of stored tags 0327 * 0328 * @return array array of stored tags (string) 0329 */ 0330 public function getTags() 0331 { 0332 return $this->_get($this->_options['cache_dir'], 'tags', array()); 0333 } 0334 0335 /** 0336 * Return an array of stored cache ids which match given tags 0337 * 0338 * In case of multiple tags, a logical AND is made between tags 0339 * 0340 * @param array $tags array of tags 0341 * @return array array of matching cache ids (string) 0342 */ 0343 public function getIdsMatchingTags($tags = array()) 0344 { 0345 return $this->_get($this->_options['cache_dir'], 'matching', $tags); 0346 } 0347 0348 /** 0349 * Return an array of stored cache ids which don't match given tags 0350 * 0351 * In case of multiple tags, a logical OR is made between tags 0352 * 0353 * @param array $tags array of tags 0354 * @return array array of not matching cache ids (string) 0355 */ 0356 public function getIdsNotMatchingTags($tags = array()) 0357 { 0358 return $this->_get($this->_options['cache_dir'], 'notMatching', $tags); 0359 } 0360 0361 /** 0362 * Return an array of stored cache ids which match any given tags 0363 * 0364 * In case of multiple tags, a logical AND is made between tags 0365 * 0366 * @param array $tags array of tags 0367 * @return array array of any matching cache ids (string) 0368 */ 0369 public function getIdsMatchingAnyTags($tags = array()) 0370 { 0371 return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags); 0372 } 0373 0374 /** 0375 * Return the filling percentage of the backend storage 0376 * 0377 * @throws Zend_Cache_Exception 0378 * @return int integer between 0 and 100 0379 */ 0380 public function getFillingPercentage() 0381 { 0382 $free = disk_free_space($this->_options['cache_dir']); 0383 $total = disk_total_space($this->_options['cache_dir']); 0384 if ($total == 0) { 0385 Zend_Cache::throwException('can\'t get disk_total_space'); 0386 } else { 0387 if ($free >= $total) { 0388 return 100; 0389 } 0390 return ((int) (100. * ($total - $free) / $total)); 0391 } 0392 } 0393 0394 /** 0395 * Return an array of metadatas for the given cache id 0396 * 0397 * The array must include these keys : 0398 * - expire : the expire timestamp 0399 * - tags : a string array of tags 0400 * - mtime : timestamp of last modification time 0401 * 0402 * @param string $id cache id 0403 * @return array array of metadatas (false if the cache id is not found) 0404 */ 0405 public function getMetadatas($id) 0406 { 0407 $metadatas = $this->_getMetadatas($id); 0408 if (!$metadatas) { 0409 return false; 0410 } 0411 if (time() > $metadatas['expire']) { 0412 return false; 0413 } 0414 return array( 0415 'expire' => $metadatas['expire'], 0416 'tags' => $metadatas['tags'], 0417 'mtime' => $metadatas['mtime'] 0418 ); 0419 } 0420 0421 /** 0422 * Give (if possible) an extra lifetime to the given cache id 0423 * 0424 * @param string $id cache id 0425 * @param int $extraLifetime 0426 * @return boolean true if ok 0427 */ 0428 public function touch($id, $extraLifetime) 0429 { 0430 $metadatas = $this->_getMetadatas($id); 0431 if (!$metadatas) { 0432 return false; 0433 } 0434 if (time() > $metadatas['expire']) { 0435 return false; 0436 } 0437 $newMetadatas = array( 0438 'hash' => $metadatas['hash'], 0439 'mtime' => time(), 0440 'expire' => $metadatas['expire'] + $extraLifetime, 0441 'tags' => $metadatas['tags'] 0442 ); 0443 $res = $this->_setMetadatas($id, $newMetadatas); 0444 if (!$res) { 0445 return false; 0446 } 0447 return true; 0448 } 0449 0450 /** 0451 * Return an associative array of capabilities (booleans) of the backend 0452 * 0453 * The array must include these keys : 0454 * - automatic_cleaning (is automating cleaning necessary) 0455 * - tags (are tags supported) 0456 * - expired_read (is it possible to read expired cache records 0457 * (for doNotTestCacheValidity option for example)) 0458 * - priority does the backend deal with priority when saving 0459 * - infinite_lifetime (is infinite lifetime can work with this backend) 0460 * - get_list (is it possible to get the list of cache ids and the complete list of tags) 0461 * 0462 * @return array associative of with capabilities 0463 */ 0464 public function getCapabilities() 0465 { 0466 return array( 0467 'automatic_cleaning' => true, 0468 'tags' => true, 0469 'expired_read' => true, 0470 'priority' => false, 0471 'infinite_lifetime' => true, 0472 'get_list' => true 0473 ); 0474 } 0475 0476 /** 0477 * PUBLIC METHOD FOR UNIT TESTING ONLY ! 0478 * 0479 * Force a cache record to expire 0480 * 0481 * @param string $id cache id 0482 */ 0483 public function ___expire($id) 0484 { 0485 $metadatas = $this->_getMetadatas($id); 0486 if ($metadatas) { 0487 $metadatas['expire'] = 1; 0488 $this->_setMetadatas($id, $metadatas); 0489 } 0490 } 0491 0492 /** 0493 * Get a metadatas record 0494 * 0495 * @param string $id Cache id 0496 * @return array|false Associative array of metadatas 0497 */ 0498 protected function _getMetadatas($id) 0499 { 0500 if (isset($this->_metadatasArray[$id])) { 0501 return $this->_metadatasArray[$id]; 0502 } else { 0503 $metadatas = $this->_loadMetadatas($id); 0504 if (!$metadatas) { 0505 return false; 0506 } 0507 $this->_setMetadatas($id, $metadatas, false); 0508 return $metadatas; 0509 } 0510 } 0511 0512 /** 0513 * Set a metadatas record 0514 * 0515 * @param string $id Cache id 0516 * @param array $metadatas Associative array of metadatas 0517 * @param boolean $save optional pass false to disable saving to file 0518 * @return boolean True if no problem 0519 */ 0520 protected function _setMetadatas($id, $metadatas, $save = true) 0521 { 0522 if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) { 0523 $n = (int) ($this->_options['metadatas_array_max_size'] / 10); 0524 $this->_metadatasArray = array_slice($this->_metadatasArray, $n); 0525 } 0526 if ($save) { 0527 $result = $this->_saveMetadatas($id, $metadatas); 0528 if (!$result) { 0529 return false; 0530 } 0531 } 0532 $this->_metadatasArray[$id] = $metadatas; 0533 return true; 0534 } 0535 0536 /** 0537 * Drop a metadata record 0538 * 0539 * @param string $id Cache id 0540 * @return boolean True if no problem 0541 */ 0542 protected function _delMetadatas($id) 0543 { 0544 if (isset($this->_metadatasArray[$id])) { 0545 unset($this->_metadatasArray[$id]); 0546 } 0547 $file = $this->_metadatasFile($id); 0548 return $this->_remove($file); 0549 } 0550 0551 /** 0552 * Clear the metadatas array 0553 * 0554 * @return void 0555 */ 0556 protected function _cleanMetadatas() 0557 { 0558 $this->_metadatasArray = array(); 0559 } 0560 0561 /** 0562 * Load metadatas from disk 0563 * 0564 * @param string $id Cache id 0565 * @return array|false Metadatas associative array 0566 */ 0567 protected function _loadMetadatas($id) 0568 { 0569 $file = $this->_metadatasFile($id); 0570 $result = $this->_fileGetContents($file); 0571 if (!$result) { 0572 return false; 0573 } 0574 $tmp = @unserialize($result); 0575 return $tmp; 0576 } 0577 0578 /** 0579 * Save metadatas to disk 0580 * 0581 * @param string $id Cache id 0582 * @param array $metadatas Associative array 0583 * @return boolean True if no problem 0584 */ 0585 protected function _saveMetadatas($id, $metadatas) 0586 { 0587 $file = $this->_metadatasFile($id); 0588 $result = $this->_filePutContents($file, serialize($metadatas)); 0589 if (!$result) { 0590 return false; 0591 } 0592 return true; 0593 } 0594 0595 /** 0596 * Make and return a file name (with path) for metadatas 0597 * 0598 * @param string $id Cache id 0599 * @return string Metadatas file name (with path) 0600 */ 0601 protected function _metadatasFile($id) 0602 { 0603 $path = $this->_path($id); 0604 $fileName = $this->_idToFileName('internal-metadatas---' . $id); 0605 return $path . $fileName; 0606 } 0607 0608 /** 0609 * Check if the given filename is a metadatas one 0610 * 0611 * @param string $fileName File name 0612 * @return boolean True if it's a metadatas one 0613 */ 0614 protected function _isMetadatasFile($fileName) 0615 { 0616 $id = $this->_fileNameToId($fileName); 0617 if (substr($id, 0, 21) == 'internal-metadatas---') { 0618 return true; 0619 } else { 0620 return false; 0621 } 0622 } 0623 0624 /** 0625 * Remove a file 0626 * 0627 * If we can't remove the file (because of locks or any problem), we will touch 0628 * the file to invalidate it 0629 * 0630 * @param string $file Complete file path 0631 * @return boolean True if ok 0632 */ 0633 protected function _remove($file) 0634 { 0635 if (!is_file($file)) { 0636 return false; 0637 } 0638 if (!@unlink($file)) { 0639 # we can't remove the file (because of locks or any problem) 0640 $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file"); 0641 return false; 0642 } 0643 return true; 0644 } 0645 0646 /** 0647 * Clean some cache records (protected method used for recursive stuff) 0648 * 0649 * Available modes are : 0650 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) 0651 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) 0652 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags 0653 * ($tags can be an array of strings or a single string) 0654 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} 0655 * ($tags can be an array of strings or a single string) 0656 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags 0657 * ($tags can be an array of strings or a single string) 0658 * 0659 * @param string $dir Directory to clean 0660 * @param string $mode Clean mode 0661 * @param array $tags Array of tags 0662 * @throws Zend_Cache_Exception 0663 * @return boolean True if no problem 0664 */ 0665 protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) 0666 { 0667 if (!is_dir($dir)) { 0668 return false; 0669 } 0670 $result = true; 0671 $prefix = $this->_options['file_name_prefix']; 0672 $glob = @glob($dir . $prefix . '--*'); 0673 if ($glob === false) { 0674 // On some systems it is impossible to distinguish between empty match and an error. 0675 return true; 0676 } 0677 $metadataFiles = array(); 0678 foreach ($glob as $file) { 0679 if (is_file($file)) { 0680 $fileName = basename($file); 0681 if ($this->_isMetadatasFile($fileName)) { 0682 // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files. 0683 // To do that, we need to save the list of the metadata files first. 0684 if ($mode == Zend_Cache::CLEANING_MODE_ALL) { 0685 $metadataFiles[] = $file; 0686 } 0687 continue; 0688 } 0689 $id = $this->_fileNameToId($fileName); 0690 $metadatas = $this->_getMetadatas($id); 0691 if ($metadatas === FALSE) { 0692 $metadatas = array('expire' => 1, 'tags' => array()); 0693 } 0694 switch ($mode) { 0695 case Zend_Cache::CLEANING_MODE_ALL: 0696 $result = $result && $this->remove($id); 0697 break; 0698 case Zend_Cache::CLEANING_MODE_OLD: 0699 if (time() > $metadatas['expire']) { 0700 $result = $this->remove($id) && $result; 0701 } 0702 break; 0703 case Zend_Cache::CLEANING_MODE_MATCHING_TAG: 0704 $matching = true; 0705 foreach ($tags as $tag) { 0706 if (!in_array($tag, $metadatas['tags'])) { 0707 $matching = false; 0708 break; 0709 } 0710 } 0711 if ($matching) { 0712 $result = $this->remove($id) && $result; 0713 } 0714 break; 0715 case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: 0716 $matching = false; 0717 foreach ($tags as $tag) { 0718 if (in_array($tag, $metadatas['tags'])) { 0719 $matching = true; 0720 break; 0721 } 0722 } 0723 if (!$matching) { 0724 $result = $this->remove($id) && $result; 0725 } 0726 break; 0727 case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: 0728 $matching = false; 0729 foreach ($tags as $tag) { 0730 if (in_array($tag, $metadatas['tags'])) { 0731 $matching = true; 0732 break; 0733 } 0734 } 0735 if ($matching) { 0736 $result = $this->remove($id) && $result; 0737 } 0738 break; 0739 default: 0740 Zend_Cache::throwException('Invalid mode for clean() method'); 0741 break; 0742 } 0743 } 0744 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { 0745 // Recursive call 0746 $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result; 0747 if ($mode == Zend_Cache::CLEANING_MODE_ALL) { 0748 // we try to drop the structure too 0749 @rmdir($file); 0750 } 0751 } 0752 } 0753 0754 // cycle through metadataFiles and delete orphaned ones 0755 foreach ($metadataFiles as $file) { 0756 if (file_exists($file)) { 0757 $result = $this->_remove($file) && $result; 0758 } 0759 } 0760 0761 return $result; 0762 } 0763 0764 protected function _get($dir, $mode, $tags = array()) 0765 { 0766 if (!is_dir($dir)) { 0767 return false; 0768 } 0769 $result = array(); 0770 $prefix = $this->_options['file_name_prefix']; 0771 $glob = @glob($dir . $prefix . '--*'); 0772 if ($glob === false) { 0773 // On some systems it is impossible to distinguish between empty match and an error. 0774 return array(); 0775 } 0776 foreach ($glob as $file) { 0777 if (is_file($file)) { 0778 $fileName = basename($file); 0779 $id = $this->_fileNameToId($fileName); 0780 $metadatas = $this->_getMetadatas($id); 0781 if ($metadatas === FALSE) { 0782 continue; 0783 } 0784 if (time() > $metadatas['expire']) { 0785 continue; 0786 } 0787 switch ($mode) { 0788 case 'ids': 0789 $result[] = $id; 0790 break; 0791 case 'tags': 0792 $result = array_unique(array_merge($result, $metadatas['tags'])); 0793 break; 0794 case 'matching': 0795 $matching = true; 0796 foreach ($tags as $tag) { 0797 if (!in_array($tag, $metadatas['tags'])) { 0798 $matching = false; 0799 break; 0800 } 0801 } 0802 if ($matching) { 0803 $result[] = $id; 0804 } 0805 break; 0806 case 'notMatching': 0807 $matching = false; 0808 foreach ($tags as $tag) { 0809 if (in_array($tag, $metadatas['tags'])) { 0810 $matching = true; 0811 break; 0812 } 0813 } 0814 if (!$matching) { 0815 $result[] = $id; 0816 } 0817 break; 0818 case 'matchingAny': 0819 $matching = false; 0820 foreach ($tags as $tag) { 0821 if (in_array($tag, $metadatas['tags'])) { 0822 $matching = true; 0823 break; 0824 } 0825 } 0826 if ($matching) { 0827 $result[] = $id; 0828 } 0829 break; 0830 default: 0831 Zend_Cache::throwException('Invalid mode for _get() method'); 0832 break; 0833 } 0834 } 0835 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { 0836 // Recursive call 0837 $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags); 0838 if ($recursiveRs === false) { 0839 $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"'); 0840 } else { 0841 $result = array_unique(array_merge($result, $recursiveRs)); 0842 } 0843 } 0844 } 0845 return array_unique($result); 0846 } 0847 0848 /** 0849 * Compute & return the expire time 0850 * 0851 * @param int $lifetime 0852 * @return int expire time (unix timestamp) 0853 */ 0854 protected function _expireTime($lifetime) 0855 { 0856 if ($lifetime === null) { 0857 return 9999999999; 0858 } 0859 return time() + $lifetime; 0860 } 0861 0862 /** 0863 * Make a control key with the string containing datas 0864 * 0865 * @param string $data Data 0866 * @param string $controlType Type of control 'md5', 'crc32' or 'strlen' 0867 * @throws Zend_Cache_Exception 0868 * @return string Control key 0869 */ 0870 protected function _hash($data, $controlType) 0871 { 0872 switch ($controlType) { 0873 case 'md5': 0874 return md5($data); 0875 case 'crc32': 0876 return crc32($data); 0877 case 'strlen': 0878 return strlen($data); 0879 case 'adler32': 0880 return hash('adler32', $data); 0881 default: 0882 Zend_Cache::throwException("Incorrect hash function : $controlType"); 0883 } 0884 } 0885 0886 /** 0887 * Transform a cache id into a file name and return it 0888 * 0889 * @param string $id Cache id 0890 * @return string File name 0891 */ 0892 protected function _idToFileName($id) 0893 { 0894 $prefix = $this->_options['file_name_prefix']; 0895 $result = $prefix . '---' . $id; 0896 return $result; 0897 } 0898 0899 /** 0900 * Make and return a file name (with path) 0901 * 0902 * @param string $id Cache id 0903 * @return string File name (with path) 0904 */ 0905 protected function _file($id) 0906 { 0907 $path = $this->_path($id); 0908 $fileName = $this->_idToFileName($id); 0909 return $path . $fileName; 0910 } 0911 0912 /** 0913 * Return the complete directory path of a filename (including hashedDirectoryStructure) 0914 * 0915 * @param string $id Cache id 0916 * @param boolean $parts if true, returns array of directory parts instead of single string 0917 * @return string Complete directory path 0918 */ 0919 protected function _path($id, $parts = false) 0920 { 0921 $partsArray = array(); 0922 $root = $this->_options['cache_dir']; 0923 $prefix = $this->_options['file_name_prefix']; 0924 if ($this->_options['hashed_directory_level']>0) { 0925 $hash = hash('adler32', $id); 0926 for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) { 0927 $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR; 0928 $partsArray[] = $root; 0929 } 0930 } 0931 if ($parts) { 0932 return $partsArray; 0933 } else { 0934 return $root; 0935 } 0936 } 0937 0938 /** 0939 * Make the directory strucuture for the given id 0940 * 0941 * @param string $id cache id 0942 * @return boolean true 0943 */ 0944 protected function _recursiveMkdirAndChmod($id) 0945 { 0946 if ($this->_options['hashed_directory_level'] <=0) { 0947 return true; 0948 } 0949 $partsArray = $this->_path($id, true); 0950 foreach ($partsArray as $part) { 0951 if (!is_dir($part)) { 0952 @mkdir($part, $this->_options['hashed_directory_perm']); 0953 @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations) 0954 } 0955 } 0956 return true; 0957 } 0958 0959 /** 0960 * Test if the given cache id is available (and still valid as a cache record) 0961 * 0962 * @param string $id Cache id 0963 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested 0964 * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record 0965 */ 0966 protected function _test($id, $doNotTestCacheValidity) 0967 { 0968 $metadatas = $this->_getMetadatas($id); 0969 if (!$metadatas) { 0970 return false; 0971 } 0972 if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) { 0973 return $metadatas['mtime']; 0974 } 0975 return false; 0976 } 0977 0978 /** 0979 * Return the file content of the given file 0980 * 0981 * @param string $file File complete path 0982 * @return string File content (or false if problem) 0983 */ 0984 protected function _fileGetContents($file) 0985 { 0986 $result = false; 0987 if (!is_file($file)) { 0988 return false; 0989 } 0990 $f = @fopen($file, 'rb'); 0991 if ($f) { 0992 if ($this->_options['file_locking']) @flock($f, LOCK_SH); 0993 $result = stream_get_contents($f); 0994 if ($this->_options['file_locking']) @flock($f, LOCK_UN); 0995 @fclose($f); 0996 } 0997 return $result; 0998 } 0999 1000 /** 1001 * Put the given string into the given file 1002 * 1003 * @param string $file File complete path 1004 * @param string $string String to put in file 1005 * @return boolean true if no problem 1006 */ 1007 protected function _filePutContents($file, $string) 1008 { 1009 $result = false; 1010 $f = @fopen($file, 'ab+'); 1011 if ($f) { 1012 if ($this->_options['file_locking']) @flock($f, LOCK_EX); 1013 fseek($f, 0); 1014 ftruncate($f, 0); 1015 $tmp = @fwrite($f, $string); 1016 if (!($tmp === FALSE)) { 1017 $result = true; 1018 } 1019 @fclose($f); 1020 } 1021 @chmod($file, $this->_options['cache_file_perm']); 1022 return $result; 1023 } 1024 1025 /** 1026 * Transform a file name into cache id and return it 1027 * 1028 * @param string $fileName File name 1029 * @return string Cache id 1030 */ 1031 protected function _fileNameToId($fileName) 1032 { 1033 $prefix = $this->_options['file_name_prefix']; 1034 return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName); 1035 } 1036 1037 }