From cf5f6414ce5383bb94ff3bfba6a607986242ed35 Mon Sep 17 00:00:00 2001 From: umherirrender Date: Wed, 25 Jun 2014 21:30:08 +0200 Subject: [PATCH] Add better error message for files which exceeds $wgMaxImageArea Added a TransformTooBigImageAreaError to allow setting an extra message. Added also size-*pixel messages to show the value of $wgMaxImageArea with some formatting. This error is still throwing for all files, to fix bug T34387 this needs a follow up with a proper check. I am not sure, if a File::isLocal() is okay, because files from a DBForeignRepo maybe transformed on the same server, so the check needs to be done also for this. For APIForeignRepo the check is done on the foreign server. Change-Id: Ieba12e424c8bddb1961a30d3f9ea5c8ff241abb5 --- autoload.php | 1 + includes/media/MediaTransformOutput.php | 21 ++++++ .../media/TransformationalImageHandler.php | 67 ++++++++++++------- languages/i18n/en.json | 10 +++ languages/i18n/qqq.json | 10 +++ .../includes/media/BitmapScalingTest.php | 4 +- 6 files changed, 88 insertions(+), 25 deletions(-) diff --git a/autoload.php b/autoload.php index 175ab42a89..107ab81da7 100644 --- a/autoload.php +++ b/autoload.php @@ -1179,6 +1179,7 @@ $wgAutoloadLocalClasses = array( 'TraditionalImageGallery' => __DIR__ . '/includes/gallery/TraditionalImageGallery.php', 'TransactionProfiler' => __DIR__ . '/includes/profiler/TransactionProfiler.php', 'TransformParameterError' => __DIR__ . '/includes/media/MediaTransformOutput.php', + 'TransformTooBigImageAreaError' => __DIR__ . '/includes/media/MediaTransformOutput.php', 'TransformationalImageHandler' => __DIR__ . '/includes/media/TransformationalImageHandler.php', 'UDPRCFeedEngine' => __DIR__ . '/includes/rcfeed/UDPRCFeedEngine.php', 'UIDGenerator' => __DIR__ . '/includes/utils/UIDGenerator.php', diff --git a/includes/media/MediaTransformOutput.php b/includes/media/MediaTransformOutput.php index 98f755299f..1dd8519155 100644 --- a/includes/media/MediaTransformOutput.php +++ b/includes/media/MediaTransformOutput.php @@ -477,3 +477,24 @@ class TransformParameterError extends MediaTransformError { wfMessage( 'thumbnail_invalid_params' )->text() ); } } + +/** + * Shortcut class for parameter file size errors + * + * @ingroup Media + * @since 1.25 + */ +class TransformTooBigImageAreaError extends MediaTransformError { + function __construct( $params, $maxImageArea ) { + $msg = wfMessage( 'thumbnail_toobigimagearea' ); + + parent::__construct( 'thumbnail_error', + max( isset( $params['width'] ) ? $params['width'] : 0, 120 ), + max( isset( $params['height'] ) ? $params['height'] : 0, 120 ), + $msg->rawParams( + $msg->getLanguage()->formatComputingNumbers( + $maxImageArea, 1000, "size-$1pixel" ) + )->text() + ); + } +} diff --git a/includes/media/TransformationalImageHandler.php b/includes/media/TransformationalImageHandler.php index 5b9982def9..51cd28d2c8 100644 --- a/includes/media/TransformationalImageHandler.php +++ b/includes/media/TransformationalImageHandler.php @@ -61,29 +61,6 @@ abstract class TransformationalImageHandler extends ImageHandler { } } - # Check if the file is smaller than the maximum image area for thumbnailing - # For historical reasons, hook starts with BitmapHandler - $checkImageAreaHookResult = null; - Hooks::run( - 'BitmapHandlerCheckImageArea', - array( $image, &$params, &$checkImageAreaHookResult ) - ); - - if ( is_null( $checkImageAreaHookResult ) ) { - global $wgMaxImageArea; - - if ( $srcWidth * $srcHeight > $wgMaxImageArea - && !( $image->getMimeType() == 'image/jpeg' - && $this->getScalerType( false, false ) == 'im' ) - ) { - # Only ImageMagick can efficiently downsize jpg images without loading - # the entire file in memory - return false; - } - } else { - return $checkImageAreaHookResult; - } - return true; } @@ -190,6 +167,11 @@ abstract class TransformationalImageHandler extends ImageHandler { return $this->getClientScalingThumbnailImage( $image, $scalerParams ); } + if ( !$this->isImageAreaOkForThumbnaling( $image, $params ) ) { + global $wgMaxImageArea; + return new TransformTooBigImageAreaError( $params, $wgMaxImageArea ); + } + if ( $flags & self::TRANSFORM_LATER ) { wfDebug( __METHOD__ . ": Transforming later per flags.\n" ); $newParams = array( @@ -596,4 +578,43 @@ abstract class TransformationalImageHandler extends ImageHandler { public function mustRender( $file ) { return $this->canRotate() && $this->getRotation( $file ) != 0; } + + /** + * Check if the file is smaller than the maximum image area for thumbnailing. + * + * Runs the 'BitmapHandlerCheckImageArea' hook. + * + * @param File $file + * @param array $params + * @return bool + * @since 1.25 + */ + public function isImageAreaOkForThumbnaling( $file, $params ) { + global $wgMaxImageArea; + + # For historical reasons, hook starts with BitmapHandler + $checkImageAreaHookResult = null; + Hooks::run( + 'BitmapHandlerCheckImageArea', + array( $file, $params, &$checkImageAreaHookResult ) + ); + + if ( !is_null( $checkImageAreaHookResult ) ) { + // was set by hook, so return that value + return (bool)$checkImageAreaHookResult; + } + + $srcWidth = $file->getWidth( $params['page'] ); + $srcHeight = $file->getHeight( $params['page'] ); + + if ( $srcWidth * $srcHeight > $wgMaxImageArea + && !( $file->getMimeType() == 'image/jpeg' + && $this->getScalerType( false, false ) == 'im' ) + ) { + # Only ImageMagick can efficiently downsize jpg images without loading + # the entire file in memory + return false; + } + return true; + } } diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 52e3a78f8d..583fc5d328 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -2274,6 +2274,7 @@ "thumbnail-temp-create": "Unable to create temporary thumbnail file", "thumbnail-dest-create": "Unable to save thumbnail to destination", "thumbnail_invalid_params": "Invalid thumbnail parameters", + "thumbnail_toobigimagearea": "File with dimensions greater than $1", "thumbnail_dest_directory": "Unable to create destination directory", "thumbnail_image-type": "Image type not supported", "thumbnail_gd-library": "Incomplete GD library configuration: Missing function $1", @@ -3139,6 +3140,15 @@ "size-exabytes": "$1 EB", "size-zetabytes": "$1 ZB", "size-yottabytes": "$1 YB", + "size-pixel": "$1 P", + "size-kilopixel": "$1 KP", + "size-megapixel": "$1 MP", + "size-gigapixel": "$1 GP", + "size-terapixel": "$1 TP", + "size-petapixel": "$1 PP", + "size-exapixel": "$1 EP", + "size-zetapixel": "$1 ZP", + "size-yottapixel": "$1 YP", "bitrate-bits": "$1 bps", "bitrate-kilobits": "$1 kbps", "bitrate-megabits": "$1 Mbps", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 2082104069..813064d799 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -2438,6 +2438,7 @@ "thumbnail-temp-create": "Used as thumbnail error message.\n\nSee also:\n* {{msg-mw|Thumbnail-dest-create}}\n* {{msg-mw|Thumbnail invalid params}}\n* {{msg-mw|Thumbnail dest directory}}", "thumbnail-dest-create": "Used as thumbnail error message.\n\nSee also:\n* {{msg-mw|Thumbnail error}}\n* {{msg-mw|Thumbnail-temp-create}}\n* {{msg-mw|Thumbnail invalid params}}\n* {{msg-mw|Thumbnail dest directory}}", "thumbnail_invalid_params": "Used as thumbnail error message.\n\nSee also:\n* {{msg-mw|Thumbnail-temp-create}}\n* {{msg-mw|Thumbnail-dest-create}}\n* {{msg-mw|Thumbnail dest directory}}", + "thumbnail_toobigimagearea": "Used as thumbnail error message.\n\n* $1 - Size in pixel (see {{msg-mw|size-megapixel}} and friends)", "thumbnail_dest_directory": "Used as thumbnail error message.\n\nSee also:\n* {{msg-mw|Thumbnail error}}\n* {{msg-mw|Thumbnail-temp-create}}\n* {{msg-mw|Thumbnail-dest-create}}\n* {{msg-mw|Thumbnail invalid params}}", "thumbnail_image-type": "This is the parameter 1 of the message {{msg-mw|thumbnail error}}", "thumbnail_gd-library": "This is the parameter 1 of the message {{msg-mw|thumbnail error}}.\n*$1 is a function name of the GD library", @@ -3303,6 +3304,15 @@ "size-exabytes": "{{optional}}\nSize (of a file, typically) in exbibytes (1 exbibytes = 1024×1024×1024×1024×1024×1024 bytes).", "size-zetabytes": "{{optional}}\nSize (of a file, typically) in zebibytes (1 zebibytes = 1024×1024×1024×1024×1024×1024×1024 bytes).", "size-yottabytes": "{{optional}}\nSize (of a file, typically) in yobibytes (1 yobibytes = 1024×1024×1024×1024×1024×1024×1024×1024 bytes).", + "size-pixel": "{{optional}}\nSize (of a file, typically) in pixel.", + "size-kilopixel": "{{optional}}\nSize (of a file, typically) in kilopixel (1 kilopixel = 1000 pixel).", + "size-megapixel": "{{optional}}\nSize (of a file, typically) in megapixel (1 megapixel = 1000×1000 pixel).", + "size-gigapixel": "{{optional}}\nSize (of a file, typically) in gigapixel (1 gigapixel = 1000×1000×1000 pixel).", + "size-terapixel": "{{optional}}\nSize (of a file, typically) in terapixel (1 terapixel = 1000×1000×1000×1000 pixel).", + "size-petapixel": "{{optional}}\nSize (of a file, typically) in petapixel (1 petapixel = 1000×1000×1000×1000×1000 pixel).", + "size-exapixel": "{{optional}}\nSize (of a file, typically) in exapixel (1 exapixel = 1000×1000×1000×1000×1000×1000 pixel).", + "size-zetapixel": "{{optional}}\nSize (of a file, typically) in zetapixel (1 zetapixel = 1000×1000×1000×1000×1000×1000×1000 pixel).", + "size-yottapixel": "{{optional}}\nSize (of a file, typically) in yottapixel (1 yottapixel = 1000×1000×1000×1000×1000×1000×1000×1000 pixel).", "bitrate-bits": "{{optional}}\nBitrate (of a file, typically) in bits.", "bitrate-kilobits": "{{optional}}\nBitrate (of a file, typically) in kilobits (1 kilobit = 1000 bits).", "bitrate-megabits": "{{optional}}\nBitrate (of a file, typically) in megabits (1 megabits = 1000×1000 bits).", diff --git a/tests/phpunit/includes/media/BitmapScalingTest.php b/tests/phpunit/includes/media/BitmapScalingTest.php index 1972c96943..e4415ece3b 100644 --- a/tests/phpunit/includes/media/BitmapScalingTest.php +++ b/tests/phpunit/includes/media/BitmapScalingTest.php @@ -113,7 +113,7 @@ class BitmapScalingTest extends MediaWikiTestCase { $file = new FakeDimensionFile( array( 4000, 4000 ) ); $handler = new BitmapHandler; $params = array( 'width' => '3700' ); // Still bigger than max size. - $this->assertEquals( 'TransformParameterError', + $this->assertEquals( 'TransformTooBigImageAreaError', get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); } @@ -125,7 +125,7 @@ class BitmapScalingTest extends MediaWikiTestCase { $file->mustRender = true; $handler = new BitmapHandler; $params = array( 'width' => '5000' ); // Still bigger than max size. - $this->assertEquals( 'TransformParameterError', + $this->assertEquals( 'TransformTooBigImageAreaError', get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); } -- 2.20.1