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.php'; 0027 0028 /** 0029 * @see Zend_Cache_Backend_Interface 0030 */ 0031 // require_once 'Zend/Cache/Backend/Interface.php'; 0032 0033 0034 /** 0035 * Impementation of Zend Cache Backend using the Zend Platform (Output Content Caching) 0036 * 0037 * @package Zend_Cache 0038 * @subpackage Zend_Cache_Backend 0039 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0040 * @license http://framework.zend.com/license/new-bsd New BSD License 0041 */ 0042 class Zend_Cache_Backend_ZendPlatform extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface 0043 { 0044 /** 0045 * internal ZP prefix 0046 */ 0047 const TAGS_PREFIX = "internal_ZPtag:"; 0048 0049 /** 0050 * Constructor 0051 * Validate that the Zend Platform is loaded and licensed 0052 * 0053 * @param array $options Associative array of options 0054 * @throws Zend_Cache_Exception 0055 * @return void 0056 */ 0057 public function __construct(array $options = array()) 0058 { 0059 if (!function_exists('accelerator_license_info')) { 0060 Zend_Cache::throwException('The Zend Platform extension must be loaded for using this backend !'); 0061 } 0062 if (!function_exists('accelerator_get_configuration')) { 0063 $licenseInfo = accelerator_license_info(); 0064 Zend_Cache::throwException('The Zend Platform extension is not loaded correctly: '.$licenseInfo['failure_reason']); 0065 } 0066 $accConf = accelerator_get_configuration(); 0067 if (@!$accConf['output_cache_licensed']) { 0068 Zend_Cache::throwException('The Zend Platform extension does not have the proper license to use content caching features'); 0069 } 0070 if (@!$accConf['output_cache_enabled']) { 0071 Zend_Cache::throwException('The Zend Platform content caching feature must be enabled for using this backend, set the \'zend_accelerator.output_cache_enabled\' directive to On !'); 0072 } 0073 if (!is_writable($accConf['output_cache_dir'])) { 0074 Zend_Cache::throwException('The cache copies directory \''. ini_get('zend_accelerator.output_cache_dir') .'\' must be writable !'); 0075 } 0076 parent:: __construct($options); 0077 } 0078 0079 /** 0080 * Test if a cache is available for the given id and (if yes) return it (false else) 0081 * 0082 * @param string $id Cache id 0083 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested 0084 * @return string Cached data (or false) 0085 */ 0086 public function load($id, $doNotTestCacheValidity = false) 0087 { 0088 // doNotTestCacheValidity implemented by giving zero lifetime to the cache 0089 if ($doNotTestCacheValidity) { 0090 $lifetime = 0; 0091 } else { 0092 $lifetime = $this->_directives['lifetime']; 0093 } 0094 $res = output_cache_get($id, $lifetime); 0095 if($res) { 0096 return $res[0]; 0097 } else { 0098 return false; 0099 } 0100 } 0101 0102 0103 /** 0104 * Test if a cache is available or not (for the given id) 0105 * 0106 * @param string $id Cache id 0107 * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record 0108 */ 0109 public function test($id) 0110 { 0111 $result = output_cache_get($id, $this->_directives['lifetime']); 0112 if ($result) { 0113 return $result[1]; 0114 } 0115 return false; 0116 } 0117 0118 /** 0119 * Save some string datas into a cache record 0120 * 0121 * Note : $data is always "string" (serialization is done by the 0122 * core not by the backend) 0123 * 0124 * @param string $data Data to cache 0125 * @param string $id Cache id 0126 * @param array $tags Array of strings, the cache record will be tagged by each string entry 0127 * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) 0128 * @return boolean true if no problem 0129 */ 0130 public function save($data, $id, $tags = array(), $specificLifetime = false) 0131 { 0132 if (!($specificLifetime === false)) { 0133 $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend"); 0134 } 0135 0136 $lifetime = $this->_directives['lifetime']; 0137 $result1 = output_cache_put($id, array($data, time())); 0138 $result2 = (count($tags) == 0); 0139 0140 foreach ($tags as $tag) { 0141 $tagid = self::TAGS_PREFIX.$tag; 0142 $old_tags = output_cache_get($tagid, $lifetime); 0143 if ($old_tags === false) { 0144 $old_tags = array(); 0145 } 0146 $old_tags[$id] = $id; 0147 output_cache_remove_key($tagid); 0148 $result2 = output_cache_put($tagid, $old_tags); 0149 } 0150 0151 return $result1 && $result2; 0152 } 0153 0154 0155 /** 0156 * Remove a cache record 0157 * 0158 * @param string $id Cache id 0159 * @return boolean True if no problem 0160 */ 0161 public function remove($id) 0162 { 0163 return output_cache_remove_key($id); 0164 } 0165 0166 0167 /** 0168 * Clean some cache records 0169 * 0170 * Available modes are : 0171 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) 0172 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) 0173 * This mode is not supported in this backend 0174 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags 0175 * ($tags can be an array of strings or a single string) 0176 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => unsupported 0177 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags 0178 * ($tags can be an array of strings or a single string) 0179 * 0180 * @param string $mode Clean mode 0181 * @param array $tags Array of tags 0182 * @throws Zend_Cache_Exception 0183 * @return boolean True if no problem 0184 */ 0185 public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) 0186 { 0187 switch ($mode) { 0188 case Zend_Cache::CLEANING_MODE_ALL: 0189 case Zend_Cache::CLEANING_MODE_OLD: 0190 $cache_dir = ini_get('zend_accelerator.output_cache_dir'); 0191 if (!$cache_dir) { 0192 return false; 0193 } 0194 $cache_dir .= '/.php_cache_api/'; 0195 return $this->_clean($cache_dir, $mode); 0196 break; 0197 case Zend_Cache::CLEANING_MODE_MATCHING_TAG: 0198 $idlist = null; 0199 foreach ($tags as $tag) { 0200 $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); 0201 if ($idlist) { 0202 $idlist = array_intersect_assoc($idlist, $next_idlist); 0203 } else { 0204 $idlist = $next_idlist; 0205 } 0206 if (count($idlist) == 0) { 0207 // if ID list is already empty - we may skip checking other IDs 0208 $idlist = null; 0209 break; 0210 } 0211 } 0212 if ($idlist) { 0213 foreach ($idlist as $id) { 0214 output_cache_remove_key($id); 0215 } 0216 } 0217 return true; 0218 break; 0219 case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: 0220 $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend"); 0221 return false; 0222 break; 0223 case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: 0224 $idlist = null; 0225 foreach ($tags as $tag) { 0226 $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); 0227 if ($idlist) { 0228 $idlist = array_merge_recursive($idlist, $next_idlist); 0229 } else { 0230 $idlist = $next_idlist; 0231 } 0232 if (count($idlist) == 0) { 0233 // if ID list is already empty - we may skip checking other IDs 0234 $idlist = null; 0235 break; 0236 } 0237 } 0238 if ($idlist) { 0239 foreach ($idlist as $id) { 0240 output_cache_remove_key($id); 0241 } 0242 } 0243 return true; 0244 break; 0245 default: 0246 Zend_Cache::throwException('Invalid mode for clean() method'); 0247 break; 0248 } 0249 } 0250 0251 /** 0252 * Clean a directory and recursivly go over it's subdirectories 0253 * 0254 * Remove all the cached files that need to be cleaned (according to mode and files mtime) 0255 * 0256 * @param string $dir Path of directory ot clean 0257 * @param string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean() 0258 * @return boolean True if ok 0259 */ 0260 private function _clean($dir, $mode) 0261 { 0262 $d = @dir($dir); 0263 if (!$d) { 0264 return false; 0265 } 0266 $result = true; 0267 while (false !== ($file = $d->read())) { 0268 if ($file == '.' || $file == '..') { 0269 continue; 0270 } 0271 $file = $d->path . $file; 0272 if (is_dir($file)) { 0273 $result = ($this->_clean($file .'/', $mode)) && ($result); 0274 } else { 0275 if ($mode == Zend_Cache::CLEANING_MODE_ALL) { 0276 $result = ($this->_remove($file)) && ($result); 0277 } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) { 0278 // Files older than lifetime get deleted from cache 0279 if ($this->_directives['lifetime'] !== null) { 0280 if ((time() - @filemtime($file)) > $this->_directives['lifetime']) { 0281 $result = ($this->_remove($file)) && ($result); 0282 } 0283 } 0284 } 0285 } 0286 } 0287 $d->close(); 0288 return $result; 0289 } 0290 0291 /** 0292 * Remove a file 0293 * 0294 * If we can't remove the file (because of locks or any problem), we will touch 0295 * the file to invalidate it 0296 * 0297 * @param string $file Complete file path 0298 * @return boolean True if ok 0299 */ 0300 private function _remove($file) 0301 { 0302 if (!@unlink($file)) { 0303 # If we can't remove the file (because of locks or any problem), we will touch 0304 # the file to invalidate it 0305 $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it"); 0306 if ($this->_directives['lifetime'] === null) { 0307 return false; 0308 } 0309 if (!file_exists($file)) { 0310 return false; 0311 } 0312 return @touch($file, time() - 2*abs($this->_directives['lifetime'])); 0313 } 0314 return true; 0315 } 0316 0317 }