[TASK] Cache cache_imagesizes using the Caching Framework 86/35686/9
authorBenjamin Mack <benni@typo3.org>
Wed, 31 Dec 2014 00:17:16 +0000 (01:17 +0100)
committerHelmut Hummel <helmut.hummel@typo3.org>
Mon, 2 Mar 2015 18:04:22 +0000 (19:04 +0100)
Streamline the code by moving the functionality to cache image sizes
processed by GraphicalFunctions (local-only so far) from the database
table cache_imagesizes to the Caching Framework.

The following changes are done:
* use sha1 instead of md5
* use Caching Framework instead of hardcoded DB table
* store only necessary data in the cache

The new Caching Framework configuration is stored
in a new group called "lowlevel" which is only emptied
when pressing the clear cache button in the install tool.

The former table cache_imagesizes has been filled automatically and
never been cleaned except manually in the Install Tool area "Cleanup".
This means there could be a lot of leftover entries. Now the cache is
cleared when using the common clear caches button in the install tool.

Resolves: #28484
Releases: master
Change-Id: Ia68410eb382163e90654718aeb17165dc48e40cc
Reviewed-on: http://review.typo3.org/35686
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Stephan GroƟberndt <stephan@grossberndt.de>
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
Tested-by: Helmut Hummel <helmut.hummel@typo3.org>
typo3/sysext/core/Classes/Imaging/GraphicalFunctions.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/ext_tables.sql
typo3/sysext/install/Classes/Controller/Action/Tool/CleanUp.php

index 81b0f13..b22cf55 100644 (file)
@@ -227,7 +227,7 @@ class GraphicalFunctions {
        public $absPrefix = '';
 
        /**
-        * ImageMagick scaling command; "-geometry" eller "-sample". Used in makeText() and imageMagickConvert()
+        * ImageMagick scaling command; "-geometry" or "-sample". Used in makeText() and imageMagickConvert()
         *
         * @var string
         */
@@ -2234,7 +2234,7 @@ class GraphicalFunctions {
                                if (file_exists($output)) {
                                        $info[3] = $output;
                                        $info[2] = $newExt;
-                                       // params could realisticly change some imagedata!
+                                       // params might change some image data!
                                        if ($params) {
                                                $info = $this->getImageDimensions($info[3]);
                                        }
@@ -2261,7 +2261,7 @@ class GraphicalFunctions {
                        if ($returnArr = $this->getCachedImageDimensions($imageFile)) {
                                return $returnArr;
                        } else {
-                               if ($temp = @getImageSize($imageFile)) {
+                               if ($temp = @getimagesize($imageFile)) {
                                        $returnArr = array($temp[0], $temp[1], strtolower($reg[0]), $imageFile);
                                } else {
                                        $returnArr = $this->imageMagickIdentify($imageFile);
@@ -2276,61 +2276,75 @@ class GraphicalFunctions {
        }
 
        /**
-        * Cache the result of the getImageDimensions function into the database. Does not check if the
-        * file exists!
+        * Caches the result of the getImageDimensions function into the database. Does not check if the file exists.
         *
         * @param array $identifyResult Result of the getImageDimensions function
-        * @return bool TRUE if operation was successful
+        *
+        * @return bool always TRUE
         */
-       public function cacheImageDimensions($identifyResult) {
-               // Create md5 hash of filemtime and filesize
-               $fileStatus = stat($identifyResult[3]);
-               $md5Hash = md5($fileStatus['mtime'] . $fileStatus['size']);
-               $result = FALSE;
-               if ($md5Hash) {
-                       $fieldArray = array(
-                               'md5hash' => $md5Hash,
-                               'md5filename' => md5($identifyResult[3]),
-                               'tstamp' => $GLOBALS['EXEC_TIME'],
-                               'filename' => $identifyResult[3],
-                               'imagewidth' => $identifyResult[0],
-                               'imageheight' => $identifyResult[1]
+       public function cacheImageDimensions(array $identifyResult) {
+               $filePath = $identifyResult[3];
+               $statusHash = $this->generateCacheKeyForImageFile($filePath);
+
+               /** @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend $cache */
+               $cache = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_imagesizes');
+               $imageDimensions = array(
+                       'hash'        => $statusHash,
+                       'imagewidth'  => $identifyResult[0],
+                       'imageheight' => $identifyResult[1],
+               );
+               $cache->set($statusHash, $imageDimensions);
+
+               return TRUE;
+       }
+
+       /**
+        * Fetches the cached image dimensions from the cache. Does not check if the image file exists.
+        *
+        * @param string $filePath the image file path
+        *
+        * @return array|bool an array where [0]/[1] is w/h, [2] is extension and [3] is the file name,
+        *                    or FALSE for a cache miss
+        */
+       public function getCachedImageDimensions($filePath) {
+               $statusHash = $this->generateCacheKeyForImageFile($filePath);
+               /** @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend $cache */
+               $cache = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_imagesizes');
+               $cachedImageDimensions = $cache->get($statusHash);
+               if (!isset($cachedImageDimensions['hash'])) {
+                       return FALSE;
+               }
+
+               if ($cachedImageDimensions['hash'] !== $statusHash) {
+                       // The file has changed. Delete the cache entry.
+                       $cache->remove($filePath);
+                       $result = FALSE;
+               } else {
+                       preg_match('/([^\\.]*)$/', $filePath, $imageExtension);
+                       $result = array(
+                               (int)$cachedImageDimensions['imagewidth'],
+                               (int)$cachedImageDimensions['imageheight'],
+                               strtolower($imageExtension[0]),
+                               $filePath
                        );
-                       $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_imagesizes', $fieldArray);
-                       if (!($err = $GLOBALS['TYPO3_DB']->sql_error())) {
-                               $result = TRUE;
-                       }
                }
+
                return $result;
        }
 
        /**
-        * Fetch the cached imageDimensions from the MySQL database. Does not check if the image file exists!
+        * Creates the key for the image dimensions cache for an image file.
         *
-        * @param string $imageFile The image filepath
-        * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
+        * This method does not check if the image file actually exists.
+        *
+        * @param string $filePath
+        *
+        * @return string the hash key (an SHA1 hash), will not be empty
         */
-       public function getCachedImageDimensions($imageFile) {
-               // Create md5 hash of filemtime and filesize
-               $fileStatus = stat($imageFile);
-               $md5Hash = md5($fileStatus['mtime'] . $fileStatus['size']);
-               $cachedImageDimensions = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('md5hash, md5filename, imagewidth, imageheight', 'cache_imagesizes', 'md5filename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr(md5($imageFile), 'cache_imagesizes'));
-               $result = FALSE;
-               if (is_array($cachedImageDimensions)) {
-                       if ($cachedImageDimensions['md5hash'] != $md5Hash) {
-                               // File has changed, delete the row
-                               $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_imagesizes', 'md5filename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($cachedImageDimensions['md5filename'], 'cache_imagesizes'));
-                       } else {
-                               preg_match('/([^\\.]*)$/', $imageFile, $imageExtension);
-                               $result = array(
-                                       (int)$cachedImageDimensions['imagewidth'],
-                                       (int)$cachedImageDimensions['imageheight'],
-                                       strtolower($imageExtension[0]),
-                                       $imageFile
-                               );
-                       }
-               }
-               return $result;
+       protected function generateCacheKeyForImageFile($filePath) {
+               $fileStatus = stat($filePath);
+
+               return sha1($fileStatus['mtime'] . $fileStatus['size']);
        }
 
        /**
index 746d5e2..11973ab 100644 (file)
@@ -175,6 +175,14 @@ return array(
                                        'options' => array(),
                                        'groups' => array('pages', 'all')
                                ),
+                               'cache_imagesizes' => array(
+                                       'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
+                                       'backend' => \TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend::class,
+                                       'options' => array(
+                                               'defaultLifetime' => 0,
+                                       ),
+                                       'groups' => array('lowlevel'),
+                               ),
                                'l10n' => array(
                                        'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
                                        'backend' => \TYPO3\CMS\Core\Cache\Backend\SimpleFileBackend::class,
index d5538e7..f05f5e2 100644 (file)
@@ -91,19 +91,6 @@ CREATE TABLE be_users (
 );
 
 #
-# Table structure for table 'cache_imagesizes'
-#
-CREATE TABLE cache_imagesizes (
-       md5hash varchar(32) DEFAULT '' NOT NULL,
-       md5filename varchar(32) DEFAULT '' NOT NULL,
-       tstamp int(11) DEFAULT '0' NOT NULL,
-       filename varchar(255) DEFAULT '' NOT NULL,
-       imagewidth mediumint(11) unsigned DEFAULT '0' NOT NULL,
-       imageheight mediumint(11) unsigned DEFAULT '0' NOT NULL,
-       PRIMARY KEY (md5filename)
-) ENGINE=InnoDB;
-
-#
 # Table structure for table 'pages'
 #
 CREATE TABLE pages (
index 64c4a47..83959f6 100644 (file)
@@ -63,10 +63,6 @@ class CleanUp extends Action\AbstractAction {
                                'description' => 'Backend user sessions'
                        ),
                        array(
-                               'name' => 'cache_imagesizes',
-                               'description' => 'Cached image sizes',
-                       ),
-                       array(
                                'name' => 'cache_md5params',
                                'description' => 'Frontend redirects',
                        ),