Bug #99406
Updated by Sybille Peters almost 2 years ago
Exception when opening the file brower in v11.5.21: #1476107295 TYPO3\CMS\Core\Error\Exception PHP Warning: Trying to access array offset on value of type bool in /var/www/site-uol11/htdocs/typo3/sysext/core/Classes/Resource/Processing/LocalImageProcessor.php line 124 LocalImageProcessor: <pre> Line 122: $imageDimensions = $this->getGraphicalFunctionsObject()->getImageDimensions($localProcessedFile); Line 123: $properties = [ Line 124 'width' => $imageDimensions[0], </pre> LocalImageProcessor::checkForExistingTargetFile calls $this->getGraphicalFunctionsObject()->getImageDimensions( and expects result to be array and accesses array elements without ??. But getImageDimensions may return false since it calls getCachedImageDimensions which may return false. h2. Reproduce 1. Open the file browser, for example, for adding images to textmedia 2. Enable preview images 3. close browser again and prepare one of the preview thumbnail files. For example set to empty: <pre> rm path/filename touch path/filename </pre> 4. Open the file browser again. This time, an exception will occur. (occurred when file browser was opened to select a file. The file it tried to access was: /var/www/site-uol11/htdocs/fileadmin/_processed/7/3/preview_18db9f6295_aa23222219.gif. This file was empty (zero content). This should normally not happen but should probably not result in exception either if image dimensions cannot be detected.). h2. Problems 1. wrong return type declaration in getImageDimensions. Either getCachedImageDimensions should not return bool or the phpdoc for getImageDimensions should be changed. 2. no checking if getImageDimensions() returned array in checkForExistingTargetFile and not checking if array elements filled in checkForExistingTargetFile 3. Generally no strong type hinting so these problems can easily occur without being detected by phpstan (for example). detected. h2. Source in main branch: <pre><code class="php"> protected function checkForExistingTargetFile(TaskInterface $task) { // the storage of the processed file, not of the original file! $storage = $task->getTargetFile()->getStorage(); $processingFolder = $storage->getProcessingFolder($task->getSourceFile()); // explicitly check for the raw filename here, as we check for files that existed before we even started // processing, i.e. that were processed earlier if ($processingFolder->hasFile($task->getTargetFileName())) { // When the processed file already exists set it as processed file $task->getTargetFile()->setName($task->getTargetFileName()); // If the processed file is stored on a remote server, we must fetch a local copy of the file, as we // have no API for fetching file metadata from a remote file. $localProcessedFile = $storage->getFileForLocalProcessing($task->getTargetFile(), false); $task->setExecuted(true); $imageDimensions = $this->getGraphicalFunctionsObject()->getImageDimensions($localProcessedFile); $properties = [ 'width' => $imageDimensions[0], 'height' => $imageDimensions[1], ... </code></pre> <pre><code class="php"> /** * Gets the input image dimensions. * * @param string $imageFile The image filepath * @return array|null Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. * @see imageMagickConvert() * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getImgResource() */ public function getImageDimensions($imageFile) { $returnArr = null; preg_match('/([^\\.]*)$/', $imageFile, $reg); if (file_exists($imageFile) && in_array(strtolower($reg[0]), $this->imageFileExt, true)) { $returnArr = $this->getCachedImageDimensions($imageFile); if (!$returnArr) { $imageInfoObject = GeneralUtility::makeInstance(ImageInfo::class, $imageFile); if ($imageInfoObject->getWidth()) { $returnArr = [ $imageInfoObject->getWidth(), $imageInfoObject->getHeight(), strtolower($reg[0]), $imageFile, ]; $this->cacheImageDimensions($returnArr); } } } return $returnArr; } </code></pre> <pre><code class="php"> /** * Fetches the cached image dimensions from the cache. Does not check if the image file exists. * * @param string $filePath Image file path, relative to public web 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->generateStatusHashForImageFile($filePath); $identifier = $this->generateCacheKeyForImageFile($filePath); $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('imagesizes'); $cachedImageDimensions = $cache->get($identifier); if (!isset($cachedImageDimensions['hash'])) { return false; } ... </code></pre>