Use modern UploadHandler to upload style preview images
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 21 Jul 2020 09:23:04 +0000 (11:23 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 21 Jul 2020 13:34:39 +0000 (15:34 +0200)
wcfsetup/install/files/acp/templates/styleAdd.tpl
wcfsetup/install/files/lib/acp/form/StyleAddForm.class.php
wcfsetup/install/files/lib/acp/form/StyleEditForm.class.php
wcfsetup/install/files/lib/data/style/StyleAction.class.php
wcfsetup/install/files/lib/data/style/StyleEditor.class.php

index d848ffb46261ad29d93d50b09c58dd49d649257b..088cca0183a6ff8b2aee644661a8691f82c7b16b 100644 (file)
@@ -18,9 +18,6 @@
                        styleRuleMap: styleRuleMap
                });
                
-               new AcpUiStyleImageUpload({if $action == 'add'}0{else}{@$style->styleID}{/if}, '{$tmpHash}', false);
-               new AcpUiStyleImageUpload({if $action == 'add'}0{else}{@$style->styleID}{/if}, '{$tmpHash}', true);
-               
                new UiToggleInput('input[name="useGoogleFont"]', {
                        show: ['#wcfFontFamilyGoogleContainer']
                });
                                <dl{if $errorField == 'image'} class="formError"{/if}>
                                        <dt><label for="image">{lang}wcf.acp.style.image{/lang}</label></dt>
                                        <dd>
-                                               <div class="selectedImagePreview">
-                                                       <img src="{if $action == 'add'}{@$__wcf->getPath()}images/stylePreview.png{else}{@$style->getPreviewImage()}{/if}" alt="" id="styleImage">
-                                               </div>
-                                               <div id="uploadImage"></div>
+                                               {@$__wcf->getUploadHandler()->renderField('image')}
                                                <small>{lang}wcf.acp.style.image.description{/lang}</small>
                                        </dd>
                                </dl>
-                               <dl{if $errorField == 'image'} class="formError"{/if}>
+                               <dl{if $errorField == 'image2x'} class="formError"{/if}>
                                        <dt><label for="image2x">{lang}wcf.acp.style.image2x{/lang}</label></dt>
                                        <dd>
-                                               <div class="selectedImagePreview">
-                                                       <img src="{if $action == 'add'}{@$__wcf->getPath()}images/stylePreview@2x.png{else}{@$style->getPreviewImage2x()}{/if}" alt="" id="styleImage2x">
-                                               </div>
-                                               <div id="uploadImage2x"></div>
+                                               {@$__wcf->getUploadHandler()->renderField('image2x')}
                                                <small>{lang}wcf.acp.style.image2x.description{/lang}</small>
                                        </dd>
                                </dl>
index b26656fb43d772019370b615e8cb96b262cf0330..424489e5e25758d8a4180fa2d105471e295f545b 100644 (file)
@@ -9,12 +9,14 @@ use wcf\form\AbstractForm;
 use wcf\system\event\EventHandler;
 use wcf\system\exception\SystemException;
 use wcf\system\exception\UserInputException;
+use wcf\system\file\upload\UploadField;
+use wcf\system\file\upload\UploadHandler;
+use wcf\system\image\ImageHandler;
 use wcf\system\language\I18nHandler;
 use wcf\system\Regex;
 use wcf\system\WCF;
 use wcf\util\ArrayUtil;
 use wcf\util\DateUtil;
-use wcf\util\FileUtil;
 use wcf\util\StringUtil;
 
 /**
@@ -206,6 +208,11 @@ class StyleAddForm extends AbstractForm {
         */
        public $scrollOffsets = [];
        
+       /**
+        * @var mixed[]
+        */
+       public $uploads = [];
+       
        /**
         * @inheritDoc
         */
@@ -227,6 +234,28 @@ class StyleAddForm extends AbstractForm {
                if (empty($this->tmpHash)) {
                        $this->tmpHash = StringUtil::getRandomID();
                }
+               
+               $this->rebuildUploadFields();
+       }
+       
+       protected function rebuildUploadFields() {
+               $handler = UploadHandler::getInstance();
+               
+               if ($handler->isRegisteredFieldId('image')) {
+                       $handler->unregisterUploadField('image');
+               }
+               $field = new UploadField('image');
+               $field->setImageOnly(true);
+               $field->maxFiles = 1;
+               $handler->registerUploadField($field);
+               
+               if ($handler->isRegisteredFieldId('image2x')) {
+                       $handler->unregisterUploadField('image2x');
+               }
+               $field = new UploadField('image2x');
+               $field->setImageOnly(true);
+               $field->maxFiles = 1;
+               $handler->registerUploadField($field);
        }
        
        /**
@@ -291,6 +320,18 @@ class StyleAddForm extends AbstractForm {
                
                // codemirror scroll offset
                if (isset($_POST['scrollOffsets']) && is_array($_POST['scrollOffsets'])) $this->scrollOffsets = ArrayUtil::toIntegerArray($_POST['scrollOffsets']); 
+               
+               $this->uploads = [];
+               foreach (['image', 'image2x'] as $field) {
+                       $files = UploadHandler::getInstance()->getFilesByFieldId($field);
+                       if (!empty($files)) {
+                               $this->uploads[$field] = $files[0];
+                       }
+                       $removedFiles = UploadHandler::getInstance()->getRemovedFiledByFieldId($field);
+                       if (!empty($removedFiles)) {
+                               $this->uploads[$field] = null;
+                       }
+               }
        }
        
        /**
@@ -357,6 +398,8 @@ class StyleAddForm extends AbstractForm {
                }
                
                $this->validateApiVersion();
+               
+               $this->validateUploads();
        }
        
        /**
@@ -383,6 +426,66 @@ class StyleAddForm extends AbstractForm {
                }
        }
        
+       protected function validateUploads() {
+               // Preview image.
+               $field = 'image';
+               $files = UploadHandler::getInstance()->getFilesByFieldId($field);
+               if (count($files) > 1) {
+                       throw new UserInputException($field, 'invalid');
+               }
+               if (!empty($files)) {
+                       $fileLocation = $files[0]->getLocation();
+                       if (($imageData = getimagesize($fileLocation)) === false) {
+                               throw new UserInputException($field, 'invalid');
+                       }
+                       switch ($imageData[2]) {
+                               case IMAGETYPE_PNG:
+                               case IMAGETYPE_JPEG:
+                               case IMAGETYPE_GIF:
+                                       // fine
+                               break;
+                               default:
+                                       throw new UserInputException($field, 'invalid');
+                       }
+                       
+                       if ($imageData[0] > (Style::PREVIEW_IMAGE_MAX_WIDTH) || $imageData[1] > (Style::PREVIEW_IMAGE_MAX_HEIGHT)) {
+                               $adapter = ImageHandler::getInstance()->getAdapter();
+                               $adapter->loadFile($fileLocation);
+                               $thumbnail = $adapter->createThumbnail(Style::PREVIEW_IMAGE_MAX_WIDTH, Style::PREVIEW_IMAGE_MAX_HEIGHT, false);
+                               $adapter->writeImage($thumbnail, $fileLocation);
+                       }
+               }
+               
+               // Preview image (2x).
+               $field = 'image2x';
+               $files = UploadHandler::getInstance()->getFilesByFieldId($field);
+               if (count($files) > 1) {
+                       throw new UserInputException($field, 'invalid');
+               }
+               if (!empty($files)) {
+                       $fileLocation = $files[0]->getLocation();
+                       if (($imageData = getimagesize($fileLocation)) === false) {
+                               throw new UserInputException($field, 'invalid');
+                       }
+                       switch ($imageData[2]) {
+                               case IMAGETYPE_PNG:
+                               case IMAGETYPE_JPEG:
+                               case IMAGETYPE_GIF:
+                                       // fine
+                               break;
+                               default:
+                                       throw new UserInputException($field, 'invalid');
+                       }
+                       
+                       if ($imageData[0] > (Style::PREVIEW_IMAGE_MAX_WIDTH * 2) || $imageData[1] > (Style::PREVIEW_IMAGE_MAX_HEIGHT * 2)) {
+                               $adapter = ImageHandler::getInstance()->getAdapter();
+                               $adapter->loadFile($fileLocation);
+                               $thumbnail = $adapter->createThumbnail(Style::PREVIEW_IMAGE_MAX_WIDTH * 2, Style::PREVIEW_IMAGE_MAX_HEIGHT * 2, false);
+                               $adapter->writeImage($thumbnail, $fileLocation);
+                       }
+               }
+       }
+       
        /**
         * Validates LESS-variable overrides.
         * 
@@ -597,6 +700,7 @@ class StyleAddForm extends AbstractForm {
                                'authorURL' => $this->authorURL,
                                'apiVersion' => $this->apiVersion
                        ]),
+                       'uploads' => $this->uploads,
                        'tmpHash' => $this->tmpHash,
                        'variables' => $this->variables
                ]);
@@ -621,6 +725,7 @@ class StyleAddForm extends AbstractForm {
                $this->imagePath = 'images/';
                $this->isTainted = true;
                $this->templateGroupID = 0;
+               $this->rebuildUploadFields();
                
                I18nHandler::getInstance()->reset();
                
index ddbf303cbb905c0e4a339ea71aa8c3c95eaa51cb..f3da9407c348289f2a29a801dac06a73669e9346 100644 (file)
@@ -5,6 +5,8 @@ use wcf\data\style\StyleAction;
 use wcf\data\user\cover\photo\UserCoverPhoto;
 use wcf\form\AbstractForm;
 use wcf\system\exception\IllegalLinkException;
+use wcf\system\file\upload\UploadFile;
+use wcf\system\file\upload\UploadHandler;
 use wcf\system\language\I18nHandler;
 use wcf\system\WCF;
 
@@ -138,6 +140,18 @@ class StyleEditForm extends StyleAddForm {
                        $this->styleName = $this->style->styleName;
                        $this->styleVersion = $this->style->styleVersion;
                        $this->templateGroupID = $this->style->templateGroupID;
+                       if ($this->style->image) {
+                               $file = new UploadFile(WCF_DIR.'images/'.$this->style->image, $this->style->image, true, true, true);
+                               UploadHandler::getInstance()->registerFilesByField('image', [
+                                       $file,
+                               ]);
+                       }
+                       if ($this->style->image2x) {
+                               $file = new UploadFile(WCF_DIR.'images/'.$this->style->image2x, $this->style->image2x, true, true, true);
+                               UploadHandler::getInstance()->registerFilesByField('image2x', [
+                                       $file,
+                               ]);
+                       }
                }
        }
        
@@ -172,6 +186,7 @@ class StyleEditForm extends StyleAddForm {
                                'authorURL' => $this->authorURL,
                                'apiVersion' => $this->apiVersion
                        ]),
+                       'uploads' => $this->uploads,
                        'tmpHash' => $this->tmpHash,
                        'variables' => $this->variables
                ]);
index d917e662b6bcc3f8c5ce3d85582053979df71bf2..7dee8e47b0eab3ea989e73cdbb3b56977862936c 100644 (file)
@@ -11,16 +11,17 @@ use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\SystemException;
 use wcf\system\exception\UserInputException;
+use wcf\system\file\upload\UploadHandler;
 use wcf\system\image\ImageHandler;
 use wcf\system\language\LanguageFactory;
 use wcf\system\request\LinkHandler;
 use wcf\system\style\StyleHandler;
 use wcf\system\upload\DefaultUploadFileValidationStrategy;
 use wcf\system\upload\UploadFile;
-use wcf\system\upload\UploadHandler;
 use wcf\system\Regex;
 use wcf\system\WCF;
 use wcf\util\FileUtil;
+use wcf\util\ImageUtil;
 
 /**
  * Executes style-related actions.
@@ -224,51 +225,43 @@ class StyleAction extends AbstractDatabaseObjectAction implements IToggleAction,
         * @param       Style           $style
         */
        protected function updateStylePreviewImage(Style $style) {
-               if (!isset($this->parameters['tmpHash'])) {
-                       return;
-               }
-               
-               foreach (['', '@2x'] as $type) {
-                       $fileExtension = WCF::getSession()->getVar('stylePreview-' . $this->parameters['tmpHash'] . $type);
-                       if ($fileExtension !== null) {
-                               $oldFilename = WCF_DIR . 'images/stylePreview-' . $this->parameters['tmpHash'] . $type . '.' . $fileExtension;
-                               if (file_exists($oldFilename)) {
-                                       $filename = 'stylePreview-' . $style->styleID . $type . '.' . $fileExtension;
-                                       if (@rename($oldFilename, WCF_DIR . 'images/' . $filename)) {
-                                               // delete old file if it has a different file extension
-                                               if ($type === '') {
-                                                       if ($style->image != $filename) {
-                                                               @unlink(WCF_DIR . 'images/' . $style->image);
-                                                               
-                                                               // update filename in database
-                                                               $sql = "UPDATE  wcf" . WCF_N . "_style
-                                                                       SET     image = ?
-                                                                       WHERE   styleID = ?";
-                                                               $statement = WCF::getDB()->prepareStatement($sql);
-                                                               $statement->execute([
-                                                                       $filename, $style->styleID
-                                                               ]);
-                                                       }
-                                               }
-                                               else {
-                                                       if ($style->image2x != $filename) {
-                                                               @unlink(WCF_DIR . 'images/' . $style->image2x);
-                                                               
-                                                               // update filename in database
-                                                               $sql = "UPDATE  wcf" . WCF_N . "_style
-                                                                       SET     image2x = ?
-                                                                       WHERE   styleID = ?";
-                                                               $statement = WCF::getDB()->prepareStatement($sql);
-                                                               $statement->execute([
-                                                                       $filename, $style->styleID
-                                                               ]);
-                                                       }
-                                               }
+               foreach (['image', 'image2x'] as $type) {
+                       if (array_key_exists($type, $this->parameters['uploads'])) {
+                               /** @var \wcf\system\file\upload\UploadFile $file */
+                               $file = $this->parameters['uploads'][$type];
+                               
+                               if ($style->{$type} && file_exists($style->getAssetPath().basename($style->{$type}))) {
+                                       if (!$file || $style->getAssetPath().basename($style->{$type}) !== $file->getLocation()) {
+                                               unlink($style->getAssetPath().basename($style->{$type}));
+                                       }
+                               }
+                               if ($file !== null) {
+                                       $fileLocation = $file->getLocation();
+                                       if (($imageData = getimagesize($fileLocation)) === false) {
+                                               throw new \InvalidArgumentException('The given '.$type.' is not an image');
+                                       }
+                                       $extension = ImageUtil::getExtensionByMimeType($imageData['mime']);
+                                       if ($type === 'image') {
+                                               $newName = 'stylePreview.'.$extension;
+                                       }
+                                       else if ($type === 'image2x') {
+                                               $newName = 'stylePreview@2x.'.$extension;
                                        }
                                        else {
-                                               // remove temp file
-                                               @unlink($oldFilename);
+                                               throw new \LogicException('Unreachable');
                                        }
+                                       $newLocation = $style->getAssetPath().$newName;
+                                       rename($fileLocation, $newLocation);
+                                       (new StyleEditor($style))->update([
+                                               $type => FileUtil::getRelativePath(WCF_DIR.'images/', $style->getAssetPath()).$newName,
+                                       ]);
+                                       
+                                       $file->setProcessed($newLocation);
+                               }
+                               else {
+                                       (new StyleEditor($style))->update([
+                                               $type => '',
+                                       ]);
                                }
                        }
                }
index c86e8bdd70e9335f0c5f7380ee56e2c5b5cc9e24..cc00b240b9e7beb060dfc3a0c008ac8114e7e369 100644 (file)
@@ -73,11 +73,6 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject
                if ($variables !== null) {
                        $this->setVariables($variables);
                }
-               
-               // scale preview image
-               if (!empty($parameters['image']) && $parameters['image'] != $this->image) {
-                       self::scalePreviewImage($parameters['image']);
-               }
        }
        
        /**
@@ -1085,16 +1080,4 @@ class StyleEditor extends DatabaseObjectEditor implements IEditableCachedObject
        public static function resetCache() {
                StyleCacheBuilder::getInstance()->reset();
        }
-       
-       /**
-        * Scales the style preview image.
-        * 
-        * @param       string          $filename
-        */
-       public static function scalePreviewImage($filename) {
-               $adapter = ImageHandler::getInstance()->getAdapter();
-               $adapter->loadFile(WCF_DIR.'images/'.$filename);
-               $thumbnail = $adapter->createThumbnail(Style::PREVIEW_IMAGE_MAX_WIDTH, Style::PREVIEW_IMAGE_MAX_HEIGHT);
-               $adapter->writeImage($thumbnail, WCF_DIR.'images/'.$filename);
-       }
 }