[BUGFIX] Apc Cache backend has side effects 73/17473/5
authorDaniel Po╠łtzinger <poetzinger@aoemedia.de>
Sun, 17 Jun 2012 12:09:41 +0000 (14:09 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Sat, 12 Jan 2013 13:13:24 +0000 (14:13 +0100)
If two caches use the APC cache backend,
one cache can write and get entries from the
 other by just using the same key!
So the backend should also use cache id as prefix

Change-Id: I46f7a04386427efb2e1753bef6dfa588508d076c
Fixes: #38135
Releases: 4.5,4.6,4.7,6.0
Reviewed-on: https://review.typo3.org/17473
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
t3lib/cache/backend/class.t3lib_cache_backend_apcbackend.php
tests/t3lib/cache/backend/t3lib_cache_backend_apcbackendTest.php

index 185215e..b0fa256 100644 (file)
@@ -60,6 +60,24 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
        protected $identifierPrefix;
 
        /**
+        * Set the cache identifier prefix.
+        *
+        * @param string $identifierPrefix
+        */
+       protected function setIdentifierPrefix($identifierPrefix) {
+               $this->identifierPrefix = $identifierPrefix;
+       }
+
+       /**
+        * Retrieves the cache identifier prefix.
+        *
+        * @return string
+        */
+       protected function getIdentifierPrefix() {
+               return $this->identifierPrefix;
+       }
+
+       /**
         * Constructs this backend
         *
         * @param array $options Configuration options - unused here
@@ -86,9 +104,28 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        public function setCache(t3lib_cache_frontend_Frontend $cache) {
                parent::setCache($cache);
-               $processUser = extension_loaded('posix') ? posix_getpwuid(posix_geteuid()) : array('name' => 'default');
-               $pathHash = t3lib_div::shortMD5(PATH_site . $processUser['name'], 12);
-               $this->identifierPrefix = 'TYPO3_' . $pathHash;
+               $processUser = $this->getCurrentUserData();
+               $pathHash = t3lib_div::shortMD5($this->getPathSite() . $processUser['name'] . $cache->getIdentifier(), 12);
+               $this->setIdentifierPrefix('TYPO3_' . $pathHash);
+       }
+
+       /**
+        * Returns the current user data with posix_getpwuid or a default structure when
+        * posix_getpwuid is not available.
+        *
+        * @return array
+        */
+       protected function getCurrentUserData() {
+               return extension_loaded('posix') ? posix_getpwuid(posix_geteuid()) : array('name' => 'default');
+       }
+
+       /**
+        * Returns the PATH_site constant.
+        *
+        * @return string
+        */
+       protected function getPathSite() {
+               return PATH_site;
        }
 
        /**
@@ -123,7 +160,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
                $tags[] = '%APCBE%' . $this->cacheIdentifier;
                $expiration = $lifetime !== NULL ? $lifetime : $this->defaultLifetime;
 
-               $success = apc_store($this->identifierPrefix . $entryIdentifier, $data, $expiration);
+               $success = apc_store($this->getIdentifierPrefix() . $entryIdentifier, $data, $expiration);
                if ($success === TRUE) {
                        $this->removeIdentifierFromAllTags($entryIdentifier);
                        $this->addIdentifierToTags($entryIdentifier, $tags);
@@ -144,7 +181,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        public function get($entryIdentifier) {
                $success = FALSE;
-               $value = apc_fetch($this->identifierPrefix . $entryIdentifier, $success);
+               $value = apc_fetch($this->getIdentifierPrefix() . $entryIdentifier, $success);
 
                return ($success ? $value : $success);
        }
@@ -158,7 +195,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        public function has($entryIdentifier) {
                $success = FALSE;
-               apc_fetch($this->identifierPrefix . $entryIdentifier, $success);
+               apc_fetch($this->getIdentifierPrefix() . $entryIdentifier, $success);
                return $success;
        }
 
@@ -174,8 +211,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        public function remove($entryIdentifier) {
                $this->removeIdentifierFromAllTags($entryIdentifier);
-
-               return apc_delete($this->identifierPrefix . $entryIdentifier);
+               return apc_delete($this->getIdentifierPrefix() . $entryIdentifier);
        }
 
        /**
@@ -188,7 +224,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        public function findIdentifiersByTag($tag) {
                $success = FALSE;
-               $identifiers = apc_fetch($this->identifierPrefix . 'tag_' . $tag, $success);
+               $identifiers = apc_fetch($this->getIdentifierPrefix() . 'tag_' . $tag, $success);
 
                if ($success === FALSE) {
                        return array();
@@ -234,7 +270,7 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
         */
        protected function findTagsByIdentifier($identifier) {
                $success = FALSE;
-               $tags = apc_fetch($this->identifierPrefix . 'ident_' . $identifier, $success);
+               $tags = apc_fetch($this->getIdentifierPrefix() . 'ident_' . $identifier, $success);
 
                return ($success ? (array) $tags : array());
        }
@@ -299,13 +335,13 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
                        $identifiers = $this->findIdentifiersByTag($tag);
                        if (array_search($entryIdentifier, $identifiers) === FALSE) {
                                $identifiers[] = $entryIdentifier;
-                               apc_store($this->identifierPrefix . 'tag_' . $tag, $identifiers);
+                               apc_store($this->getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
                        }
 
                                // Update identifier-to-tag index
                        $existingTags = $this->findTagsByIdentifier($entryIdentifier);
                        if (array_search($entryIdentifier, $existingTags) === false) {
-                               apc_store($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
+                               apc_store($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
                        }
 
                }
@@ -333,14 +369,14 @@ class t3lib_cache_backend_ApcBackend extends t3lib_cache_backend_AbstractBackend
                        if (($key = array_search($entryIdentifier, $identifiers)) !== FALSE) {
                                unset($identifiers[$key]);
                                if (count($identifiers)) {
-                                       apc_store($this->identifierPrefix . 'tag_' . $tag, $identifiers);
+                                       apc_store($this->getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
                                } else {
-                                       apc_delete($this->identifierPrefix . 'tag_' . $tag);
+                                       apc_delete($this->getIdentifierPrefix() . 'tag_' . $tag);
                                }
                        }
                }
                        // Clear reverse tag index for this identifier
-               apc_delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
+               apc_delete($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier);
        }
 
        /**
index bf9b62a..09f891e 100644 (file)
 ***************************************************************/
 
 /**
- * Testcase for the APC cache backend
+ * Testcase for the APC cache backend.
+ *
+ * NOTE: If you want to execute these tests you need to enable apc in
+ * cli context (apc.enable_cli = 1)
  *
  * This file is a backport from FLOW3
  *
@@ -155,6 +158,33 @@ class t3lib_cache_backend_ApcBackendTest extends tx_phpunit_testcase {
 
        /**
         * @test
+        * @author Timo Schmidt <timo.schmidt@gmx.net>
+        */
+       public function setCacheIsSettingIdentifierPrefixWithCacheIdentifier() {
+               $cacheMock = $this->getMock('t3lib_cache_frontend_Frontend', array(), array(), '', FALSE);
+               $cacheMock->expects($this->any())
+                               ->method('getIdentifier')
+                               ->will($this->returnValue('testidentifier'));
+
+               /** @var $backendMock t3lib_cache_backend_ApcBackend|PHPUnit_Framework_MockObject_MockObject */
+               $backendMock = $this->getMock('t3lib_cache_backend_ApcBackend', array('setIdentifierPrefix','getCurrentUserData','getPathSite'));
+
+               $backendMock->expects($this->once())
+                               ->method('getCurrentUserData')
+                               ->will($this->returnValue(array('name' => 'testname'))
+               );
+
+               $backendMock->expects($this->once())
+                               ->method('getPathSite')
+                               ->will($this->returnValue('testpath'));
+
+               $expectedIdentifier = 'TYPO3_'.t3lib_div::shortMD5('testpath' . 'testname' . 'testidentifier', 12);
+               $backendMock->expects($this->once())->method('setIdentifierPrefix')->with($expectedIdentifier);
+               $backendMock->setCache($cacheMock);
+       }
+
+       /**
+        * @test
         * @author Christian Jul Jensen <julle@typo3.org>
         */
        public function hasReturnsFalseIfTheEntryDoesntExist() {