|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2009-2011 Ingo Renner <ingo@typo3.org> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * 00017 * This script is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 * GNU General Public License for more details. 00021 * 00022 * This copyright notice MUST APPEAR in all copies of the script! 00023 ***************************************************************/ 00024 00025 00026 /** 00027 * A caching backend which stores cache entries by using APC. 00028 * 00029 * This backend uses the following types of keys: 00030 * - tag_xxx 00031 * xxx is tag name, value is array of associated identifiers identifier. This 00032 * is "forward" tag index. It is mainly used for obtaining content by tag 00033 * (get identifier by tag -> get content by identifier) 00034 * - ident_xxx 00035 * xxx is identifier, value is array of associated tags. This is "reverse" tag 00036 * index. It provides quick access for all tags associated with this identifier 00037 * and used when removing the identifier 00038 * 00039 * Each key is prepended with a prefix. By default prefix consists from two parts 00040 * separated by underscore character and ends in yet another underscore character: 00041 * - "TYPO3" 00042 * - MD5 of path to TYPO3 and user running TYPO3 00043 * This prefix makes sure that keys from the different installations do not 00044 * conflict. 00045 * 00046 * This file is a backport from FLOW3 00047 * 00048 * @package TYPO3 00049 * @subpackage t3lib_cache 00050 * @api 00051 * @version $Id: class.t3lib_cache_backend_apcbackend.php 10121 2011-01-18 20:15:30Z ohader $ 00052 */ 00053 class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend { 00054 00055 /** 00056 * A prefix to seperate stored data from other data possible stored in the APC 00057 * 00058 * @var string 00059 */ 00060 protected $identifierPrefix; 00061 00062 /** 00063 * Constructs this backend 00064 * 00065 * @param array $options Configuration options - unused here 00066 * @author Robert Lemke <robert@typo3.org> 00067 * @author Karsten Dambekalns <karsten@typo3.org> 00068 */ 00069 public function __construct(array $options = array()) { 00070 if (!extension_loaded('apc')) { 00071 throw new t3lib_cache_Exception( 00072 'The PHP extension "apc" must be installed and loaded in order to use the APC backend.', 00073 1232985414 00074 ); 00075 } 00076 00077 parent::__construct($options); 00078 } 00079 00080 /** 00081 * Initializes the identifier prefix when setting the cache. 00082 * 00083 * @param t3lib_cache_frontend_Frontend $cache The frontend for this backend 00084 * @return void 00085 * @author Robert Lemke <robert@typo3.org> 00086 */ 00087 public function setCache(t3lib_cache_frontend_Frontend $cache) { 00088 parent::setCache($cache); 00089 $processUser = extension_loaded('posix') ? posix_getpwuid(posix_geteuid()) : array('name' => 'default'); 00090 $pathHash = t3lib_div::shortMD5(PATH_site . $processUser['name'], 12); 00091 $this->identifierPrefix = 'TYPO3_' . $pathHash; 00092 } 00093 00094 /** 00095 * Saves data in the cache. 00096 * 00097 * @param string $entryIdentifier An identifier for this specific cache entry 00098 * @param string $data The data to be stored 00099 * @param array $tags Tags to associate with this cache entry 00100 * @param integer $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime. 00101 * @return void 00102 * @throws t3lib_cache_Exception if no cache frontend has been set. 00103 * @throws InvalidArgumentException if the identifier is not valid 00104 * @throws t3lib_cache_exception_InvalidData if $data is not a string 00105 * @author Christian Jul Jensen <julle@typo3.org> 00106 * @author Karsten Dambekalns <karsten@typo3.org> 00107 */ 00108 public function set($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) { 00109 if (!$this->cache instanceof t3lib_cache_frontend_Frontend) { 00110 throw new t3lib_cache_Exception( 00111 'No cache frontend has been set yet via setCache().', 00112 1232986818 00113 ); 00114 } 00115 00116 if (!is_string($data)) { 00117 throw new t3lib_cache_exception_InvalidData( 00118 'The specified data is of type "' . gettype($data) . '" but a string is expected.', 00119 1232986825 00120 ); 00121 } 00122 00123 $tags[] = '%APCBE%' . $this->cacheIdentifier; 00124 $expiration = $lifetime !== NULL ? $lifetime : $this->defaultLifetime; 00125 00126 $success = apc_store($this->identifierPrefix . $entryIdentifier, $data, $expiration); 00127 if ($success === TRUE) { 00128 $this->removeIdentifierFromAllTags($entryIdentifier); 00129 $this->addIdentifierToTags($entryIdentifier, $tags); 00130 } else { 00131 throw new t3lib_cache_Exception( 00132 'Could not set value.', 00133 1232986877 00134 ); 00135 } 00136 } 00137 00138 /** 00139 * Loads data from the cache. 00140 * 00141 * @param string $entryIdentifier An identifier which describes the cache entry to load 00142 * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded 00143 * @author Karsten Dambekalns <karsten@typo3.org> 00144 */ 00145 public function get($entryIdentifier) { 00146 $success = FALSE; 00147 $value = apc_fetch($this->identifierPrefix . $entryIdentifier, $success); 00148 00149 return ($success ? $value : $success); 00150 } 00151 00152 /** 00153 * Checks if a cache entry with the specified identifier exists. 00154 * 00155 * @param string $entryIdentifier An identifier specifying the cache entry 00156 * @return boolean TRUE if such an entry exists, FALSE if not 00157 * @author Karsten Dambekalns <karsten@typo3.org> 00158 */ 00159 public function has($entryIdentifier) { 00160 $success = FALSE; 00161 apc_fetch($this->identifierPrefix . $entryIdentifier, $success); 00162 return $success; 00163 } 00164 00165 /** 00166 * Removes all cache entries matching the specified identifier. 00167 * Usually this only affects one entry but if - for what reason ever - 00168 * old entries for the identifier still exist, they are removed as well. 00169 * 00170 * @param string $entryIdentifier Specifies the cache entry to remove 00171 * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found 00172 * @author Christian Jul Jensen <julle@typo3.org> 00173 * @author Karsten Dambekalns <karsten@typo3.org> 00174 */ 00175 public function remove($entryIdentifier) { 00176 $this->removeIdentifierFromAllTags($entryIdentifier); 00177 00178 return apc_delete($this->identifierPrefix . $entryIdentifier); 00179 } 00180 00181 /** 00182 * Finds and returns all cache entry identifiers which are tagged by the 00183 * specified tag. 00184 * 00185 * @param string $tag The tag to search for 00186 * @return array An array with identifiers of all matching entries. An empty array if no entries matched 00187 * @author Karsten Dambekalns <karsten@typo3.org> 00188 */ 00189 public function findIdentifiersByTag($tag) { 00190 $success = FALSE; 00191 $identifiers = apc_fetch($this->identifierPrefix . 'tag_' . $tag, $success); 00192 00193 if ($success === FALSE) { 00194 return array(); 00195 } else { 00196 return (array) $identifiers; 00197 } 00198 } 00199 00200 /** 00201 * Finds and returns all cache entry identifiers which are tagged by the 00202 * specified tags. 00203 * 00204 * @param array Array of tags to search for 00205 * @return array An array with identifiers of all matching entries. An empty array if no entries matched 00206 * @author Ingo Renner <ingo@typo3.org> 00207 */ 00208 public function findIdentifiersByTags(array $tags) { 00209 $taggedEntries = array(); 00210 $foundEntries = array(); 00211 00212 foreach ($tags as $tag) { 00213 $taggedEntries[$tag] = $this->findIdentifiersByTag($tag); 00214 } 00215 00216 $intersectedTaggedEntries = call_user_func_array('array_intersect', $taggedEntries); 00217 00218 foreach ($intersectedTaggedEntries as $entryIdentifier) { 00219 if ($this->has($entryIdentifier)) { 00220 $foundEntries[$entryIdentifier] = $entryIdentifier; 00221 } 00222 } 00223 00224 return $foundEntries; 00225 } 00226 00227 /** 00228 * Finds all tags for the given identifier. This function uses reverse tag 00229 * index to search for tags. 00230 * 00231 * @param string $identifier Identifier to find tags by 00232 * @return array Array with tags 00233 * @author Karsten Dambekalns <karsten@typo3.org> 00234 */ 00235 protected function findTagsByIdentifier($identifier) { 00236 $success = FALSE; 00237 $tags = apc_fetch($this->identifierPrefix . 'ident_' . $identifier, $success); 00238 00239 return ($success ? (array) $tags : array()); 00240 } 00241 00242 /** 00243 * Removes all cache entries of this cache. 00244 * 00245 * @return void 00246 * @author Karsten Dambekalns <karsten@typo3.org> 00247 */ 00248 public function flush() { 00249 if (!$this->cache instanceof t3lib_cache_frontend_Frontend) { 00250 throw new t3lib_cache_Exception( 00251 'Yet no cache frontend has been set via setCache().', 00252 1232986971 00253 ); 00254 } 00255 00256 $this->flushByTag('%APCBE%' . $this->cacheIdentifier); 00257 } 00258 00259 /** 00260 * Removes all cache entries of this cache which are tagged by the specified 00261 * tag. 00262 * 00263 * @param string $tag The tag the entries must have 00264 * @return void 00265 * @author Karsten Dambekalns <karsten@typo3.org> 00266 */ 00267 public function flushByTag($tag) { 00268 $identifiers = $this->findIdentifiersByTag($tag); 00269 00270 foreach ($identifiers as $identifier) { 00271 $this->remove($identifier); 00272 } 00273 } 00274 00275 /** 00276 * Removes all cache entries of this cache which are tagged by the specified tag. 00277 * 00278 * @param array The tags the entries must have 00279 * @return void 00280 * @author Ingo Renner <ingo@typo3.org> 00281 */ 00282 public function flushByTags(array $tags) { 00283 foreach ($tags as $tag) { 00284 $this->flushByTag($tag); 00285 } 00286 } 00287 00288 /** 00289 * Associates the identifier with the given tags 00290 * 00291 * @param string $entryIdentifier 00292 * @param array $tags 00293 * @author Karsten Dambekalns <karsten@typo3.org> 00294 * @author Dmitry Dulepov <dmitry.@typo3.org> 00295 */ 00296 protected function addIdentifierToTags($entryIdentifier, array $tags) { 00297 foreach ($tags as $tag) { 00298 // Update tag-to-identifier index 00299 $identifiers = $this->findIdentifiersByTag($tag); 00300 if (array_search($entryIdentifier, $identifiers) === FALSE) { 00301 $identifiers[] = $entryIdentifier; 00302 apc_store($this->identifierPrefix . 'tag_' . $tag, $identifiers); 00303 } 00304 00305 // Update identifier-to-tag index 00306 $existingTags = $this->findTagsByIdentifier($entryIdentifier); 00307 if (array_search($entryIdentifier, $existingTags) === false) { 00308 apc_store($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags)); 00309 } 00310 00311 } 00312 } 00313 00314 /** 00315 * Removes association of the identifier with the given tags 00316 * 00317 * @param string $entryIdentifier 00318 * @param array $tags 00319 * @author Karsten Dambekalns <karsten@typo3.org> 00320 * @author Dmitry Dulepov <dmitry.@typo3.org> 00321 */ 00322 protected function removeIdentifierFromAllTags($entryIdentifier) { 00323 // Get tags for this identifier 00324 $tags = $this->findTagsByIdentifier($entryIdentifier); 00325 // Deassociate tags with this identifier 00326 foreach ($tags as $tag) { 00327 $identifiers = $this->findIdentifiersByTag($tag); 00328 // Formally array_search() below should never return false due to 00329 // the behavior of findTagsByIdentifier(). But if reverse index is 00330 // corrupted, we still can get 'false' from array_search(). This is 00331 // not a problem because we are removing this identifier from 00332 // anywhere. 00333 if (($key = array_search($entryIdentifier, $identifiers)) !== FALSE) { 00334 unset($identifiers[$key]); 00335 if (count($identifiers)) { 00336 apc_store($this->identifierPrefix . 'tag_' . $tag, $identifiers); 00337 } else { 00338 apc_delete($this->identifierPrefix . 'tag_' . $tag); 00339 } 00340 } 00341 } 00342 // Clear reverse tag index for this identifier 00343 apc_delete($this->identifierPrefix . 'ident_' . $entryIdentifier); 00344 } 00345 00346 /** 00347 * Does nothing, as APC does GC itself 00348 * 00349 * @return void 00350 */ 00351 public function collectGarbage() { 00352 00353 } 00354 } 00355 00356 00357 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_apcbackend.php'])) { 00358 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_apcbackend.php']); 00359 } 00360 00361 ?>
1.8.0