[ImageEncoder] Ensure proper memory limits are used when loading images from disk

This commit is contained in:
Hugo Sales 2021-09-23 14:50:53 +01:00
parent 1c1bef76ef
commit 6a2c3eb711
Signed by untrusted user: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0

View File

@ -100,21 +100,25 @@ class ImageEncoder extends Plugin
public function fileMeta(SplFileInfo &$file, ?string &$mimetype, ?int &$width, ?int &$height): bool public function fileMeta(SplFileInfo &$file, ?string &$mimetype, ?int &$width, ?int &$height): bool
{ {
$original_mimetype = $mimetype; $old_limit = ini_set('memory_limit', Common::config('attachments', 'memory_limit'));
if (GSFile::mimetypeMajor($original_mimetype) !== 'image') {
// Nothing concerning us
return false;
}
try { try {
$image = Vips\Image::newFromFile($file->getRealPath(), ['access' => 'sequential']); $original_mimetype = $mimetype;
} catch (Vips\Exception $e) { if (GSFile::mimetypeMajor($original_mimetype) !== 'image') {
Log::debug("ImageEncoder's Vips couldn't handle the image file, failed with {$e}."); // Nothing concerning us
throw new UnsupportedFileTypeException(_m("Unsupported image file with {$mimetype}.", previous: $e)); return false;
} }
$width = $image->width;
$height = $image->height;
try {
$image = Vips\Image::newFromFile($file->getRealPath(), ['access' => 'sequential']);
} catch (Vips\Exception $e) {
Log::debug("ImageEncoder's Vips couldn't handle the image file, failed with {$e}.");
throw new UnsupportedFileTypeException(_m("Unsupported image file with {$mimetype}.", previous: $e));
}
$width = $image->width;
$height = $image->height;
} finally {
ini_set('memory_limit', $old_limit); // Restore the old memory limit
}
// Only one plugin can handle meta // Only one plugin can handle meta
return true; return true;
} }
@ -138,42 +142,47 @@ class ImageEncoder extends Plugin
*/ */
public function fileSanitize(SplFileInfo &$file, ?string &$mimetype, ?int &$width, ?int &$height): bool public function fileSanitize(SplFileInfo &$file, ?string &$mimetype, ?int &$width, ?int &$height): bool
{ {
$original_mimetype = $mimetype; $old_limit = ini_set('memory_limit', Common::config('attachments', 'memory_limit'));
if (GSFile::mimetypeMajor($original_mimetype) !== 'image') { try {
// Nothing concerning us $original_mimetype = $mimetype;
return false; if (GSFile::mimetypeMajor($original_mimetype) !== 'image') {
} // Nothing concerning us
return false;
}
// Try to maintain original mimetype extension, otherwise default to preferred. // Try to maintain original mimetype extension, otherwise default to preferred.
$extension = '.' . Common::config('thumbnail', 'extension'); $extension = '.' . Common::config('thumbnail', 'extension');
$extension = GSFile::ensureFilenameWithProperExtension( $extension = GSFile::ensureFilenameWithProperExtension(
title: $file->getFilename(), title: $file->getFilename(),
mimetype: $original_mimetype, mimetype: $original_mimetype,
ext: $extension, ext: $extension,
force: false force: false
) ?? $extension; ) ?? $extension;
// TemporaryFile handles deleting the file if some error occurs // TemporaryFile handles deleting the file if some error occurs
// IMPORTANT: We have to specify the extension for the temporary file // IMPORTANT: We have to specify the extension for the temporary file
// in order to have a format conversion // in order to have a format conversion
$temp = new TemporaryFile(['prefix' => 'image', 'suffix' => $extension]); $temp = new TemporaryFile(['prefix' => 'image', 'suffix' => $extension]);
try { try {
$image = Vips\Image::newFromFile($file->getRealPath(), ['access' => 'sequential']); $image = Vips\Image::newFromFile($file->getRealPath(), ['access' => 'sequential']);
} catch (Vips\Exception $e) { } catch (Vips\Exception $e) {
Log::debug("ImageEncoder's Vips couldn't handle the image file, failed with {$e}."); Log::debug("ImageEncoder's Vips couldn't handle the image file, failed with {$e}.");
throw new UnsupportedFileTypeException(_m("Unsupported image file with {$mimetype}.", previous: $e)); throw new UnsupportedFileTypeException(_m("Unsupported image file with {$mimetype}.", previous: $e));
}
$width = $image->width;
$height = $image->height;
$image = $image->crop(left: 0,
top: 0,
width: $width,
height: $height);
$image->writeToFile($temp->getRealPath());
// Replace original file with the sanitized one
$temp->commit($file->getRealPath());
} finally {
ini_set('memory_limit', $old_limit); // Restore the old memory limit
} }
$width = $image->width;
$height = $image->height;
$image = $image->crop(left: 0,
top: 0,
width: $width,
height: $height);
$image->writeToFile($temp->getRealPath());
// Replace original file with the sanitized one
$temp->commit($file->getRealPath());
// Only one plugin can handle sanitization // Only one plugin can handle sanitization
return true; return true;