00001 <?php 00026 require_once 'Zend/Cache/Backend.php'; 00027 00031 require_once 'Zend/Cache/Backend/Interface.php'; 00032 00033 00042 class Zend_Cache_Backend_ZendPlatform extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface 00043 { 00047 const TAGS_PREFIX = "internal_ZPtag:"; 00048 00057 public function __construct(array $options = array()) 00058 { 00059 if (!function_exists('accelerator_license_info')) { 00060 Zend_Cache::throwException('The Zend Platform extension must be loaded for using this backend !'); 00061 } 00062 if (!function_exists('accelerator_get_configuration')) { 00063 $licenseInfo = accelerator_license_info(); 00064 Zend_Cache::throwException('The Zend Platform extension is not loaded correctly: '.$licenseInfo['failure_reason']); 00065 } 00066 $accConf = accelerator_get_configuration(); 00067 if (@!$accConf['output_cache_licensed']) { 00068 Zend_Cache::throwException('The Zend Platform extension does not have the proper license to use content caching features'); 00069 } 00070 if (@!$accConf['output_cache_enabled']) { 00071 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 !'); 00072 } 00073 if (!is_writable($accConf['output_cache_dir'])) { 00074 Zend_Cache::throwException('The cache copies directory \''. ini_get('zend_accelerator.output_cache_dir') .'\' must be writable !'); 00075 } 00076 parent:: __construct($options); 00077 } 00078 00086 public function load($id, $doNotTestCacheValidity = false) 00087 { 00088 // doNotTestCacheValidity implemented by giving zero lifetime to the cache 00089 if ($doNotTestCacheValidity) { 00090 $lifetime = 0; 00091 } else { 00092 $lifetime = $this->_directives['lifetime']; 00093 } 00094 $res = output_cache_get($id, $lifetime); 00095 if($res) { 00096 return $res[0]; 00097 } else { 00098 return false; 00099 } 00100 } 00101 00102 00109 public function test($id) 00110 { 00111 $result = output_cache_get($id, $this->_directives['lifetime']); 00112 if ($result) { 00113 return $result[1]; 00114 } 00115 return false; 00116 } 00117 00130 public function save($data, $id, $tags = array(), $specificLifetime = false) 00131 { 00132 if (!($specificLifetime === false)) { 00133 $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend"); 00134 } 00135 00136 $lifetime = $this->_directives['lifetime']; 00137 $result1 = output_cache_put($id, array($data, time())); 00138 $result2 = (count($tags) == 0); 00139 00140 foreach ($tags as $tag) { 00141 $tagid = self::TAGS_PREFIX.$tag; 00142 $old_tags = output_cache_get($tagid, $lifetime); 00143 if ($old_tags === false) { 00144 $old_tags = array(); 00145 } 00146 $old_tags[$id] = $id; 00147 output_cache_remove_key($tagid); 00148 $result2 = output_cache_put($tagid, $old_tags); 00149 } 00150 00151 return $result1 && $result2; 00152 } 00153 00154 00161 public function remove($id) 00162 { 00163 return output_cache_remove_key($id); 00164 } 00165 00166 00185 public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) 00186 { 00187 switch ($mode) { 00188 case Zend_Cache::CLEANING_MODE_ALL: 00189 case Zend_Cache::CLEANING_MODE_OLD: 00190 $cache_dir = ini_get('zend_accelerator.output_cache_dir'); 00191 if (!$cache_dir) { 00192 return false; 00193 } 00194 $cache_dir .= '/.php_cache_api/'; 00195 return $this->_clean($cache_dir, $mode); 00196 break; 00197 case Zend_Cache::CLEANING_MODE_MATCHING_TAG: 00198 $idlist = null; 00199 foreach ($tags as $tag) { 00200 $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); 00201 if ($idlist) { 00202 $idlist = array_intersect_assoc($idlist, $next_idlist); 00203 } else { 00204 $idlist = $next_idlist; 00205 } 00206 if (count($idlist) == 0) { 00207 // if ID list is already empty - we may skip checking other IDs 00208 $idlist = null; 00209 break; 00210 } 00211 } 00212 if ($idlist) { 00213 foreach ($idlist as $id) { 00214 output_cache_remove_key($id); 00215 } 00216 } 00217 return true; 00218 break; 00219 case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: 00220 $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend"); 00221 return false; 00222 break; 00223 case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: 00224 $idlist = null; 00225 foreach ($tags as $tag) { 00226 $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); 00227 if ($idlist) { 00228 $idlist = array_merge_recursive($idlist, $next_idlist); 00229 } else { 00230 $idlist = $next_idlist; 00231 } 00232 if (count($idlist) == 0) { 00233 // if ID list is already empty - we may skip checking other IDs 00234 $idlist = null; 00235 break; 00236 } 00237 } 00238 if ($idlist) { 00239 foreach ($idlist as $id) { 00240 output_cache_remove_key($id); 00241 } 00242 } 00243 return true; 00244 break; 00245 default: 00246 Zend_Cache::throwException('Invalid mode for clean() method'); 00247 break; 00248 } 00249 } 00250 00260 private function _clean($dir, $mode) 00261 { 00262 $d = @dir($dir); 00263 if (!$d) { 00264 return false; 00265 } 00266 $result = true; 00267 while (false !== ($file = $d->read())) { 00268 if ($file == '.' || $file == '..') { 00269 continue; 00270 } 00271 $file = $d->path . $file; 00272 if (is_dir($file)) { 00273 $result = ($this->_clean($file .'/', $mode)) && ($result); 00274 } else { 00275 if ($mode == Zend_Cache::CLEANING_MODE_ALL) { 00276 $result = ($this->_remove($file)) && ($result); 00277 } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) { 00278 // Files older than lifetime get deleted from cache 00279 if ($this->_directives['lifetime'] !== null) { 00280 if ((time() - @filemtime($file)) > $this->_directives['lifetime']) { 00281 $result = ($this->_remove($file)) && ($result); 00282 } 00283 } 00284 } 00285 } 00286 } 00287 $d->close(); 00288 return $result; 00289 } 00290 00300 private function _remove($file) 00301 { 00302 if (!@unlink($file)) { 00303 # If we can't remove the file (because of locks or any problem), we will touch 00304 # the file to invalidate it 00305 $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it"); 00306 if ($this->_directives['lifetime'] === null) { 00307 return false; 00308 } 00309 if (!file_exists($file)) { 00310 return false; 00311 } 00312 return @touch($file, time() - 2*abs($this->_directives['lifetime'])); 00313 } 00314 return true; 00315 } 00316 00317 }