Merge branch '5.3'
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 2 Feb 2021 10:33:23 +0000 (11:33 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 2 Feb 2021 10:33:23 +0000 (11:33 +0100)
1  2 
com.woltlab.wcf/package.xml
wcfsetup/install/files/lib/data/user/avatar/UserAvatarAction.class.php

index 8ca2bdf808d846ba26dca8c1238ac915ac2247aa,83b3f025cd64a079a8eb36ae19670e3b87c11d6c..42302364010dc2262fc60b38dc0bd8223de9e95c
@@@ -5,8 -5,8 +5,8 @@@
                <packagedescription>Free CMS and web-framework, designed for awesome websites and communities.</packagedescription>
                <packagedescription language="de">Freies CMS und Web-Framework, das eindrucksvolle Websites und Communities ermöglicht.</packagedescription>
                <isapplication>1</isapplication>
 -              <version>5.3.4</version>
 +              <version>5.4.0 Alpha 1</version>
-               <date>2021-01-29</date>
+               <date>2021-02-01</date>
        </packageinformation>
        
        <authorinformation>
index b5af4583280cef9350b7a1719369d8b57933c2b2,9097c1a9c3e87e04e67fe7d6fe0b1f59dfad1aa1..6cc6b8f13410c79a2606be5601a56fbb1a00447c
@@@ -21,234 -19,221 +21,234 @@@ use wcf\util\Url
  
  /**
   * Executes avatar-related actions.
 - * 
 - * @author    Marcel Werk
 - * @copyright 2001-2019 WoltLab GmbH
 - * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 - * @package   WoltLabSuite\Core\Data\User\Avatar
 - * 
 - * @method    UserAvatar              create()
 - * @method    UserAvatarEditor[]      getObjects()
 - * @method    UserAvatarEditor        getSingleObject()
 + *
 + * @author  Marcel Werk
 + * @copyright   2001-2019 WoltLab GmbH
 + * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 + * @package WoltLabSuite\Core\Data\User\Avatar
 + *
 + * @method  UserAvatar      create()
 + * @method  UserAvatarEditor[]  getObjects()
 + * @method  UserAvatarEditor    getSingleObject()
   */
 -class UserAvatarAction extends AbstractDatabaseObjectAction {
 -      /**
 -       * currently edited avatar
 -       * @var UserAvatarEditor
 -       */
 -      public $avatar = null;
 -      
 -      /**
 -       * Validates the upload action.
 -       */
 -      public function validateUpload() {
 -              $this->readInteger('userID', true);
 -              
 -              if ($this->parameters['userID']) {
 -                      if (!WCF::getSession()->getPermission('admin.user.canEditUser')) {
 -                              throw new PermissionDeniedException();
 -                      }
 -                      
 -                      $user = new User($this->parameters['userID']);
 -                      if (!$user->userID) {
 -                              throw new IllegalLinkException();
 -                      }
 -              }
 -              
 -              // check upload permissions
 -              if (!WCF::getSession()->getPermission('user.profile.avatar.canUploadAvatar') || WCF::getUser()->disableAvatar) {
 -                      throw new PermissionDeniedException();
 -              }
 -              
 -              /** @noinspection PhpUndefinedMethodInspection */
 -              if (count($this->parameters['__files']->getFiles()) != 1) {
 -                      throw new UserInputException('files');
 -              }
 -              
 -              // check max filesize, allowed file extensions etc.
 -              /** @noinspection PhpUndefinedMethodInspection */
 -              $this->parameters['__files']->validateFiles(new AvatarUploadFileValidationStrategy(PHP_INT_MAX, explode("\n", WCF::getSession()->getPermission('user.profile.avatar.allowedFileExtensions'))));
 -      }
 -      
 -      /**
 -       * Handles uploaded attachments.
 -       */
 -      public function upload() {
 -              /** @var UploadFile $file */
 -              $file = $this->parameters['__files']->getFiles()[0];
 -              $saveStrategy = new AvatarUploadFileSaveStrategy((!empty($this->parameters['userID']) ? intval($this->parameters['userID']) : WCF::getUser()->userID));
 -              /** @noinspection PhpUndefinedMethodInspection */
 -              $this->parameters['__files']->saveFiles($saveStrategy);
 -              
 -              if ($file->getValidationErrorType()) {
 -                      return ['errorType' => $file->getValidationErrorType()];
 -              }
 -              else {
 -                      return [
 -                              'avatarID' => $saveStrategy->getAvatar()->avatarID,
 -                              'url' => $saveStrategy->getAvatar()->getURL(96)
 -                      ];
 -              }
 -      }
 -      
 -      /**
 -       * Fetches an avatar from a remote server and sets it for given user.
 -       */
 -      public function fetchRemoteAvatar() {
 -              $avatarID = 0;
 -              $filename = '';
 -              
 -              // fetch avatar from URL
 -              $imageData = null;
 -              try {
 -                      $request = new HTTPRequest($this->parameters['url']);
 -                      $request->execute();
 -                      $reply = $request->getReply();
 -                      $filename = FileUtil::getTemporaryFilename('avatar_');
 -                      file_put_contents($filename, $reply['body']);
 -                      
 -                      $imageData = getimagesize($filename);
 -                      if ($imageData === false) throw new SystemException('Downloaded file is not an image');
 -              }
 -              catch (\Exception $e) {
 -                      // log exception unless this was caused by a non-image file being supplied
 -                      if ($imageData !== false) {
 -                              \wcf\functions\exception\logThrowable($e);
 -                      }
 -                      
 -                      if (!empty($filename)) {
 -                              @unlink($filename);
 -                      }
 -                      return;
 -              }
 -              
 -              // rescale avatar if required
 -              try {
 -                      $newFilename = $this->enforceDimensions($filename);
 -                      if ($newFilename !== $filename) @unlink($filename);
 -                      $filename = $newFilename;
 -                      
 -                      $imageData = getimagesize($filename);
 -                      if ($imageData === false) throw new SystemException('Rescaled file is not an image');
 -              }
 -              catch (\Exception $e) {
 -                      @unlink($filename);
 -                      return;
 -              }
 -              
 -              $tmp = Url::parse($this->parameters['url']);
 -              if (!isset($tmp['path'])) {
 -                      @unlink($filename);
 -                      return;
 -              }
 -              
 -              $tmp = pathinfo($tmp['path']);
 -              if (!isset($tmp['basename'])) {
 -                      $tmp['basename'] = basename($filename);
 -              }
 -              
 -              $imageData = @getimagesize($filename);
 -              if ($imageData !== false) {
 -                      $tmp['extension'] = ImageUtil::getExtensionByMimeType($imageData['mime']);
 -                      
 -                      if (!in_array($tmp['extension'], ['jpeg', 'jpg', 'png', 'gif'])) {
 -                              @unlink($filename);
 -                              return;
 -                      }
 -              }
 -              else {
 -                      @unlink($filename);
 -                      return;
 -              }
 -              
 -              $data = [
 -                      'avatarName' => mb_substr($tmp['basename'], 0, 255),
 -                      'avatarExtension' => $tmp['extension'],
 -                      'width' => $imageData[0],
 -                      'height' => $imageData[1],
 -                      'userID' => $this->parameters['userEditor']->userID,
 -                      'fileHash' => sha1_file($filename)
 -              ];
 -              
 -              // create avatar
 -              $avatar = UserAvatarEditor::create($data);
 -              
 -              // check avatar directory
 -              // and create subdirectory if necessary
 -              $dir = dirname($avatar->getLocation());
 -              if (!@file_exists($dir)) {
 -                      FileUtil::makePath($dir);
 -              }
 -              
 -              // move uploaded file
 -              if (@copy($filename, $avatar->getLocation())) {
 -                      @unlink($filename);
 -                      
 -                      $avatarID = $avatar->avatarID;
 -              }
 -              else {
 -                      @unlink($filename);
 -                      
 -                      // moving failed; delete avatar
 -                      $editor = new UserAvatarEditor($avatar);
 -                      $editor->delete();
 -              }
 -              
 -              // update user
 -              if ($avatarID) {
 -                      /** @var UserEditor $userEditor */
 -                      $userEditor = $this->parameters['userEditor'];
 -                      
 -                      $userEditor->update([
 -                              'avatarID' => $avatarID,
 -                              'enableGravatar' => 0
 -                      ]);
 -                      
 -                      // delete old avatar
 -                      if ($userEditor->avatarID) {
 -                              $action = new UserAvatarAction([$userEditor->avatarID], 'delete');
 -                              $action->executeAction();
 -                      }
 -              }
 -              
 -              // reset user storage
 -              UserStorageHandler::getInstance()->reset([$this->parameters['userEditor']->userID], 'avatar');
 -      }
 -      
 -      /**
 -       * Enforces dimensions for given avatar.
 -       * 
 -       * @param       string          $filename
 -       * @return      string
 -       * @throws      UserInputException
 -       */
 -      protected function enforceDimensions($filename) {
 -              try {
 -                      $filename = ImageUtil::enforceDimensions($filename, UserAvatar::AVATAR_SIZE, UserAvatar::AVATAR_SIZE);
 -              }
 -                      /** @noinspection PhpRedundantCatchClauseInspection */
 -              catch (SystemException $e) {
 -                      throw new UserInputException('avatar', 'tooLarge');
 -              }
 -              
 -              // check filesize (after shrink)
 -              if (@filesize($filename) > WCF::getSession()->getPermission('user.profile.avatar.maxSize')) {
 -                      throw new UserInputException('avatar', 'tooLarge');
 -              }
 -              
 -              return $filename;
 -      }
 +class UserAvatarAction extends AbstractDatabaseObjectAction
 +{
 +    /**
 +     * currently edited avatar
 +     * @var UserAvatarEditor
 +     */
 +    public $avatar;
 +
 +    /**
 +     * Validates the upload action.
 +     */
 +    public function validateUpload()
 +    {
 +        $this->readInteger('userID', true);
 +
 +        if ($this->parameters['userID']) {
 +            if (!WCF::getSession()->getPermission('admin.user.canEditUser')) {
 +                throw new PermissionDeniedException();
 +            }
 +
 +            $user = new User($this->parameters['userID']);
 +            if (!$user->userID) {
 +                throw new IllegalLinkException();
 +            }
 +        }
 +
 +        // check upload permissions
 +        if (!WCF::getSession()->getPermission('user.profile.avatar.canUploadAvatar') || WCF::getUser()->disableAvatar) {
 +            throw new PermissionDeniedException();
 +        }
 +
 +        /** @noinspection PhpUndefinedMethodInspection */
 +        if (\count($this->parameters['__files']->getFiles()) != 1) {
 +            throw new UserInputException('files');
 +        }
 +
 +        // check max filesize, allowed file extensions etc.
 +        /** @noinspection PhpUndefinedMethodInspection */
 +        $this->parameters['__files']->validateFiles(new AvatarUploadFileValidationStrategy(
 +            \PHP_INT_MAX,
 +            \explode("\n", WCF::getSession()->getPermission('user.profile.avatar.allowedFileExtensions'))
 +        ));
 +    }
 +
 +    /**
 +     * Handles uploaded attachments.
 +     */
 +    public function upload()
 +    {
 +        /** @var UploadFile $file */
 +        $file = $this->parameters['__files']->getFiles()[0];
 +        $saveStrategy = new AvatarUploadFileSaveStrategy((!empty($this->parameters['userID']) ? \intval($this->parameters['userID']) : WCF::getUser()->userID));
 +        /** @noinspection PhpUndefinedMethodInspection */
 +        $this->parameters['__files']->saveFiles($saveStrategy);
 +
 +        if ($file->getValidationErrorType()) {
 +            return ['errorType' => $file->getValidationErrorType()];
 +        } else {
 +            return [
 +                'avatarID' => $saveStrategy->getAvatar()->avatarID,
 +                'url' => $saveStrategy->getAvatar()->getURL(96),
 +            ];
 +        }
 +    }
 +
 +    /**
 +     * Fetches an avatar from a remote server and sets it for given user.
 +     */
 +    public function fetchRemoteAvatar()
 +    {
 +        $avatarID = 0;
 +        $filename = '';
 +
 +        // fetch avatar from URL
 +        $imageData = null;
 +        try {
 +            $request = new HTTPRequest($this->parameters['url']);
 +            $request->execute();
 +            $reply = $request->getReply();
 +            $filename = FileUtil::getTemporaryFilename('avatar_');
 +            \file_put_contents($filename, $reply['body']);
 +
 +            $imageData = \getimagesize($filename);
 +            if ($imageData === false) {
 +                throw new SystemException('Downloaded file is not an image');
 +            }
 +        } catch (\Exception $e) {
 +            // log exception unless this was caused by a non-image file being supplied
 +            if ($imageData !== false) {
 +                \wcf\functions\exception\logThrowable($e);
 +            }
 +
 +            if (!empty($filename)) {
 +                @\unlink($filename);
 +            }
 +
 +            return;
 +        }
 +
 +        // rescale avatar if required
 +        try {
 +            $newFilename = $this->enforceDimensions($filename);
 +            if ($newFilename !== $filename) {
 +                @\unlink($filename);
 +            }
 +            $filename = $newFilename;
 +
 +            $imageData = \getimagesize($filename);
 +            if ($imageData === false) {
 +                throw new SystemException('Rescaled file is not an image');
 +            }
 +        } catch (\Exception $e) {
 +            @\unlink($filename);
 +
 +            return;
 +        }
 +
 +        $tmp = Url::parse($this->parameters['url']);
 +        if (!isset($tmp['path'])) {
 +            @\unlink($filename);
 +
 +            return;
 +        }
 +
 +        $tmp = \pathinfo($tmp['path']);
 +        if (!isset($tmp['basename'])) {
 +            $tmp['basename'] = \basename($filename);
 +        }
 +
 +        $imageData = @\getimagesize($filename);
 +        if ($imageData !== false) {
 +            $tmp['extension'] = ImageUtil::getExtensionByMimeType($imageData['mime']);
 +
 +            if (!\in_array($tmp['extension'], ['jpeg', 'jpg', 'png', 'gif', 'webp'])) {
 +                @\unlink($filename);
 +
 +                return;
 +            }
 +        } else {
 +            @\unlink($filename);
 +
 +            return;
 +        }
 +
 +        $data = [
-             'avatarName' => $tmp['basename'],
++            'avatarName' => mb_substr($tmp['basename'], 0, 255),
 +            'avatarExtension' => $tmp['extension'],
 +            'width' => $imageData[0],
 +            'height' => $imageData[1],
 +            'userID' => $this->parameters['userEditor']->userID,
 +            'fileHash' => \sha1_file($filename),
 +        ];
 +
 +        // create avatar
 +        $avatar = UserAvatarEditor::create($data);
 +
 +        // check avatar directory
 +        // and create subdirectory if necessary
 +        $dir = \dirname($avatar->getLocation());
 +        if (!@\file_exists($dir)) {
 +            FileUtil::makePath($dir);
 +        }
 +
 +        // move uploaded file
 +        if (@\copy($filename, $avatar->getLocation())) {
 +            @\unlink($filename);
 +
 +            $avatarID = $avatar->avatarID;
 +        } else {
 +            @\unlink($filename);
 +
 +            // moving failed; delete avatar
 +            $editor = new UserAvatarEditor($avatar);
 +            $editor->delete();
 +        }
 +
 +        // update user
 +        if ($avatarID) {
 +            /** @var UserEditor $userEditor */
 +            $userEditor = $this->parameters['userEditor'];
 +
 +            $userEditor->update([
 +                'avatarID' => $avatarID,
 +                'enableGravatar' => 0,
 +            ]);
 +
 +            // delete old avatar
 +            if ($userEditor->avatarID) {
 +                $action = new self([$userEditor->avatarID], 'delete');
 +                $action->executeAction();
 +            }
 +        }
 +
 +        // reset user storage
 +        UserStorageHandler::getInstance()->reset([$this->parameters['userEditor']->userID], 'avatar');
 +    }
 +
 +    /**
 +     * Enforces dimensions for given avatar.
 +     *
 +     * @param string $filename
 +     * @return  string
 +     * @throws  UserInputException
 +     */
 +    protected function enforceDimensions($filename)
 +    {
 +        try {
 +            $filename = ImageUtil::enforceDimensions($filename, UserAvatar::AVATAR_SIZE, UserAvatar::AVATAR_SIZE);
 +        } /** @noinspection PhpRedundantCatchClauseInspection */
 +        catch (SystemException $e) {
 +            throw new UserInputException('avatar', 'tooLarge');
 +        }
 +
 +        // check filesize (after shrink)
 +        if (@\filesize($filename) > WCF::getSession()->getPermission('user.profile.avatar.maxSize')) {
 +            throw new UserInputException('avatar', 'tooLarge');
 +        }
 +
 +        return $filename;
 +    }
  }