From c1df2277c5a9bd03fcc258833f93a6f190b5d660 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Tue, 30 Jul 2024 13:21:34 +0200 Subject: [PATCH] Detect and handle corrupt images --- .../file/processor/FileProcessor.class.php | 18 ++++++++++++--- .../exception/DamagedImage.class.php | 22 +++++++++++++++++++ .../worker/FileRebuildDataWorker.class.php | 19 ++++++++++++++-- 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/file/processor/exception/DamagedImage.class.php diff --git a/wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php b/wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php index d38534d8b9..5b6459d5f9 100644 --- a/wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php +++ b/wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php @@ -10,6 +10,8 @@ use wcf\data\file\thumbnail\FileThumbnailList; use wcf\data\object\type\ObjectType; use wcf\data\object\type\ObjectTypeCache; use wcf\system\database\util\PreparedStatementConditionBuilder; +use wcf\system\exception\SystemException; +use wcf\system\file\processor\exception\DamagedImage; use wcf\system\image\adapter\ImageAdapter; use wcf\system\image\ImageHandler; use wcf\system\SingletonFactory; @@ -73,7 +75,7 @@ final class FileProcessor extends SingletonFactory $allowedFileExtensions = \implode( ',', \array_map( - static fn (string $fileExtension) => ".{$fileExtension}", + static fn(string $fileExtension) => ".{$fileExtension}", $allowedFileExtensions ) ); @@ -134,7 +136,12 @@ final class FileProcessor extends SingletonFactory } $imageAdapter = ImageHandler::getInstance()->getAdapter(); - $imageAdapter->loadFile($file->getPathname()); + + try { + $imageAdapter->loadFile($file->getPathname()); + } catch (SystemException) { + throw new DamagedImage($file->fileID); + } $filename = FileUtil::getTemporaryFilename(extension: 'webp'); $imageAdapter->saveImageAs($imageAdapter->getImage(), $filename, 'webp', 80); @@ -205,7 +212,12 @@ final class FileProcessor extends SingletonFactory if ($imageAdapter === null) { $imageAdapter = ImageHandler::getInstance()->getAdapter(); - $imageAdapter->loadFile($file->getPathname()); + + try { + $imageAdapter->loadFile($file->getPathname()); + } catch (SystemException) { + throw new DamagedImage($file->fileID); + } } \assert($imageAdapter instanceof ImageAdapter); diff --git a/wcfsetup/install/files/lib/system/file/processor/exception/DamagedImage.class.php b/wcfsetup/install/files/lib/system/file/processor/exception/DamagedImage.class.php new file mode 100644 index 0000000000..5b69754337 --- /dev/null +++ b/wcfsetup/install/files/lib/system/file/processor/exception/DamagedImage.class.php @@ -0,0 +1,22 @@ + + * @since 6.1 + */ +final class DamagedImage extends \Exception +{ + public function __construct(public readonly int $fileID) + { + parent::__construct( + \sprintf( + "The file '%d' is a damaged image.", + $this->fileID, + ), + ); + } +} diff --git a/wcfsetup/install/files/lib/system/worker/FileRebuildDataWorker.class.php b/wcfsetup/install/files/lib/system/worker/FileRebuildDataWorker.class.php index 7a15b88f8f..aa03b53b40 100644 --- a/wcfsetup/install/files/lib/system/worker/FileRebuildDataWorker.class.php +++ b/wcfsetup/install/files/lib/system/worker/FileRebuildDataWorker.class.php @@ -2,9 +2,13 @@ namespace wcf\system\worker; +use wcf\data\file\FileEditor; use wcf\data\file\FileList; +use wcf\system\file\processor\exception\DamagedImage; use wcf\system\file\processor\FileProcessor; +use function wcf\functions\exception\logThrowable; + /** * Worker implementation for updating files. * @@ -41,9 +45,20 @@ final class FileRebuildDataWorker extends AbstractLinearRebuildDataWorker { parent::execute(); + $damagedFileIDs = []; foreach ($this->objectList as $file) { - FileProcessor::getInstance()->generateWebpVariant($file); - FileProcessor::getInstance()->generateThumbnails($file); + try { + FileProcessor::getInstance()->generateWebpVariant($file); + FileProcessor::getInstance()->generateThumbnails($file); + } catch (DamagedImage $e) { + logThrowable($e); + + $damagedFileIDs[] = $e->fileID; + } + } + + if ($damagedFileIDs !== []) { + FileEditor::deleteAll($damagedFileIDs); } } } -- 2.20.1