getBackendEnableStatus('Memcached') <= self::STATUS_DISABLED_ERROR) { throw new Exception('Cache Backend memcached is disabled.'); } // Instanciate on first need if (!$this->backendMemcached instanceof Zend_Cache_Backend_Memcached) { try { // Set memcached options $cfg = $this->_getConfig(Array('backend','memcached')); $options = array( 'servers' => array(array( 'host' => $cfg->get('host','localhost'), 'port' => $cfg->get('port','11211'), 'failure_callback' => Factory::getMostSpecificClass('Cache_Backend_Memcached').'::failureCallback', )) ); $this->backendMemcached = Factory::getNewInstance('Cache_Backend_Memcached'); // Check if connection works $this->backendMemcached->save('123', 123); if (!$this->backendMemcached->test(123)) { $this->backendMemcachedEnabled = self::STATUS_DISABLED_ERROR; throw new Exception('Cache Backend memcached is not reachable.'); } } catch(Exception $e) { // Log Broker::getLog()->log($e->getMessage(),Zend_Log::ERR); // Hard disable on error $this->backendMemcachedEnabled = self::STATUS_DISABLED_ERROR; // Rethrow error, as we cannot return a valid backend throw $e; } } // Return Singleton return $this->backendMemcached; } /** * Add an entry to the memcache (if installed) and optionally to filesystem, too. * * The cache fallback to filesystem can be useful if memcache is not installed, * or if the memcache entry was displaced. * * @param mixed $data The data you want to cache. Will be serialized internally. * @param String $key The name under which the cache lies. Must be unique. * @param Array $filenames Files to be watched, if site is not live * @param Int $fallback_to_file 1=Use File Cache if memcache is not available, 2=use only file * @param Array $tags Tags for the cache entry. * @param Int $ttl Time to live. If set to false, it will not expire. * * @return boolean True if adding to cache succeeded. */ public function addMemcache($data, $key, $filenames=array(), $fallback_to_file=false, $tags=array(), $ttl=false) { // Cache disabled completely if (!$this->isEnabled()) { return false; } // One of the tags is disabled if ($this->isTagDisabled($tags)) { return FALSE; } try { // Check which backend is active $memcached_enabled = $this->getBackendEnableStatus('Memcached')==self::STATUS_ENABLED; $file_enabled = $this->getBackendEnableStatus('File')==self::STATUS_ENABLED; // Neither memcache nor file cache active if (!$memcached_enabled && (!$fallback_to_file || !$file_enabled)) { return false; } // escape the key $key = $this->escapeCacheKey($key); /* Remember file mtimes, if site is in development mode */ if (!Bootstrap::siteIsLive()) { $mtimes = Array(); foreach ($filenames AS $file) { if (file_exists($file)) { $mtimes[$file] = filemtime($file); } } /* Save file information and data */ $entry = Array( 'entry' => $data, 'filenames' => $mtimes ); // In live mode, this is much faster without filesystem operations } else { $entry = Array( 'entry' => $data, 'filenames' => Array() ); } $succ = false; // Save to memcache if ($fallback_to_file!==2 && $memcached_enabled) { $succ = $this->getBackendMemcached()->save($entry,$key,$tags,$ttl); } // Save to filesystem if ($fallback_to_file && $file_enabled) { $succ |= $this->getBackendFile()->save(serialize($entry),$key,$tags,$ttl); } return $succ; // Something failed (e.g. extension not installed) } catch (Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); return false; } } /** * Recieve the cache entry from the memcache. * * Optionally it is recieved from filesystem, if memcache entry was not found. * * @param String $key The name under which the cache lies. Must be unique. * @param boolean $fallback_to_file Use filesystem cache as fallback. * * @return mixed The data put into the cache. Null if nothing was found. */ public function deliverMemcache($key, $fallback_to_file=false) { // Cache is somehow disabled if (!$this->isEnabled()) { return null; } try { // Neither memcache nor file cache active $memcached_enabled = $this->getBackendEnableStatus('Memcached')==self::STATUS_ENABLED; $file_enabled = $this->getBackendEnableStatus('File')==self::STATUS_ENABLED; if (!$memcached_enabled && (!$fallback_to_file || !$file_enabled)) { return null; } // escape the key $key = $this->escapeCacheKey($key); // No Cache available in memcache $no_mem = FALSE; if (!$memcached_enabled || !$this->getBackendMemcached()->test($key)) { $no_mem = TRUE; // No cache available in file if (!$file_enabled || !$fallback_to_file || !$this->getBackendFile()->test($key)) { return null; } } // Load entry from memcache or file if ($no_mem) { $entry = unserialize($this->getBackendFile()->load($key)); } else { $entry = $this->getBackendMemcached()->load($key); } // No entry available (even if we tested it before) if ($entry===FALSE) { return null; } // Check for file modifications, if not live if (!Bootstrap::siteIsLive()) { // Check for each file if it has been modified. If so -> no cache foreach ($entry['filenames'] AS $file => $mtime) { if (!file_exists($file) || filemtime($file)!=$mtime) { return null; } } } // Deliver the content return $entry['entry']; // Something failed (e.g. extension not installed) } catch (Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); return null; } } /** * Clean memcache completely. This is sometimes neccessary, if tags must * be purged, because memcache does not support tagging. * * @return Boolean */ public function purgeMemcache() { // Backend is disabled hard if ($this->getBackendEnableStatus('Memcached') < self::STATUS_DISABLED_TEMPORARILY) { return false; } // Purge Backend try { $succ = $this->getBackendMemcached()->clean(); // Disable backend temporarily $this->backendMemcachedEnabled = self::STATUS_DISABLED_TEMPORARILY; return $succ; // Something failed (e.g. extension not installed) } catch (Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); } return false; } /*************************************************************************/ /* File Backend */ /*************************************************************************/ /** * Get file backend * * @return Zend_Cache_Backend_File */ public function getBackendFile() { // Cache disabled and uninstanciatable! if ($this->getBackendEnableStatus('File') <= self::STATUS_DISABLED_ERROR) { throw new Exception('Cache Backend file is disabled.'); } // Instanciate on first need if (!$this->backendFile instanceof Redspark_Cache_Backend_File) { try { // Get backend sepcific options $cfg = $this->_getConfig(Array('backend','file')); $options = Array( 'hashed_directory_level' => $cfg->get('hashed_directory_level',1), ); $this->backendFile = Factory::getNewInstance('Cache_Backend_File'); } catch(Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::ERR); // Hard disable on error $this->backendFileEnabled = self::STATUS_DISABLED_ERROR; // Rethrow error, as we cannot return a valid backend throw $e; } } return $this->backendFile; } /** * Purge all file-caches from filesystem. * * @return Boolean */ public function purgeFile() { // Backend is disabled hard if ($this->getBackendEnableStatus('File') < self::STATUS_DISABLED_TEMPORARILY) { return false; } // Purge Backend try { $succ = $this->getBackendFile()->clean(); // Disable backend temporarily $this->backendFileEnabled = self::STATUS_DISABLED_TEMPORARILY; return $succ; // Something failed (e.g. extension not installed) } catch (Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); } return false; } /*************************************************************************/ /* Proxy Backend */ /*************************************************************************/ /** * Get Proxy cache backend * * @return Redspark_Cache_Backend_Proxy */ public function getBackendProxy() { // Cache disabled and uninstanciatable! if ($this->getBackendEnableStatus('Proxy') <= self::STATUS_DISABLED_ERROR) { throw new Exception('Cache Backend Proxy is disabled.'); } // Instanciate on first need if (!$this->backendProxy instanceof Redspark_Cache_Backend_Proxy) { try { $this->backendProxy = Factory::getNewInstance('Cache_Backend_Proxy'); } catch(Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::ERR); // Hard disable on error $this->backendProxyEnabled = self::STATUS_DISABLED_ERROR; // Rethrow error, as we cannot return a valid backend throw $e; } } // return singleton return $this->backendProxy; } /** * Set an entry to be cached by a reversed proxy * * @param Redspark_Cache_Entity_Proxy $entity * * @return Boolean */ public function addProxy($entity) { // Check if cache backend is disabled if ($this->getBackendEnableStatus('Proxy') != self::STATUS_ENABLED) { return false; } // Check if cache in general is disabled if (!$this->isEnabled()) { return false; } // Check if one of the tags is disabled if ($this->isTagDisabled($entity->tags)) { return false; } // Check if is cache is disabled via action if (!$entity->enabled) { return false; } // Build cache id $rq = Broker::getRequest(); if ($rq instanceof Zend_Controller_Request_Abstract) { $id = $rq->getRequestUri(); } else { $id = $_SERVER['REQUEST_URI']; } // Add to cache $proxy = $this->getBackendProxy(); return $proxy->save(null, $id, $entity->tags, $entity->ttl); } /** * Delivering is done at the end of the script. In this case that means * sending of the correct headers * */ public function deliverProxy() { // Check if cache backend is disabled if ($this->getBackendEnableStatus('Proxy') != self::STATUS_ENABLED) { return false; } // Check if cache in general is disabled if (!$this->isEnabled()) { return false; } // Purge backend $proxy = $this->getBackendProxy(); return $proxy->sendHeaders(); } /** * Purge the whole proxy cache * * @return Boolean true on success */ public function purgeProxy() { // Check if cache backend is disabled hard. Temp disables are still working if ($this->getBackendEnableStatus('Proxy') < self::STATUS_DISABLED_TEMPORARILY) { return FALSE; } // Purge backend $proxy = $this->getBackendProxy(); $stat = $proxy->clean(); // Disable backend temporarily $this->backendProxyEnabled = self::STATUS_DISABLED_TEMPORARILY; return $stat; // Inform all interested modules /*foreach(Broker::getModuleControllers('RedSparkCore_RsModule_Abstract_Controller_Interface_CachePurge') AS $mod) { $mod->cachePurgeHook(RedSparkCore_RsModule_Abstract_Controller_Interface_CachePurge::PURGE_BACKEND,'proxy'); }*/ } /*************************************************************************/ /* Static Backend */ /*************************************************************************/ /** * Get static cache backend * * @return Redspark_Cache_Backend_Proxy */ public function getBackendStatic() { // Cache disabled and uninstanciatable! if ($this->getBackendEnableStatus('Static') <= self::STATUS_DISABLED_ERROR) { throw new Exception('Cache Backend Static is disabled.'); } // Instanciate on first need if (!$this->backendStatic instanceof Redspark_Cache_Backend_Static) { try { $this->backendStatic = Factory::getNewInstance('Cache_Backend_Static'); } catch(Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::ERR); // Hard disable on error $this->backendStaticEnabled = self::STATUS_DISABLED_ERROR; // Rethrow error, as we cannot return a valid backend throw $e; } } // return singleton return $this->backendStatic; } /** * Put a file into the static cache. * * @param String $data Binary data or HTML string. * @param String $uri URI under which the cache is to be recieved later. * @param Array $tags List of tags * @param Int $ttl Time-To-Live (muste be purged by a cron!) */ public function addStatic($data, $uri, $tags=array(), $ttl=false) { // Check if cache backend is disabled if ($this->getBackendEnableStatus('Static') != self::STATUS_ENABLED) { return false; } // Check if cache in general is disabled if (!$this->isEnabled()) { return false; } // Check if one of the tags is disabled if ($this->isTagDisabled($tags)) { return false; } // Calculate TTL. Check if overwritten globaly by cms timeswitch if ($this->_max_ttl!==false) { // No TTL set -> use global max ttl if ($ttl==false) { $ttl = $this->_max_ttl; // TTL set -> take lower one } else { $ttl = min($ttl, $this->_max_ttl); } } // Strip the protocol off the URL if (strpos($uri,'://') !== false) { $host = Broker::getRequest()->getHttpHost(); $uri = substr($uri,strpos($uri,$host) + strlen($host)); } // Auto generate tags from uri foreach(explode('/',$uri) AS $tmp) { if (empty($tmp)) { continue; } $tags[] = $tmp; } // Save cache into backend $succ = $this->getBackendStatic()->save($data, $uri, $tags, $ttl); return $succ; } /** * Purge all files from static/htdocs folder. * * @return Boolean */ public function purgeStatic() { // Backend is disabled hard if ($this->getBackendEnableStatus('Static') < self::STATUS_DISABLED_TEMPORARILY) { return false; } // Purge Backend try { $succ = $this->getBackendStatic()->clean(); // Disable backend temporarily $this->backendStaticEnabled = self::STATUS_DISABLED_TEMPORARILY; return $succ; // Something failed (e.g. extension not installed) } catch (Exception $e) { Broker::getLog()->log($e->getMessage(),Zend_Log::WARN); } return false; } /** * Purge all caches, that exceeded their TTL and are stale by now * * @return Boolean false if one of the backend fails */ public function purgeStale() { $success = true; // Static try { // Backend is not disabled by config if ($this->getBackendEnableStatus('Static') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendStatic()->clean(Zend_Cache::CLEANING_MODE_OLD); } } catch(Exception $e) { Broker::getLog()->log('Clean old cache: '.$e->getMessage(),Zend_Log::ERR); $success = false; } // File try { // Backend is not disabled by config if ($this->getBackendEnableStatus('File') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendFile()->clean(Zend_Cache::CLEANING_MODE_OLD); } } catch(Exception $e) { Broker::getLog()->log('Clean old cache: '.$e->getMessage(),Zend_Log::ERR); $success = false; } return $success; } /*************************************************************************/ /* Action Frontend */ /*************************************************************************/ /** * Add a cache entry to the cache, containig all data of an action. * * This data can either be assigns, or a fully rendered view. * * @param Redspark_Cache_Entity_Action $entity Entity object containing all data, needed. * * @return boolean True if adding to cache suceeded. */ public function addAction(Redspark_Cache_Entity_Action $entity) { // Check if cache backend is disabled if ($this->getBackendEnableStatus('File') != self::STATUS_ENABLED) { return false; } // Check if cache frontend is disabled if ($this->getFrontendEnableStatus('Action') != self::STATUS_ENABLED) { return false; } // Check if $entity is disabled if (!$entity->enabled) { return false; } // Check if cache in general is disabled if (!$this->isEnabled()) { return false; } // Check if one of the tags is disabled if ($this->isTagDisabled($entity->tags)) { return false; } // Calculate TTL. Check if overwritten globaly by cms timeswitch $ttl = $entity->ttl; if ($this->_max_ttl!==false) { $ttl = min($ttl, $this->_max_ttl); } // Generate an appropriate key $key = $entity->module.'-'.$entity->action.'-'.implode('-',$entity->params); $key = $this->escapeCacheKey($key); // Serialize assigns. View is already a string if (!$entity->with_view) { $data = serialize($entity->data); } else { $data = $entity->data; } // Save date into file backend $succ = $this->getBackendFile()->save($data, $key, $entity->tags, $ttl); // Save headers, too if (count($entity->headers)) { $headers = serialize($entity->headers); $this->backend_file->save($headers,'header-'.$key,$entity->tags,$ttl); } } /** * Recieve a cache entry from cache, containig all data of an action. * * @return Redspark_Cache_Entity_Action|null Entity object containing all data, needed. Null if not found. */ public function deliverAction(Redspark_Cache_Entity_Action $entity) { // Cache is somehow disabled if (!$this->isEnabled()) { return $entity; } // Backend disabled if ($this->getBackendEnableStatus('File')!=self::STATUS_ENABLED) { return $entity; } // Frontend disabled if ($this->getFrontendEnableStatus('Action')!=self::STATUS_ENABLED) { return $entity; } // Check if one of the tags is disabled if ($this->isTagDisabled($entity->tags)) { return $entity; } // Generate key $key = $entity->module.'-'.$entity->action.'-'.implode('-',$entity->params); $key = $this->escapeCacheKey($key); // Check if cache is available $backend = $this->getBackendFile(); // do not test. it only checks metadata and is thus unneccessary //if ($backend->test($key)) {} $data = $backend->load($key); // Entity is false (cache not found) if ($data===false) { return $entity; } // Deserialize assigns if (!$entity->with_view) { $entity->data = unserialize($data); } else { $entity->data = $data; } // Data is empty -> cache not found if (empty($data)) { return $entity; } $entity->found = TRUE; // Deliver headers, too $h = $backend->load('header-'.$key); if ($h!==false) { $entity->headers = unserialize($h); } return $entity; } /** * Discards all entries inside memcache and filesystem fallback. * * @param array $tags Optionally purge only the given tags. * * @return boolean True if purge suceeded. */ public function purgeAction($tags=array()) { // Backend is disabled hard if ($this->getBackendEnableStatus('File') < self::STATUS_DISABLED_TEMPORARILY) { return false; } // Frontend is disabled hard if ($this->getFrontendEnableStatus('Action') < self::STATUS_DISABLED_TEMPORARILY) { return false; } // Purge by tag $tags[] = 'Action'; return $this->getBackendFile()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags); } /** * Count entries, belonging to this frontend. This is internally done * via tags. * * @return Int */ public function countAction() { if (!$this->backend_file_enabled || !$this->frontend_action_enabled) { return FALSE; } $ids = $this->backend_file->getIdsMatchingTags(Array('Action')); return count($ids); } /****************/ /* Cache Status */ /****************/ /** * Disable a cache backend, frontend or the whole cache. * * You can disable the memcache backend for example with * $ype='backend_memcache' * * @param string $type Name of the cache to disable. * * @return boolean if disabling suceeded. */ public function disableCache($type='') { switch (strtolower($type)) { // Disable all caches case '': $this->url_disabled = true; break; // Disable proxy cache case 'proxy': if ($this->getBackendEnableStatus('proxy')==self::STATUS_ENABLED) { $this->backendProxyEnabled = self::STATUS_DISABLED_TEMPORARILY; } // Disable memcache case 'memcached': if ($this->getBackendEnableStatus('Memcached')==self::STATUS_ENABLED) { $this->backendMemcachedEnabled = self::STATUS_DISABLED_TEMPORARILY; } // Disable static case 'static': if ($this->getBackendEnableStatus('Static')==self::STATUS_ENABLED) { $this->backendStaticEnabled = self::STATUS_DISABLED_TEMPORARILY; } // Disable file backend case 'file': if ($this->getBackendEnableStatus('File')==self::STATUS_ENABLED) { $this->backendFileEnabled = self::STATUS_DISABLED_TEMPORARILY; } } return false; } /** * Check if the whole cache or a given frontend/backend is disabled. * * @deprecated use getBackendEnableStatus() and/or isEnabled() instead * * @param string $type Name of the cache to check. * * @return boolean True if disabled. */ public function isCacheDisabled($type='') { switch (strtolower($type)) { // Cache enabled globally? case '': return !$this->isEnabled(); case 'Proxy': case 'Static': case 'File': case 'Memcached': return $this->getBackendEnableStatus($type)==self::STATUS_ENABLED; default: return true; } } /****************/ /* Purge Cache **/ /****************/ /** * Purge all cache front- and backends. * * @return boolean True if succeeded. */ public function purgeAll() { // Disable cache $this->disableCache(); // Purge all backends $this->purgeProxy(); $this->purgeMemcache(); $this->purgeStatic(); $this->purgeFile(); return true; } /** * Purge the given cache frontend. * * @param string $frontend Name of the frontend. * * @return boolean True if succeeded. */ public function purgeFrontend($frontend) { return false; } /** * Purge the given cache backend. * * @param string $backend Name of the backend. * * @return boolean True if succeeded. */ public function purgeBackend($backend) { switch(strtolower($backend)) { // Proxy backend case 'proxy': return $this->purgeProxy(); // Memcached case 'memcached': return $this->purgeMemcache(); // File case 'file': return $this->purgeFile(); // Static case 'static': return $this->purgeStatic(); } // Purge failed return false; } /** * Purge entries, matching all of the given tags. * * @param array $tags * * @return boolean True if succeeded. */ public function purgeTags(array $tags) { // Purge tags from backends, supporting it // Convert to array, if string given (should raise warning because of typehinting, too) if (is_string($tags)) { $tags = Array($tags); } // Proxy backend if ($this->getBackendEnableStatus('Proxy') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendProxy()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags); } // File backend if ($this->getBackendEnableStatus('File') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendFile()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags); } // Static backend if ($this->getBackendEnableStatus('Static') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendStatic()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags); } // Memcache backend. Warning: memcache will be purge completely, because // of missing tag support. Can be disabled inside config if ($this->getBackendEnableStatus('Memcached') >= self::STATUS_DISABLED_TEMPORARILY) { $this->getBackendMemcached()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags); } return true; } /** * Cache konfiguration in den Handler übernehmen * * @param Zend_Config $config */ public function setConfig(Zend_Config $config) { return false; } /** * Load the cached array for the autoloader * @return Boolean */ public function loadAutoloaderLookupTable() { return false; } /** * Load the cached array for the autoloader * @return Boolean */ public function loadPathLookupTables() { return false; } /** * Check if the backend with the given name is enabled * * @param String $backend * * @return Int Enabled code described in header */ public function getBackendEnableStatus($backend) { // Load config for this backend $cfg = $this->_getConfig(Array('backend',strtolower($backend))); // Check the given cache backend switch(strtolower($backend)) { // Proxy backend case 'proxy': // Not initialized -> check config if ($this->backendProxyEnabled==self::STATUS_UNKNOWN) { // Config available if (!is_null($cfg->enabled)) { $this->backendProxyEnabled = $cfg->enabled ? self::STATUS_ENABLED : self::STATUS_DISABLED_CONFIG; } } return $this->backendProxyEnabled; // Memcached backend case 'memcached': // Not initialized -> check config if ($this->backendMemcachedEnabled==self::STATUS_UNKNOWN) { // Config available if (!is_null($cfg->enabled)) { $this->backendMemcachedEnabled = $cfg->enabled ? self::STATUS_ENABLED : self::STATUS_DISABLED_CONFIG; } } return $this->backendMemcachedEnabled; // File backend case 'file': // Not initialized -> check config if ($this->backendFileEnabled==self::STATUS_UNKNOWN) { // Config available if (!is_null($cfg->enabled)) { $this->backendFileEnabled = $cfg->enabled ? self::STATUS_ENABLED : self::STATUS_DISABLED_CONFIG; } } return $this->backendFileEnabled; // Static backend case 'static': // Not initialized -> check config if ($this->backendStaticEnabled==self::STATUS_UNKNOWN) { // Config available if (!is_null($cfg->enabled)) { $this->backendStaticEnabled = $cfg->enabled ? self::STATUS_ENABLED : self::STATUS_DISABLED_CONFIG; } } return $this->backendStaticEnabled; } // Cache backend not found Broker::getLog()->log(sprintf('Unknown Cache backend %s', $backend),Zend_Log::WARN); return self::STATUS_DISABLED_ERROR; } /** * Check if the backend with the given name is enabled * * @param String $frontend * * @return Int Enabled code described in header */ public function getFrontendEnableStatus($frontend) { // Load config for this backend $cfg = $this->_getConfig(Array('frontend',strtolower($frontend))); // Check the given cache frontend switch(strtolower($frontend)) { // Action frontend case 'action': // Not initialized -> check config if ($this->frontendActionEnabled==self::STATUS_UNKNOWN) { // Config available if (!is_null($cfg->enabled)) { $this->frontendActionEnabled = $cfg->enabled ? self::STATUS_ENABLED : self::STATUS_DISABLED_CONFIG; } } return $this->frontendActionEnabled; } // Cache frontend not found Broker::getLog()->log(sprintf('Unknown Cache frontend %s', $frontend),Zend_Log::WARN); return self::STATUS_DISABLED_ERROR; } /** * Check if cache is enabled. * * @return Boolean */ public function isEnabled() { // Check request param if (is_null($this->url_disabled)) { $rq = Broker::getRequest(); if ($rq instanceof Zend_Controller_Request_Abstract) { $uri = $rq->getRequestUri(); } else { $uri = $_SERVER['REQUEST_URI']; } if (strpos(strtolower($uri),'cache=0')!==FALSE) { $this->url_disabled = true; } else { $this->url_disabled = false; } } // Check config if (is_null($this->config_disabled)) { $cfg = $this->_getConfig(); $enabled = $cfg->enabled; if (!is_null($enabled)) { $this->config_disabled = !$enabled; } } return !$this->url_disabled && !$this->config_disabled; } /** * Checks a given list of tags if one of them is disabled * * @param Array[String] $tags * * @return Boolean */ public function isTagDisabled($tags) { // Load blacklist $disabled_tags = $this->getDisabledTags(); // Check each tag against the blacklist foreach($tags as $tag) { if (in_array(strtolower($tag),$disabled_tags)) { return true; } } return false; } /** * Get a list of tags, disabled for caching via config. * * @return Array */ public function getDisabledTags() { // Disabled tags not initialized -> load from config if (is_null($this->disabled_tags)) { $cfg = $this->_getConfig(); $tags = $cfg->disabled_tags; if (is_string($tags)) { $this->disabled_tags = Array(); // Explode tags and trim each one foreach(explode(',',$tags) AS $tag) { $tag = trim($tag); if (!empty($tag)) { $this->disabled_tags[] = $tag; } } } } // Return empty array, if not initialized return is_array($this->disabled_tags) ? $this->disabled_tags : Array(); } /** * Get an instance of the specified backend * * @param String $backend * * @return Zend_Cache_Backend */ protected function _getBackend($backend) { // Cache disabled and uninstanciatable! if ($this->getBackendEnableStatus($backend) <= self::STATUS_DISABLED_ERROR) { throw new Exception(sprintf('Cache Backend %s is disabled.',$backend)); } // Instanciate cache by name switch(strtolower($backend)) { // Proxy backend case 'proxy': return $this->getBackendProxy(); // Memcached backend case 'memcached': return $this->getBackendMemcached(); // File backend case 'file': return $this->getBackendFile(); // Static backend case 'static': return $this->getBackendStatic(); } throw new Exception(sprintf('Error getting cache backend %s.',$backend)); } /** * Load the cache config and/or subsections of it * * @param Array $subsections * * @return Zend_Config */ protected function _getConfig($subsections=Array()) { // Load global config $cfg = Broker::getConfig()->getSection('Cache'); // Load subconfigs foreach($subsections AS $subsect) { $cfg = $cfg->$subsect; // Subconfig didnt exists. Return empty config if (!$cfg instanceof Zend_Config) { return Factory::getNewInstance('Config', Array(Array())); } } // Return config return $cfg; } /** * Extends the Cache key with the current app and version, * and strips unallowed signs ( / for example is a bad idea for filesystem cache) * * @param unknown_type $key */ public function escapeCacheKey($key) { // get account id $aid = (isset($_SESSION) && array_key_exists('', $_SESSION)) ? $_SESSION["session_AccountID"] : 0; /* Schlüssel aufbereiten */ $key = (defined('MAIN_APPLICATION') ? MAIN_APPLICATION : 'APP').'-'.(defined('MAIN_APPLICATION_VERSION') ? MAIN_APPLICATION_VERSION : '0.0.0').'-'.$aid.'-'.$key; $key = preg_replace('/([^A-Za-z0-9\-])/','',$key); if (strlen($key)>100) { $key = 'md5-'.md5($key); } return $key; } /** * setMaxTTL decreases the max ttl for page/static cache. This must be some * kind of superglobal, to enable page assets to limit the ttl. * TTL can only be decreased, no increased anymore! * * @param Int Sekunden */ public function setMaxTTL($sec) { // ignore non-numeric values if (!is_numeric($sec)) { return false; } // No limitation set by now if ($this->_max_ttl===false) { $this->_max_ttl = $sec; // Take the lower value of both } else { $this->_max_ttl = min($this->_max_ttl,$sec); } Broker::getLog()->log(sprintf('Cache TTL reduced to %s sec.', $this->_max_ttl),Zend_Log::DEBUG); } }