Added feature 9097: Introduce a new caching framework (backported from FLOW3)
authorIngo Renner <ingo.renner@typo3.org>
Mon, 15 Sep 2008 15:36:16 +0000 (15:36 +0000)
committerIngo Renner <ingo.renner@typo3.org>
Mon, 15 Sep 2008 15:36:16 +0000 (15:36 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@4128 709f56b5-9817-0410-a4d7-c38de5d9e867

20 files changed:
ChangeLog
t3lib/cache/backend/class.t3lib_cache_backend_db.php [new file with mode: 0644]
t3lib/cache/backend/class.t3lib_cache_backend_file.php [new file with mode: 0644]
t3lib/cache/backend/class.t3lib_cache_backend_globals.php [new file with mode: 0644]
t3lib/cache/backend/class.t3lib_cache_backend_memcached.php [new file with mode: 0644]
t3lib/cache/backend/class.t3lib_cache_backend_null.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_abstractbackend.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_abstractcache.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_exception.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_factory.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_manager.php [new file with mode: 0644]
t3lib/cache/class.t3lib_cache_variablecache.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_classalreadyloaded.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_duplicateidentifier.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_invalidbackend.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_invalidcache.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_invaliddata.php [new file with mode: 0644]
t3lib/cache/exception/class.t3lib_cache_exception_nosuchcache.php [new file with mode: 0644]
t3lib/config_default.php
typo3/sysext/cms/tslib/index_ts.php

index 5d5b065..15264f7 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-09-15  Ingo Renner  <ingo@typo3.org>
+
+       * Added feature 9097: Introduce a new caching framework (backported from FLOW3)
+
 2008-09-14  Benjamin Mack  <benni@typo3.org>
 
        * Fixed bug #7595: Docheaders: Module Admin tools > Indexing: No docheader (Thanks to Christian Kuhn, initial patch by Patrick Broens)
diff --git a/t3lib/cache/backend/class.t3lib_cache_backend_db.php b/t3lib/cache/backend/class.t3lib_cache_backend_db.php
new file mode 100644 (file)
index 0000000..9d0a5f6
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A caching backend which stores cache entries in files
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_backend_Db extends t3lib_cache_AbstractBackend {
+
+       protected $cacheTable;
+
+       /**
+        * Saves data in a cache file.
+        *
+        * @param string An identifier for this specific cache entry
+        * @param string The data to be stored
+        * @param array Tags to associate with this cache entry
+        * @param integer Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
+        * @return void
+        * @throws t3lib_cache_Exception if the directory does not exist or is not writable, or if no cache frontend has been set.
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
+               if (is_null($lifetime)) {
+                       $lifetime = $this->defaultLifetime;
+               }
+
+               $this->remove($entryIdentifier);
+
+               $GLOBALS['TYPO3_DB']->exec_INSERTquery(
+                       $this->cacheTable,
+                       array(
+                               'identifier' => $entryIdentifier,
+                               'crdate'     => time(),
+                               'data'       => $data,
+                               'tags'       => implode(',', $tags),
+                               'lifetime'   => $lifetime
+                       )
+               );
+       }
+
+       /**
+        * Loads data from a cache file.
+        *
+        * @param string An identifier which describes the cache entry to load
+        * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function load($entryIdentifier) {
+               $cacheEntry = false;
+
+               $caheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       'data',
+                       $this->cacheTable,
+                       'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' '
+                               . 'AND (crdate + lifetime) >= ' . time()
+               );
+
+               if (count($caheEntries) == 1) {
+                       $cacheEntry = $caheEntries[0]['data'];
+               }
+
+               return $cacheEntry;
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param unknown_type
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               $hasEntry = false;
+
+               $caheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       'data',
+                       $this->cacheTable,
+                       'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' '
+                               . 'AND (crdate + lifetime) >= ' . time()
+               );
+
+               if (count($caheEntries) == 1) {
+                       $hasEntry = true;
+               }
+
+               return $hasEntry;
+       }
+
+       /**
+        * Removes all cache entries matching the specified identifier.
+        * Usually this only affects one entry.
+        *
+        * @param string Specifies the cache entry to remove
+        * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               $entryRemoved = false;
+
+               $res = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
+                       $this->cacheTable,
+                       'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable)
+               );
+
+               if($GLOBALS['TYPO3_DB']->sql_affected_rows($res) == 1) {
+                       $entryRemoved = true;
+               }
+
+               return $entryRemoved;
+       }
+
+       /**
+        * Finds and returns all cache entries which are tagged by the specified tag.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tag.
+        *
+        * @param string The tag to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTag($tag) {
+               $cacheEntries = array();
+
+               $cacheEntryRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       'identifier',
+                       $this->cacheTable,
+                       $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable)
+               );
+
+               foreach ($cacheEntryRows as $cacheEntryRow) {
+                       $cacheEntries[$cacheEntryRow['identifier']] = $cacheEntryRow['identifier'];
+               }
+
+               return $cacheEntries;
+       }
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * a tag.
+        *
+        * @param array Array of tags to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTags(array $tags) {
+               $cacheEntries = array();
+               $whereClause  = array();
+
+               foreach ($tags as $tag) {
+                       $whereClause[] = $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable);
+               }
+
+               $cacheEntryRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       'identifier',
+                       $this->cacheTable,
+                       implode(' AND ', $whereClause)
+               );
+
+               foreach ($cacheEntryRows as $cacheEntryRow) {
+                       $cacheEntries[$cacheEntryRow['identifier']] = $cacheEntryRow['identifier'];
+               }
+
+               return $cacheEntries;
+       }
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * @return void
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function flush() {
+               $GLOBALS['TYPO3_DB']->sql_query('TRUNCATE ' . $this->cacheTable);
+       }
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string The tag the entries must have
+        * @return void
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function flushByTag($tag) {
+               foreach ($this->findEntriesByTag($tag) as $entryIdentifier) {
+                       $this->remove($entryIdentifier);
+               }
+       }
+
+       protected function setCacheTable($cacheTable) {
+               $this->cacheTable = $cacheTable;
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_db.php'])   {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_db.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/backend/class.t3lib_cache_backend_file.php b/t3lib/cache/backend/class.t3lib_cache_backend_file.php
new file mode 100644 (file)
index 0000000..edd6317
--- /dev/null
@@ -0,0 +1,496 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A caching backend which stores cache entries in files
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_backend_File extends t3lib_cache_AbstractBackend {
+
+       /**
+        * @var string Directory where the files are stored
+        */
+       protected $cacheDirectory = '';
+
+       /**
+        * Constructs this backend
+        *
+        * @param mixed Configuration options - depends on the actual backend
+        */
+       public function __construct(array $options = array()) {
+               parent::__construct($options);
+
+               if (empty($this->cacheDirectory)) {
+                       $cacheDirectory = 'typo3temp/cache/';
+                       try {
+                               $this->setCacheDirectory($cacheDirectory);
+                       } catch(t3lib_cache_Exception $exception) {
+
+                       }
+               }
+       }
+
+       /**
+        * Sets the directory where the cache files are stored.
+        *
+        * @param string The directory
+        * @return void
+        * @throws t3lib_cache_Exception if the directory does not exist, is not writable or could not be created.
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function setCacheDirectory($cacheDirectory) {
+
+               if ($cacheDirectory{strlen($cacheDirectory) - 1} !== '/') {
+                       $cacheDirectory .= '/';
+               }
+
+               if (!is_writable($cacheDirectory)) {
+                       t3lib_div::mkdir_deep(
+                               t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/',
+                               $cacheDirectory
+                       );
+               }
+
+               if (!is_dir($cacheDirectory)) {
+                       throw new t3lib_cache_Exception(
+                               'The directory "' . $cacheDirectory . '" does not exist.',
+                               1203965199
+                       );
+               }
+
+               if (!is_writable($cacheDirectory)) {
+                       throw new t3lib_cache_Exception(
+                               'The directory "' . $cacheDirectory . '" is not writable.',
+                               1203965200
+                       );
+               }
+
+               $tagsDirectory = $cacheDirectory . 'tags/';
+
+               if (!is_writable($tagsDirectory)) {
+                       t3lib_div::mkdir_deep(
+                               t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/',
+                               $tagsDirectory
+                       );
+               }
+
+               $this->cacheDirectory = $cacheDirectory;
+       }
+
+       /**
+        * Returns the directory where the cache files are stored
+        *
+        * @return string Full path of the cache directory
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getCacheDirectory() {
+               return $this->cacheDirectory;
+       }
+
+       /**
+        * Saves data in a cache file.
+        *
+        * @param string An identifier for this specific cache entry
+        * @param string The data to be stored
+        * @param array Tags to associate with this cache entry
+        * @param integer Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
+        * @return void
+        * @throws t3lib_cache_Exception if the directory does not exist or is not writable, or if no cache frontend has been set.
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
+               if (!self::isValidEntryIdentifier($entryIdentifier)) {
+                       throw new InvalidArgumentException(
+                               '"' . $entryIdentifier . '" is not a valid cache entry identifier.',
+                               1207139693
+                       );
+               }
+
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'No cache frontend has been set yet via setCache().',
+                               1204111375
+                       );
+               }
+
+               if (!is_string($data)) {
+                       throw new t3lib_cache_Exception_InvalidData(
+                               'The specified data is of type "' . gettype($data) . '" but a string is expected.',
+                               1204481674
+                       );
+               }
+
+               foreach ($tags as $tag) {
+                       if (!self::isValidTag($tag)) {
+                               throw new InvalidArgumentException(
+                                       '"' . $tag . '" is not a valid tag for a cache entry.',
+                                       1213105438
+                               );
+                       }
+               }
+
+               if (is_null($lifetime)) {
+                       $lifetime = $this->defaultLifetime;
+               }
+
+               $expiryTime          = new DateTime(
+                       'now +' . $lifetime . ' seconds',
+                       new DateTimeZone('UTC')
+               );
+               $entryIdentifierHash = sha1($entryIdentifier);
+               $cacheEntryPath      = $this->cacheDirectory
+                       . 'data/' . $this->cache->getIdentifier()
+                       . '/' . $entryIdentifierHash{0} . '/' . $entryIdentifierHash {1} . '/';
+               $filename            = $this->renderCacheFilename($entryIdentifier, $expiryTime);
+
+               if (!is_writable($cacheEntryPath)) {
+                       try {
+                               t3lib_div::mkdir_deep(
+                                       t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/',
+                                       $cacheEntryPath
+                               );
+                       } catch(Exception $exception) {
+
+                       }
+                       if (!is_writable($cacheEntryPath)) {
+                               throw new t3lib_cache_Exception(
+                                       'The cache directory "' . $cacheEntryPath . '" could not be created.',
+                                       1204026250
+                               );
+                       }
+               }
+
+               $this->remove($entryIdentifier);
+
+               $temporaryFilename = $filename . '.' . uniqid() . '.temp';
+               $result = file_put_contents($cacheEntryPath . $temporaryFilename, $data);
+               if ($result === FALSE) {
+                       throw new t3lib_cache_Exception(
+                               'The temporary cache file "' . $temporaryFilename . '" could not be written.',
+                               1204026251
+                       );
+               }
+
+               for ($i = 0; $i < 5; $i++) {
+                       $result = rename(
+                               $cacheEntryPath . $temporaryFilename,
+                               $cacheEntryPath . $filename
+                       );
+
+                       if ($result === TRUE) {
+                               break;
+                       }
+               }
+
+               foreach ($tags as $tag) {
+                       $tagPath = $this->cacheDirectory . 'tags/' . $tag . '/';
+
+                       if (!is_writable($tagPath)) {
+                               mkdir($tagPath);
+                       }
+
+                       touch($tagPath . $this->cache->getIdentifier() . '_' . $entryIdentifier);
+               }
+       }
+
+       /**
+        * Loads data from a cache file.
+        *
+        * @param string An identifier which describes the cache entry to load
+        * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function load($entryIdentifier) {
+               $pathsAndFilenames = $this->findCacheFilesByEntry($entryIdentifier);
+               $cacheEntry        = FALSE;
+
+               if ($pathsAndFilenames !== FALSE) {
+                       $cacheEntry = file_get_contents(array_pop($pathsAndFilenames));
+               }
+
+               return $cacheEntry;
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param unknown_type
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               return $this->findCacheFilesByEntry($entryIdentifier) !== FALSE;
+       }
+
+       /**
+        * Removes all cache entries matching the specified identifier.
+        * Usually this only affects one entry.
+        *
+        * @param string Specifies the cache entry to remove
+        * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               $pathsAndFilenames = $this->findCacheFilesByEntry($entryIdentifier);
+
+               if ($pathsAndFilenames === FALSE) {
+                       return FALSE;
+               }
+
+               foreach ($pathsAndFilenames as $pathAndFilename) {
+                       $result = unlink($pathAndFilename);
+                       if ($result === FALSE) {
+                               return FALSE;
+                       }
+               }
+
+               $pathsAndFilenames = $this->findTagFilesByEntry($entryIdentifier);
+               if ($pathsAndFilenames === FALSE) {
+                       return FALSE;
+               }
+
+               foreach ($pathsAndFilenames as $pathAndFilename) {
+                       $result = unlink($pathAndFilename);
+                       if ($result === FALSE) {
+                               return FALSE;
+                       }
+               }
+
+               return TRUE;
+       }
+
+       /**
+        * Finds and returns all cache entries which are tagged by the specified tag.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tag.
+        *
+        * @param string The tag to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function findEntriesByTag($tag) {
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'Yet no cache frontend has been set via setCache().',
+                               1204111376
+                       );
+               }
+
+               $path       = $this->cacheDirectory . 'tags/';
+               $pattern    = $path . $tag . '/*';
+               $filesFound = glob($pattern);
+
+               if ($filesFound === FALSE || count($filesFound) == 0) {
+                       return array();
+               }
+
+               $cacheEntries = array();
+               foreach ($filesFound as $filename) {
+                       list(,$entryIdentifier) = explode('_', basename($filename));
+                       $cacheEntries[$entryIdentifier] = $entryIdentifier;
+               }
+
+               return array_values($cacheEntries);
+       }
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * a tag.
+        *
+        * @param array Array of tags to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTags(array $tags) {
+               $taggedEntries = array();
+               $foundEntries  = array();
+
+               foreach ($tags as $tag) {
+                       $taggedEntries[$tag] = $this->findEntriesByTag($tag);
+               }
+
+               $intersectedTaggedEntries = call_user_func_array('array_intersect', $taggedEntries);
+
+               foreach ($intersectedTaggedEntries as $entryIdentifier) {
+                       $foundEntries[$entryIdentifier] = $entryIdentifier;
+               }
+
+               return $foundEntries;
+       }
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flush() {
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'Yet no cache frontend has been set via setCache().',
+                               1204111376
+                       );
+               }
+
+               $path       = $this->cacheDirectory . 'data/' . $this->cache->getIdentifier() . '/';
+               $pattern    = $path . '*/*/*';
+               $filesFound = glob($pattern);
+
+               if ($filesFound === FALSE || count($filesFound) == 0) {
+                       return;
+               }
+
+               foreach($filesFound as $filename) {
+                       list(,$entryIdentifier) = explode('_', basename($filename));
+                       $this->remove($entryIdentifier);
+               }
+       }
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string The tag the entries must have
+        * @return void
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function flushByTag($tag) {
+               $path       = $this->cacheDirectory . 'tags/' . $tag . '/';
+               $pattern    = $path . '*';
+               $filesFound = glob($pattern);
+
+               foreach ($filesFound as $file) {
+                       unlink($file);
+               }
+               rmdir($path);
+       }
+
+       /**
+        * Renders a file name for the specified cache entry
+        *
+        * @param string Identifier for the cache entry
+        * @param DateTime Date and time specifying the expiration of the entry. Must be a UTC time.
+        * @return string Filename of the cache data file
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function renderCacheFilename($identifier, DateTime $expiryTime) {
+               $filename = $expiryTime->format('Y-m-d\TH\;i\;sO') . '_' . $identifier;
+
+               return $filename;
+       }
+
+       /**
+        * Tries to find the cache entry for the specified identifier.
+        * Usually only one cache entry should be found - if more than one exist, this
+        * is due to some error or crash.
+        *
+        * @param string The cache entry identifier
+        * @return mixed The file names (including path) as an array if one or more entries could be found, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        * @throws t3lib_cache_Exception if no frontend has been set
+        */
+       protected function findCacheFilesByEntry($entryIdentifier) {
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'Yet no cache frontend has been set via setCache().',
+                               1204111376
+                       );
+               }
+
+               $path            = $this->cacheDirectory . 'data/' . $this->cache->getIdentifier() . '/';
+               $pattern         = $path . '*/*/????-??-?????;??;???????_' . $entryIdentifier;
+               $filesFound      = glob($pattern);
+               $validFilesFound = array();
+
+               if ($filesFound === FALSE || count($filesFound) == 0) {
+                       return FALSE;
+               }
+
+               foreach ($filesFound as $pathAndFilename) {
+                       $expiryTimeAndIdentifier = explode('/', $pathAndFilename);
+                       $expiryTime = substr(array_pop($expiryTimeAndIdentifier), 0, -(strlen($entryIdentifier) + 1));
+
+                       $expiryTimeParsed = strtotime(str_replace(';', ':', $expiryTime));
+
+                       $now = new DateTime(
+                               'now',
+                               new DateTimeZone('UTC')
+                       );
+                       $now = (int) $now->format('U');
+
+                       if ($expiryTimeParsed > $now) {
+                               $validFilesFound[] = $pathAndFilename;
+                       } else {
+                               unlink($pathAndFilename);
+                       }
+               }
+
+               if (count($validFilesFound) == 0) {
+                       return FALSE;
+               }
+
+               return $validFilesFound;
+       }
+
+
+       /**
+        * Tries to find the tag entries for the specified cache entry.
+        *
+        * @param string The cache entry identifier to find tag files for
+        * @return mixed The file names (including path) as an array if one or more entries could be found, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        * @throws t3lib_cache_Exception if no frontend has been set
+        */
+       protected function findTagFilesByEntry($entryIdentifier) {
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'Yet no cache frontend has been set via setCache().',
+                               1204111376
+                       );
+               }
+
+               $path       = $this->cacheDirectory . 'tags/';
+               $pattern    = $path . '*/' . $this->cache->getIdentifier() . '_' . $entryIdentifier;
+               $filesFound = glob($pattern);
+
+               if ($filesFound === FALSE || count($filesFound) == 0) {
+                       return FALSE;
+               }
+
+               return $filesFound;
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_file.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_file.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/backend/class.t3lib_cache_backend_globals.php b/t3lib/cache/backend/class.t3lib_cache_backend_globals.php
new file mode 100644 (file)
index 0000000..b0f7407
--- /dev/null
@@ -0,0 +1,235 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A caching backend which saves it's data in $GLOBALS - a very short living cache, probably useful only during page rendering
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_backend_Globals extends t3lib_cache_AbstractBackend {
+
+       /**
+        * Constructs this backend
+        *
+        * @param mixed Configuration options - depends on the actual backend
+        */
+       public function __construct(array $options = array()) {
+               parent::__construct($options);
+
+               if (!isset($GLOBALS['typo3CacheStorage'])) {
+                       $GLOBALS['typo3CacheStorage'] = array();
+               }
+
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'No cache frontend has been set yet via setCache().',
+                               1217611408
+                       );
+               }
+
+               $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()] = array(
+                       'data' => array(),
+                       'tags' => array()
+               );
+       }
+
+       /**
+        * Saves data in a cache file.
+        *
+        * @param string An identifier for this specific cache entry
+        * @param string The data to be stored
+        * @param array Tags to associate with this cache entry
+        * @param integer Ignored as $GLOBALS lasts for the time of the script execution only anyway
+        * @return void
+        * @throws t3lib_cache_Exception if the directory does not exist or is not writable, or if no cache frontend has been set.
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
+               if (!self::isValidEntryIdentifier($entryIdentifier)) {
+                       throw new InvalidArgumentException(
+                               '"' . $entryIdentifier . '" is not a valid cache entry identifier.',
+                               1217611184
+                       );
+               }
+
+               if (!is_object($this->cache)) {
+                       throw new t3lib_cache_Exception(
+                               'No cache frontend has been set yet via setCache().',
+                               1217611191
+                       );
+               }
+
+               if (!is_string($data)) {
+                       throw new t3lib_cache_Exception_InvalidData(
+                               'The specified data is of type "' . gettype($data) . '" but a string is expected.',
+                               1217611199
+                       );
+               }
+
+               foreach ($tags as $tag) {
+                       if (!self::isValidTag($tag)) {
+                               throw new InvalidArgumentException(
+                                       '"' . $tag . '" is not a valid tag for a cache entry.',
+                                       1217611205
+                               );
+                       }
+               }
+
+                       // saving data
+               $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'][$entryIdentifier] = $data;
+
+                       // tagging
+               foreach ($tags as $tag) {
+                       if (!isset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag])) {
+                               $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag] = array();
+                       }
+
+                       $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag][] = $entryIdentifier;
+               }
+
+       }
+
+       /**
+        * Loads data from a cache file.
+        *
+        * @param string An identifier which describes the cache entry to load
+        * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function load($entryIdentifier) {
+               $cacheEntry = FALSE;
+
+               if (isset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'][$entryIdentifier])) {
+                       $cacheEntry = $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'][$entryIdentifier];
+               }
+
+               return $cacheEntry;
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param unknown_type
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               return isset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'][$entryIdentifier]);
+       }
+
+       /**
+        * Removes all cache entries matching the specified identifier.
+        * Usually this only affects one entry.
+        *
+        * @param string Specifies the cache entry to remove
+        * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               $cacheEntryFound = $this->has($entryIdentifier);
+
+               if ($cacheEntryFound) {
+                       unset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'][$entryIdentifier]);
+               }
+
+               return $cacheEntryFound;
+       }
+
+       /**
+        * Finds and returns all cache entries which are tagged by the specified tag.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tag.
+        *
+        * @param string The tag to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTag($tag) {
+               $taggedEntries = array();
+
+               if (!empty($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag])) {
+                       $taggedEntries = $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag];
+               }
+
+               return $taggedEntries;
+       }
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * a tag.
+        *
+        * @param array Array of tags to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTags(array $tags) {
+               $taggedEntries = array();
+               $foundEntries  = array();
+
+               foreach ($tags as $tag) {
+                       $taggedEntries[$tag] = $this->findEntriesByTag($tag);
+               }
+
+               $intersectedTaggedEntries = call_user_func_array('array_intersect', $taggedEntries);
+
+               foreach ($intersectedTaggedEntries as $entryIdentifier) {
+                       $foundEntries[$entryIdentifier] = $entryIdentifier;
+               }
+
+               return $foundEntries;
+       }
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * @return void
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function flush() {
+               $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['data'] = array();
+               $GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'] = array();
+       }
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string The tag the entries must have
+        * @return void
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function flushByTag($tag) {
+               unset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag]);
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_globals.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_globals.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/backend/class.t3lib_cache_backend_memcached.php b/t3lib/cache/backend/class.t3lib_cache_backend_memcached.php
new file mode 100644 (file)
index 0000000..d50ea9d
--- /dev/null
@@ -0,0 +1,403 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ *  A caching backend which stores cache entries by using Memcached
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_backend_Memcached extends t3lib_cache_AbstractBackend {
+
+       /**
+        * @var Memcache
+        */
+       protected $memcache;
+
+       /**
+        * @var array
+        */
+       protected $servers = array();
+
+       /**
+        * @var boolean whether the memcache uses compression or not (requires zlib)
+        */
+       protected $useCompressed;
+
+       /**
+        * @var string A prefix to seperate stored data from other data possible stored in the memcache
+        */
+       protected $identifierPrefix;
+
+       /**
+        * Constructs this backend
+        *
+        * @param string $context FLOW3's application context
+        * @param mixed $options Configuration options - depends on the actual backend
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function __construct($options = array()) {
+               if (!extension_loaded('memcache')) {
+                       throw new t3lib_cache_Exception(
+                               'The PHP extension "memcached" must be installed and loaded in order to use the Memcached backend.',
+                               1213987706
+                       );
+               }
+
+               parent::__construct($options);
+
+               $this->memcache = new Memcache();
+               $this->identifierPrefix = 'TYPO3_' . md5(
+                       t3lib_div::getIndpEnv('SCRIPT_FILENAME')
+                       . php_sapi_name()
+               ) . '_';
+
+               if (!count($this->servers)) {
+                       throw new t3lib_cache_Exception(
+                               'No servers were given to Memcache',
+                               1213115903
+                       );
+               }
+
+               foreach ($this->servers as $serverConf) {
+                       $conf = explode(':',$serverConf, 2);
+                       $this->memcache->addServer($conf[0], $conf[1]);
+               }
+       }
+
+       /**
+        * setter for servers property
+        * should be an array of entries like host:port
+        *
+        * @param array An array of servers to add
+        * @return void
+        * @author Christian Jul Jensen <julle@typo3.org>
+        */
+       protected function setServers(array $servers) {
+               $this->servers = $servers;
+       }
+
+       /**
+        * Setter for useCompressed
+        *
+        * @param boolean $enableCompression
+        * @return void
+        * @author Christian Jul Jensen <julle@typo3.org>
+        */
+       protected function setCompression($enableCompression) {
+               $this->useCompressed = $enableCompression;
+       }
+
+       /**
+        * Saves data in the cache.
+        *
+        * @param string An identifier for this specific cache entry
+        * @param string The data to be stored
+        * @param array Tags to associate with this cache entry
+        * @param integer Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
+        * @return void
+        * @throws t3lib_cache_Exception if no cache frontend has been set.
+        * @throws InvalidArgumentException if the identifier is not valid
+        * @throws t3lib_cache_exception_InvalidData if $data is not a string
+        * @author Christian Jul Jensen <julle@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        **/
+       public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
+               if (!self::isValidEntryIdentifier($entryIdentifier)) {
+                       throw new InvalidArgumentException(
+                               '"' . $entryIdentifier . '" is not a valid cache entry identifier.',
+                               1207149191
+                       );
+               }
+
+               if (!$this->cache instanceof t3lib_cache_AbstractCache) {
+                       throw new t3lib_cache_Exception(
+                               'No cache frontend has been set yet via setCache().',
+                               1207149215
+                       );
+               }
+
+               if (!is_string($data)) {
+                       throw new t3lib_cache_Exception_InvalidData(
+                               'The specified data is of type "' . gettype($data) . '" but a string is expected.',
+                               1207149231
+                       );
+               }
+
+               foreach($tags as $tag) {
+                       if (!self::isValidTag($tag)) {
+                               throw new InvalidArgumentException(
+                                       '"' . $tag . '" is not a valid tag.',
+                                       1213120275
+                               );
+                       }
+               }
+
+               $expiration = $lifetime ? $lifetime : $this->defaultLifetime;
+               try {
+                       $this->remove($entryIdentifier);
+                       $success = $this->memcache->set(
+                               $this->identifierPrefix . $entryIdentifier,
+                               $data,
+                               $this->useCompressed,
+                               $expiration
+                       );
+
+                       if (!$success) {
+                               throw new t3lib_cache_Exception(
+                                       'Memcache was unable to connect to any server.',
+                                       1207165277
+                               );
+                       }
+
+                       $this->addTagsToTagIndex($tags);
+                       $this->addIdentifierToTags($entryIdentifier, $tags);
+               } catch(Exception $exception) {
+                       throw new t3lib_cache_Exception(
+                               'Memcache was unable to connect to any server. ' . $exception->getMessage(),
+                               1207208100
+                       );
+               }
+       }
+
+       /**
+        * Loads data from the cache.
+        *
+        * @param string An identifier which describes the cache entry to load
+        * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
+        * @author Christian Jul Jensen <julle@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function load($entryIdentifier) {
+               return $this->memcache->get($this->identifierPrefix . $entryIdentifier);
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Christian Jul Jensen <julle@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               return (boolean) $this->memcache->get($this->identifierPrefix . $entryIdentifier);
+       }
+
+       /**
+        * Removes all cache entries matching the specified identifier.
+        * Usually this only affects one entry but if - for what reason ever -
+        * old entries for the identifier still exist, they are removed as well.
+        *
+        * @param string Specifies the cache entry to remove
+        * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
+        * @author Christian Jul Jensen <julle@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               $this->removeIdentifierFromAllTags($entryIdentifier);
+               return $this->memcache->delete($this->identifierPrefix . $entryIdentifier);
+       }
+
+       /**
+        * Finds and returns all cache entries which are tagged by the specified tag.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tag.
+        *
+        * @param string The tag to search for, the "*" wildcard is supported
+        * @return array An array of entries with all matching entries. An empty array if no entries matched
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function findEntriesByTag($tag) {
+               if (!self::isValidTag($tag)) {
+                       throw new InvalidArgumentException(
+                               '"' . $tag . '" is not a valid tag.',
+                               1213120307
+                       );
+               }
+
+               $entries     = array();
+               $identifiers = $this->findIdentifiersTaggedWith($tag);
+               foreach($identifiers as $identifier) {
+                       $entries[] = $this->load($identifier);
+               }
+
+               return $entries;
+       }
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * Beware that this flushes the complete memcached, not only the cache
+        * entries we stored there. We do this because:
+        *  it is expensive to keep track of all identifiers we put there
+        *  memcache is a cache, you should never rely on things being there
+        *
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function flush() {
+               $this->memcache->flush();
+       }
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string $tag The tag the entries must have
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function flushByTag($tag) {
+               $identifiers = $this->findIdentifiersTaggedWith($tag);
+               foreach($identifiers as $identifier) {
+                       $this->remove($identifier);
+               }
+       }
+
+       /**
+        * Returns an array with all known tags
+        *
+        * @return array
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function getTagIndex() {
+               return (array) $this->memcache->get($this->identifierPrefix . '_tagIndex');
+       }
+
+       /**
+        * Saves the tags known to the backend
+        *
+        * @param array Array of tags
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function setTagIndex(array $tags) {
+               $this->memcache->set(
+                       $this->identifierPrefix . '_tagIndex',
+                       array_unique($tags),
+                       0,
+                       0
+               );
+       }
+
+       /**
+        * Adds the given tags to the tag index
+        *
+        * @param array Array of tags
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function addTagsToTagIndex(array $tags) {
+               if(count($tags)) {
+                       $this->setTagIndex(array_merge($tags, $this->getTagIndex()));
+               }
+       }
+
+       /**
+        * Removes the given tags from the tag index
+        *
+        * @param array $tags
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function removeTagsFromTagIndex(array $tags) {
+               if(count($tags)) {
+                       $this->setTagIndex(array_diff($this->getTagIndex(), $tags));
+               }
+       }
+
+       /**
+        * Associates the identifier with the given tags
+        *
+        * @param string $entryIdentifier
+        * @param array Array of tags
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function addIdentifierToTags($entryIdentifier, array $tags) {
+               foreach($tags as $tag) {
+                       $identifiers   = $this->findIdentifiersTaggedWith($tag);
+                       $identifiers[] = $entryIdentifier;
+                       $this->memcache->set(
+                               $this->identifierPrefix . '_tag_' . $tag,
+                               array_unique($identifiers)
+                       );
+               }
+       }
+
+       /**
+        * Removes association of the identifier with the given tags
+        *
+        * @param string $entryIdentifier
+        * @param array Array of tags
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function removeIdentifierFromAllTags($entryIdentifier) {
+               $tags = $this->getTagIndex();
+
+               foreach($tags as $tag) {
+                       $identifiers = $this->findIdentifiersTaggedWith($tag);
+
+                       if(array_search($entryIdentifier, $identifiers) !== FALSE) {
+                               unset($identifiers[array_search($entryIdentifier, $identifiers)]);
+                       }
+
+                       if(count($identifiers)) {
+                               $this->memcache->set(
+                                       $this->identifierPrefix . '_tag_' . $tag,
+                                       array_unique($identifiers)
+                               );
+                       } else {
+                               $this->removeTagsFromTagIndex(array($tag));
+                               $this->memcache->delete($this->identifierPrefix . '_tag_' . $tag);
+                       }
+               }
+       }
+
+       /**
+        * Returns all identifiers associated with $tag
+        *
+        * @param string $tag
+        * @return array
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function findIdentifiersTaggedWith($tag) {
+               $identifiers = $this->memcache->get($this->identifierPrefix . '_tag_' . $tag);
+
+               if($identifiers !== FALSE) {
+                       return (array) $identifiers;
+               } else {
+                       return array();
+               }
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_memcached.php'])    {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_memcached.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/backend/class.t3lib_cache_backend_null.php b/t3lib/cache/backend/class.t3lib_cache_backend_null.php
new file mode 100644 (file)
index 0000000..e9ad9d6
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A caching backend which forgets everything immediately
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_backend_Null extends t3lib_cache_AbstractBackend {
+
+       /**
+        * Acts as if it would save data
+        *
+        * @param string ignored
+        * @param string ignored
+        * @param array ignored
+        * @param integer ignored
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
+       }
+
+       /**
+        * Returns False
+        *
+        * @param string ignored
+        * @return boolean FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function load($entryIdentifier) {
+               return FALSE;
+       }
+
+       /**
+        * Returns False
+        *
+        * @param string ignored
+        * @return boolean FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               return FALSE;
+       }
+
+       /**
+        * Does nothing
+        *
+        * @param string ignored
+        * @return boolean FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               return FALSE;
+       }
+
+       /**
+        * Returns an empty array
+        *
+        * @param string ignored
+        * @return array An empty array
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function findEntriesByTag($tag) {
+               return array();
+       }
+
+       /**
+        * Returns an empty array
+        *
+        * @param string ignored
+        * @return array An empty array
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function findEntriesByTags(array $tags) {
+               return array();
+       }
+
+       /**
+        * Does nothing
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flush() {
+       }
+
+       /**
+        * Does nothing
+        *
+        * @param string ignored
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flushByTag($tag) {
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_null.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_null.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_abstractbackend.php b/t3lib/cache/class.t3lib_cache_abstractbackend.php
new file mode 100644 (file)
index 0000000..4d58782
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An abstract caching backend
+ *
+ * This file is a backport from FLOW3
+ *
+ * @author     Ingo Renner <ingo@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+abstract class t3lib_cache_AbstractBackend {
+
+       /**
+        * Pattern an entry identifer must match.
+        */
+       const PATTERN_ENTRYIDENTIFIER = '/^[a-zA-Z0-9_%]{1,250}$/';
+
+       /**
+        * Pattern a tag identifer must match.
+        */
+       const PATTERN_TAG = '/^[a-zA-Z0-9_%]{1,250}$/';
+
+       /**
+        * @var t3lib_cache_AbstractCache Reference to the cache which uses this backend
+        */
+       protected $cache;
+
+       /**
+        * @var integer Default lifetime of a cache entry in seconds
+        */
+       protected $defaultLifetime = 3600;
+
+
+       /**
+        * Constructs this backend
+        *
+        * @param mixed Configuration options - depends on the actual backend
+        */
+       public function __construct(array $options = array()) {
+               if (is_array($options) || $options instanceof ArrayAccess) {
+                       foreach ($options as $optionKey => $optionValue) {
+                               $methodName = 'set' . ucfirst($optionKey);
+                               if (method_exists($this, $methodName)) {
+                                       $this->$methodName($optionValue);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Sets a reference to the cache which uses this backend
+        *
+        * @param t3lib_cache_AbstractCache The frontend for this backend
+        * @return void
+        */
+       public function setCache(t3lib_cache_AbstractCache $cache) {
+               $this->cache = $cache;
+       }
+
+       /**
+        * Saves data in the cache.
+        *
+        * @param string An identifier for this specific cache entry
+        * @param string The data to be stored
+        * @param array Tags to associate with this cache entry
+        * @param integer Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
+        * @return void
+        * @throws t3lib_cache_Exception if no cache frontend has been set.
+        * @throws InvalidArgumentException if the identifier is not valid
+        * @throws t3lib_cache_Exception_InvalidData if the data is not a string
+        */
+       abstract public function save($entryIdentifier, $data, array $tags = array(), $lifetime = NULL);
+
+       /**
+        * Loads data from the cache.
+        *
+        * @param string An identifier which describes the cache entry to load
+        * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
+        */
+       abstract public function load($entryIdentifier);
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        */
+       abstract public function has($entryIdentifier);
+
+       /**
+        * Removes all cache entries matching the specified identifier.
+        * Usually this only affects one entry but if - for what reason ever -
+        * old entries for the identifier still exist, they are removed as well.
+        *
+        * @param string Specifies the cache entry to remove
+        * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
+        */
+       abstract public function remove($entryIdentifier);
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * @return void
+        */
+       abstract public function flush();
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string The tag the entries must have
+        * @return void
+        */
+       abstract public function flushByTag($tag);
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tag.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tag.
+        *
+        * @param string The tag to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        */
+       abstract public function findEntriesByTag($tag);
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * a tag.
+        *
+        * @param array Array of tags to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        */
+       abstract public function findEntriesByTags(array $tags);
+
+       /**
+        * Checks the validity of an entry identifier. Returns true if it's valid.
+        *
+        * @param string An identifier to be checked for validity
+        * @return boolean
+        * @author Christian Jul Jensen <julle@typo3.org>
+        */
+       static public function isValidEntryIdentifier($identifier) {
+               return preg_match(self::PATTERN_ENTRYIDENTIFIER, $identifier) === 1;
+       }
+
+       /**
+        * Checks the validity of a tag. Returns true if it's valid.
+        *
+        * @param string An identifier to be checked for validity
+        * @return boolean
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       static public function isValidTag($tag) {
+               return preg_match(self::PATTERN_TAG, $tag) === 1;
+       }
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_abstractbackend.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_abstractbackend.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_abstractcache.php b/t3lib/cache/class.t3lib_cache_abstractcache.php
new file mode 100644 (file)
index 0000000..ef3c95f
--- /dev/null
@@ -0,0 +1,185 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * An abstract cache
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+abstract class t3lib_cache_AbstractCache {
+
+       const PATTERN_IDENTIFIER = '/^[a-zA-Z0-9_%]{1,250}$/';
+
+       /**
+        * @var string Identifies this cache
+        */
+       protected $identifier;
+
+       /**
+        * @var t3lib_cache_AbstractBackend
+        */
+       protected $backend;
+
+       /**
+        * Constructs the cache
+        *
+        * @param string A identifier which describes this cache
+        * @param t3lib_cache_AbstractBackend Backend to be used for this cache
+        * @author Robert Lemke <robert@typo3.org>
+        * @throws InvalidArgumentException if the identifier doesn't match PATTERN_IDENTIFIER
+        */
+       public function __construct($identifier, t3lib_cache_AbstractBackend $backend) {
+               if (!preg_match(self::PATTERN_IDENTIFIER, $identifier)) {
+                       throw new InvalidArgumentException('"' . $identifier . '" is not a valid cache identifier.', 1203584729);
+               }
+
+               $this->identifier = $identifier;
+               $this->backend    = $backend;
+               $this->backend->setCache($this);
+       }
+
+       /**
+        * Returns this cache's identifier
+        *
+        * @return string The identifier for this cache
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getIdentifier() {
+               return $this->identifier;
+       }
+
+       /**
+        * Returns the backend used by this cache
+        *
+        * @return t3lib_cache_AbstractBackend The backend used by this cache
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getBackend() {
+               return $this->backend;
+       }
+
+       /**
+        * Saves data in the cache.
+        *
+        * @param string Something which identifies the data - depends on concrete cache
+        * @param mixed The data to cache - also depends on the concrete cache implementation
+        * @param array Tags to associate with this cache entry
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       abstract public function save($entryIdentifier, $data, array $tags = array());
+
+       /**
+        * Loads data from the cache.
+        *
+        * @param string Something which identifies the cache entry - depends on concrete cache
+        * @return mixed
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       abstract public function load($entryIdentifier);
+
+       /**
+        * Finds, loads, and returns all cache entries which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * the tags.
+        *
+        * @param array An array of tags to search for, the "*" wildcard is supported
+        * @return array An array with all matching entries. An empty array if no entries matched
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function loadByTag(array $tags) {
+               $loadedEntries = array();
+               $foundEntries  = $this->findEntriesByTag($tags);
+
+               foreach($foundEntries as $foundEntryIdentifier) {
+                       $loadedEntries[$foundEntryIdentifier] = $this->load($foundEntryIdentifier);
+               }
+
+               return $loadedEntries;
+       }
+
+       /**
+        * Finds and returns all cache entry identifiers which are tagged by the specified tags.
+        * The asterisk ("*") is allowed as a wildcard at the beginning and the end of
+        * a tag.
+        *
+        * @param array Array of tags to search for, the "*" wildcard is supported
+        * @return array An array with identifiers of all matching entries. An empty array if no entries matched
+        */
+       public function findEntriesByTag(array $tags) {
+               return $this->backend->findEntriesByTags($tags);
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       abstract public function has($entryIdentifier);
+
+       /**
+        * Removes the given cache entry from the cache.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Sebastian Kurfuerst <sebastian@typo3.org>
+        */
+       abstract public function remove($entryIdentifier);
+
+       /**
+        * Removes all cache entries of this cache.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flush() {
+               $this->backend->flush();
+       }
+
+       /**
+        * Removes all cache entries of this cache which are tagged by the specified tag.
+        *
+        * @param string $tag The tag the entries must have
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flushByTag($tag) {
+               $this->backend->flushByTag($tag);
+       }
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_abstractcache.php'])        {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_abstractcache.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_exception.php b/t3lib/cache/class.t3lib_cache_exception.php
new file mode 100644 (file)
index 0000000..0cb5aa6
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A generic Cache exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO33
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_Exception extends Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_exception.php'])    {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_exception.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_factory.php b/t3lib/cache/class.t3lib_cache_factory.php
new file mode 100644 (file)
index 0000000..f68ae10
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * This cache factory takes care of instantiating a cache frontend and injecting
+ * a certain cache backend. After creation of the new cache, the cache object
+ * is registered at the cache manager.
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_Factory {
+
+       /**
+        * A reference to the cache manager
+        *
+        * @var t3lib_cache_Manager
+        */
+       protected $cacheManager;
+
+       /**
+        * Constructs this cache factory
+        *
+        * @param t3lib_cache_Manager A reference to the cache manager
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Ingo Renner <ingo@typo3.org>
+        */
+       public function __construct(t3lib_cache_Manager $cacheManager) {
+               $this->cacheManager = $cacheManager;
+       }
+
+       /**
+        * Factory method which creates the specified cache along with the specified kind of backend.
+        * After creating the cache, it will be registered at the cache manager.
+        *
+        * @param string The name / identifier of the cache to create
+        * @param string Name of the cache frontend
+        * @param string Name of the cache backend
+        * @param array (optional) Array of backend options
+        * @return t3lib_cache_AbstractCache The created cache frontend
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function create($cacheIdentifier, $cacheName, $backendName, array $backendOptions = array()) {
+
+                       // loading the cache backend file and class
+               list($backendFile, $backendClassReference) = explode(
+                       ':',
+                       $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackends'][$backendName]
+               );
+
+               $backendRequireFile = t3lib_div::getFileAbsFileName($backendFile);
+               if ($backendRequireFile) {
+                       t3lib_div::requireOnce($backendRequireFile);
+               }
+
+               $backendClassName = t3lib_div::makeInstanceClassName($backendClassReference);
+               $backend = new $backendClassName($backendOptions);
+
+               if (!$backend instanceof t3lib_cache_AbstractBackend) {
+                       throw new t3lib_cache_exception_InvalidCache(
+                               '"' .$backendName . '" is not a valid cache backend.',
+                               1216304301
+                       );
+               }
+
+
+                       // loading the cache frontend file and class
+               list($cacheFile, $cacheClassReference) = explode(
+                       ':',
+                       $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['caches'][$cacheName]
+               );
+
+               $cacheRequireFile = t3lib_div::getFileAbsFileName($cacheFile);
+               if ($cacheRequireFile) {
+                       t3lib_div::requireOnce($cacheRequireFile);
+               }
+
+               $cacheClassName = t3lib_div::makeInstanceClassName($cacheClassReference);
+               $cache = new $cacheClassName($cacheIdentifier, $backend);
+
+
+               if (!$cache instanceof t3lib_cache_AbstractCache) {
+                       throw new t3lib_cache_exception_InvalidCache(
+                               '"' .$cacheName . '" is not a valid cache.',
+                               1216304300
+                       );
+               }
+
+               $this->cacheManager->registerCache($cache);
+               return $cache;
+       }
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_factory.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_factory.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_manager.php b/t3lib/cache/class.t3lib_cache_manager.php
new file mode 100644 (file)
index 0000000..70c9eee
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * The Cache Manager
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_Manager {
+
+       /**
+        * @const Cache Entry depends on the PHP code of the packages
+        */
+       const TAG_PACKAGES_CODE = '%PACKAGES_CODE';
+
+       /**
+        * @var array Registered Caches
+        */
+       protected $caches = array();
+
+       /**
+        * Registers a cache so it can be retrieved at a later point.
+        *
+        * @param t3lib_cache_AbstractCache The cache to be registered
+        * @return void
+        * @throws t3lib_cache_DuplicateIdentifier if a cache with the given identifier has already been registered.
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function registerCache(t3lib_cache_AbstractCache $cache) {
+               $identifier = $cache->getIdentifier();
+
+               if (array_key_exists($identifier, $this->caches)) {
+                       throw new t3lib_cache_exception_DuplicateIdentifier(
+                               'A cache with identifier "' . $identifier . '" has already been registered.',
+                               1203698223
+                       );
+               }
+
+               $this->caches[$identifier] = $cache;
+       }
+
+       /**
+        * Returns the cache specified by $identifier
+        *
+        * @param string Identifies which cache to return
+        * @return t3lib_cache_AbstractCache The specified cache
+        * @throws t3lib_cache_Exception_NoSuchCache
+        */
+       public function getCache($identifier) {
+               if (!array_key_exists($identifier, $this->caches)) {
+                       throw new t3lib_cache_exception_NoSuchCache(
+                               'A cache with identifier "' . $identifier . '" does not exist.',
+                               1203699034
+                       );
+               }
+
+               return $this->caches[$identifier];
+       }
+
+       /**
+        * Checks if the specified cache has been registered.
+        *
+        * @param string The identifier of the cache
+        * @return boolean TRUE if a cache with the given identifier exists, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function hasCache($identifier) {
+               return array_key_exists($identifier, $this->caches);
+       }
+
+       /**
+        * Flushes all registered caches
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flushCaches() {
+               foreach ($this->caches as $cache) {
+                       $cache->flush();
+               }
+       }
+
+       /**
+        * Flushes entries tagged by the specified tag of all registered
+        * caches.
+        *
+        * @param string Tag to search for
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function flushCachesByTag($tag) {
+               foreach ($this->caches as $cache) {
+                       $cache->flushByTag($tag);
+               }
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_manager.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_manager.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/class.t3lib_cache_variablecache.php b/t3lib/cache/class.t3lib_cache_variablecache.php
new file mode 100644 (file)
index 0000000..decb1af
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A cache for any kinds of PHP variables
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_VariableCache extends t3lib_cache_AbstractCache {
+
+       /**
+        * Saves the value of a PHP variable in the cache. Note that the variable
+        * will be serialized if necessary.
+        *
+        * @param string An identifier used for this cache entry
+        * @param mixed The variable to cache
+        * @param array Tags to associate with this cache entry
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function save($entryIdentifier, $variable, array $tags = array()) {
+               $this->backend->save($entryIdentifier, serialize($variable), $tags);
+       }
+
+       /**
+        * Loads a variable value from the cache.
+        *
+        * @param string Identifier of the cache entry to fetch
+        * @return mixed The value
+        * @author Robert Lemke <robert@typo3.org>
+        * @throws t3lib_cache_exception_ClassAlreadyLoaded if the class already exists
+        */
+       public function load($entryIdentifier) {
+               return unserialize($this->backend->load($entryIdentifier));
+       }
+
+       /**
+        * Checks if a cache entry with the specified identifier exists.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function has($entryIdentifier) {
+               return $this->backend->has($entryIdentifier);
+       }
+
+       /**
+        * Removes the given cache entry from the cache.
+        *
+        * @param string An identifier specifying the cache entry
+        * @return boolean TRUE if such an entry exists, FALSE if not
+        * @author Sebastian Kurfuerst <sebastian@typo3.org>
+        */
+       public function remove($entryIdentifier) {
+               return $this->backend->remove($entryIdentifier);
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_variablecache.php'])        {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/class.t3lib_cache_variablecache.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_classalreadyloaded.php b/t3lib/cache/exception/class.t3lib_cache_exception_classalreadyloaded.php
new file mode 100644 (file)
index 0000000..1ca8615
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A "Class Already Loaded" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_ClassAlreadyLoaded extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_classalreadyloaded.php'])       {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_classalreadyloaded.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_duplicateidentifier.php b/t3lib/cache/exception/class.t3lib_cache_exception_duplicateidentifier.php
new file mode 100644 (file)
index 0000000..f60e1cf
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A "Duplicate Identifier" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_DuplicateIdentifier extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_duplicateidentifier.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_duplicateidentifier.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_invalidbackend.php b/t3lib/cache/exception/class.t3lib_cache_exception_invalidbackend.php
new file mode 100644 (file)
index 0000000..c99d750
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * An "Invalid Backend" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO33
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_InvalidBackend extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invalidbackend.php'])   {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invalidbackend.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_invalidcache.php b/t3lib/cache/exception/class.t3lib_cache_exception_invalidcache.php
new file mode 100644 (file)
index 0000000..758edbb
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * An "Invalid Cache" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_InvalidCache extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invalidcache.php'])     {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invalidcache.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_invaliddata.php b/t3lib/cache/exception/class.t3lib_cache_exception_invaliddata.php
new file mode 100644 (file)
index 0000000..73062bc
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * An "Invalid Data" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_InvalidData extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invaliddata.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_invaliddata.php']);
+}
+
+?>
\ No newline at end of file
diff --git a/t3lib/cache/exception/class.t3lib_cache_exception_nosuchcache.php b/t3lib/cache/exception/class.t3lib_cache_exception_nosuchcache.php
new file mode 100644 (file)
index 0000000..f2787e6
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Ingo Renner <ingo@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A "No Such Cache" exception
+ *
+ * This file is a backport from FLOW3
+ *
+ * @package TYPO3
+ * @subpackage t3lib_cache
+ * @version $Id$
+ */
+class t3lib_cache_exception_NoSuchCache extends t3lib_cache_Exception {
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_nosuchcache.php'])      {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/exception/class.t3lib_cache_exception_nosuchcache.php']);
+}
+
+?>
\ No newline at end of file
index db11788..0128652 100755 (executable)
@@ -100,6 +100,18 @@ $TYPO3_CONF_VARS = Array(
                'reverseProxyPrefix' => '',                             // String: optional prefix to be added to the internal URL (SCRIPT_NAME and REQUEST_URI).
                'reverseProxySSL' => '',                                // String: '*' or list of IP addresses of proxies that use SSL (https) for the connection to the client, but an unencrypted connection (http) to the server. If '*' all proxies defined in SYS[reverseProxyIP] use SSL.
                'reverseProxyPrefixSSL' => '',                          // String: prefix to be added to the internal URL (SCRIPT_NAME and REQUEST_URI) when accessing the server via an SSL proxy. This setting overrides SYS[reverseProxyPrefix].
+               'caching' => array(
+                       'caches' => array(
+                               't3lib_cache_VariableCache' => 't3lib/cache/class.t3lib_cache_variablecache.php:t3lib_cache_VariableCache'
+                       ),
+                       'cacheBackends' => array(
+                               't3lib_cache_backend_Db'        => 't3lib/cache/backend/class.t3lib_cache_backend_db.php:t3lib_cache_backend_Db',
+                               't3lib_cache_backend_File'      => 't3lib/cache/backend/class.t3lib_cache_backend_file.php:t3lib_cache_backend_File',
+                               't3lib_cache_backend_Globals'   => 't3lib/cache/backend/class.t3lib_cache_backend_globals.php:t3lib_cache_backend_Globals',
+                               't3lib_cache_backend_Memcached' => 't3lib/cache/backend/class.t3lib_cache_backend_memcached.php:t3lib_cache_backend_Memcached',
+                               't3lib_cache_backend_Null'      => 't3lib/cache/backend/class.t3lib_cache_backend_null.php:t3lib_cache_backend_Null'
+                       )
+               )
        ),
        'EXT' => Array (        // Options related to the Extension Management
                'noEdit' => 1,                                                  // Boolean: If set, the Extension Manager does NOT allow extension files to be edited! (Otherwise both local and global extensions can be edited.)
index 2c30531..a75e221 100755 (executable)
@@ -150,6 +150,31 @@ $TT->push('Include Frontend libraries','');
        require_once(PATH_t3lib.'class.t3lib_cs.php');
 $TT->pull();
 
+// ***********************************
+// Initializing the Caching System
+// ***********************************
+
+$TT->push('Initializing the Caching System','');
+               // TODO implement autoloading so that we only require stuff we really need
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_abstractbackend.php');
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_abstractcache.php');
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_exception.php');
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_factory.php');
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_manager.php');
+       require_once(PATH_t3lib.'cache/class.t3lib_cache_variablecache.php');
+
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_classalreadyloaded.php');
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_duplicateidentifier.php');
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_invalidbackend.php');
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_invalidcache.php');
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_invaliddata.php');
+       require_once(PATH_t3lib.'cache/exception/class.t3lib_cache_exception_nosuchcache.php');
+
+       $cacheManager      = t3lib_div::makeInstance('t3lib_cache_Manager');
+       $cacheFactoryClass = t3lib_div::makeInstanceClassName('t3lib_cache_Factory');
+       $TYPO3_CACHE       = new $cacheFactoryClass($cacheManager);
+       unset($cacheFactoryClass);
+$TT->pull();
 
 // ***********************************
 // Create $TSFE object (TSFE = TypoScript Front End)
@@ -167,12 +192,12 @@ $TSFE = new $temp_TSFEclassName(
                t3lib_div::_GP('RDCT')
        );
 
-if($TYPO3_CONF_VARS['FE']['pageUnavailable_force'] && 
+if($TYPO3_CONF_VARS['FE']['pageUnavailable_force'] &&
    !t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $TYPO3_CONF_VARS['SYS']['devIPmask'])) {
        $TSFE->pageUnavailableAndExit('This page is temporarily unavailable.');
 }
-       
-       
+
+
 $TSFE->connectToDB();
 
        // In case of a keyword-authenticated preview, re-initialize the TSFE object: