From 0585b4e1ef539d40e93b61ce369a01f11b42fd3b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joshua=20R=C3=BCsweg?= Date: Mon, 28 Jan 2019 16:31:39 +0100 Subject: [PATCH] Add support for svg images See #2825 --- .../lib/action/AJAXFileUploadAction.class.php | 17 ++++++---- .../system/file/upload/UploadField.class.php | 28 +++++++++++++++++ .../system/file/upload/UploadFile.class.php | 31 ++++++++++++++++--- .../builder/field/UploadFormField.class.php | 29 ++++++++++++++++- 4 files changed, 94 insertions(+), 11 deletions(-) diff --git a/wcfsetup/install/files/lib/action/AJAXFileUploadAction.class.php b/wcfsetup/install/files/lib/action/AJAXFileUploadAction.class.php index 13e472ec52..44f5e7080c 100644 --- a/wcfsetup/install/files/lib/action/AJAXFileUploadAction.class.php +++ b/wcfsetup/install/files/lib/action/AJAXFileUploadAction.class.php @@ -89,11 +89,16 @@ class AJAXFileUploadAction extends AbstractSecureAction { foreach ($_FILES['__files']['tmp_name'] as $id => $tmpName) { if ($field->isImageOnly()) { if (@getimagesize($tmpName) === false) { - $response['error'][$i++] = [ - 'filename' => $_FILES['__files']['name'][$id], - 'errorMessage' => WCF::getLanguage()->get('wcf.upload.error.noImage') - ]; - continue; + if (!($field->svgImagesAllowed() && in_array(FileUtil::getMimeType($tmpName), [ + 'image/svg', + 'image/svg+xml' + ]))) { + $response['error'][$i++] = [ + 'filename' => $_FILES['__files']['name'][$id], + 'errorMessage' => WCF::getLanguage()->get('wcf.upload.error.noImage') + ]; + continue; + } } } @@ -107,7 +112,7 @@ class AJAXFileUploadAction extends AbstractSecureAction { continue; } - $uploadFile = new UploadFile($tmpFile, $_FILES['__files']['name'][$id]); + $uploadFile = new UploadFile($tmpFile, $_FILES['__files']['name'][$id], true, false, $field->svgImagesAllowed()); UploadHandler::getInstance()->addFileByInternalId($this->internalId, $uploadFile); diff --git a/wcfsetup/install/files/lib/system/file/upload/UploadField.class.php b/wcfsetup/install/files/lib/system/file/upload/UploadField.class.php index 1efbe748b3..096b4ae479 100644 --- a/wcfsetup/install/files/lib/system/file/upload/UploadField.class.php +++ b/wcfsetup/install/files/lib/system/file/upload/UploadField.class.php @@ -35,6 +35,16 @@ class UploadField { */ public $imageOnly = false; + /** + * Indicates whether the field supports svg images. + * + * Heads up: svg images can contain code, therefore do not + * use this option, outside the acp or check the file whether remote code is contained. + * + * @var boolean + */ + public $allowSvgImages = false; + /** * UploadField constructor. * @@ -71,6 +81,15 @@ class UploadField { return $this->imageOnly; } + /** + * Returns true, if svg images are allowed. + * + * @return boolean + */ + public function svgImagesAllowed() { + return $this->allowSvgImages; + } + /** * Returns the fieldId. * @@ -106,4 +125,13 @@ class UploadField { public function setImageOnly($imageOnly) { $this->imageOnly = $imageOnly; } + + /** + * Set the image only flag. + * + * @param boolean $allowSvgImages + */ + public function setAllowSvgImages($allowSvgImages) { + $this->allowSvgImages = $allowSvgImages; + } } diff --git a/wcfsetup/install/files/lib/system/file/upload/UploadFile.class.php b/wcfsetup/install/files/lib/system/file/upload/UploadFile.class.php index deba057abd..065f201fc2 100644 --- a/wcfsetup/install/files/lib/system/file/upload/UploadFile.class.php +++ b/wcfsetup/install/files/lib/system/file/upload/UploadFile.class.php @@ -26,6 +26,12 @@ class UploadFile { */ private $imageLink; + /** + * Flag whether svg files should detected as image + * @var bool + */ + private $detectSvgAsImage; + /** * Indicator, whether the file is already processed. * @var boolean @@ -69,8 +75,9 @@ class UploadFile { * @param string $filename * @param boolean $viewableImage * @param boolean $processed + * @param boolean $detectSvgAsImage */ - public function __construct($location, $filename, $viewableImage = true, $processed = false) { + public function __construct($location, $filename, $viewableImage = true, $processed = false, $detectSvgAsImage = false) { if (!file_exists($location)) { throw new \InvalidArgumentException("File '". $location ."' could not be found."); } @@ -81,8 +88,12 @@ class UploadFile { $this->processed = $processed; $this->viewableImage = $viewableImage; $this->uniqueId = StringUtil::getRandomID(); + $this->detectSvgAsImage = $detectSvgAsImage; - if (@getimagesize($location) !== false) { + if (@getimagesize($location) !== false || ($detectSvgAsImage && in_array(FileUtil::getMimeType($location), [ + 'image/svg', + 'image/svg+xml' + ]))) { $this->isImage = true; } } @@ -117,8 +128,20 @@ class UploadFile { } } else { - $imageData = getimagesize($this->location); - return 'data:'. $imageData['mime'] .';base64,'.base64_encode(file_get_contents($this->location)); + $imageData = @getimagesize($this->location); + + if ($imageData !== false) { + return 'data:'. $imageData['mime'] .';base64,'.base64_encode(file_get_contents($this->location)); + } + + if ($this->detectSvgAsImage && in_array(FileUtil::getMimeType($this->location), [ + 'image/svg', + 'image/svg+xml' + ])) { + return 'data:image/svg+xml;base64,'.base64_encode(file_get_contents($this->location)); + } + + throw new \LogicException('File is an image, but can not be rendered.8'); } } diff --git a/wcfsetup/install/files/lib/system/form/builder/field/UploadFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/UploadFormField.class.php index 40d625c58f..0430697c0e 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/UploadFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/UploadFormField.class.php @@ -26,6 +26,12 @@ class UploadFormField extends AbstractFormField { */ protected $imageOnly = false; + /** + * allowSvgImage flag. + * @var boolean + */ + protected $allowSvgImage = false; + /** * @inheritDoc */ @@ -58,7 +64,7 @@ class UploadFormField extends AbstractFormField { $uploadField = new UploadField($this->getId()); $uploadField->maxFiles = $this->getMaximum(); $uploadField->setImageOnly($this->isImageOnly()); - $uploadField->setAllowSvgImages($this->isImageOnly()); + $uploadField->setAllowSvgImages($this->svgImageAllowed()); return $uploadField; } @@ -200,6 +206,18 @@ class UploadFormField extends AbstractFormField { return $this; } + /** + * Sets the imageOnly flag for this field. + * + * @param boolean $allowSvgImages + * @return static this field + */ + public function allowSvgImage($allowSvgImages = true) { + $this->allowSvgImage = $allowSvgImages; + + return $this; + } + /** * Returns true, if the field is an image only field (only images can be uploaded). * @@ -208,4 +226,13 @@ class UploadFormField extends AbstractFormField { public function isImageOnly() { return $this->imageOnly; } + + /** + * Returns true, if the field can contain svg images. + * + * @return boolean + */ + public function svgImageAllowed() { + return $this->allowSvgImage; + } } -- 2.20.1