[BUGFIX][Cache][PDO] Duplicate cache entry possible 44/9144/6
authorLeon Dietsch <leon.dietsch@googlemail.com>
Tue, 27 Nov 2012 01:12:52 +0000 (02:12 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Thu, 7 Feb 2013 21:20:13 +0000 (22:20 +0100)
An identifier must be unique in the database. If some entry is set(),
the PdoBackend removes any entry with a given identifier if the cache
entry exists already. The remove() call is encapsulated with has(),
but has() returns FALSE if a cache entry is expired, so entries with
expired lifetime are not removed properly.
This leads to a \PDOException because of duplicate identifier.

The patch removes the check to has(), so set() will also remove
expired cache entries with this identifier before creating a new one.

Change-Id: Ife4e35223394805fc6d9e0b820a5d42789133f7b
Fixes: #34129
Releases: 6.1, 6.0, 4.7, 4.6, 4.5
Reviewed-on: https://review.typo3.org/9144
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
typo3/sysext/core/Classes/Cache/Backend/PdoBackend.php
typo3/sysext/core/Tests/Unit/Cache/Backend/PdoBackendTest.php

index 37e1385..fcf7132 100644 (file)
@@ -48,7 +48,7 @@ class PdoBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implement
        protected $password;
 
        /**
-        * @var PDO
+        * @var \PDO
         */
        protected $databaseHandle;
 
@@ -119,9 +119,7 @@ class PdoBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implement
                if (!is_string($data)) {
                        throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1259515601);
                }
-               if ($this->has($entryIdentifier)) {
-                       $this->remove($entryIdentifier);
-               }
+               $this->remove($entryIdentifier);
                $lifetime = $lifetime === NULL ? $this->defaultLifetime : $lifetime;
                $statementHandle = $this->databaseHandle->prepare('INSERT INTO "cache" ("identifier", "context", "cache", "created", "lifetime", "content") VALUES (?, ?, ?, ?, ?, ?)');
                $result = $statementHandle->execute(array($entryIdentifier, $this->context, $this->cacheIdentifier, $GLOBALS['EXEC_TIME'], $lifetime, $data));
index 70b84c2..a2f14ac 100644 (file)
@@ -137,6 +137,20 @@ class PdoBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        /**
         * @test
         */
+       public function setOverwritesExistingEntryThatExceededItsLifetimeWithNewData() {
+               $backend = $this->setUpBackend();
+               $data1 = 'data1';
+               $entryIdentifier = uniqid('test');
+               $backend->set($entryIdentifier, $data1, array(), 1);
+               $data2 = 'data2';
+               $GLOBALS['EXEC_TIME'] += 2;
+               $backend->set($entryIdentifier, $data2, array(), 10);
+               $this->assertEquals($data2, $backend->get($entryIdentifier));
+       }
+
+       /**
+        * @test
+        */
        public function hasReturnsFalseIfTheEntryDoesntExist() {
                $backend = $this->setUpBackend();
                $identifier = 'NonExistingIdentifier';