From: Matthias Schmidt Date: Wed, 1 Jun 2016 15:38:01 +0000 (+0200) Subject: Merge branch 'master' into next X-Git-Tag: 3.0.0_Beta_1~1547^2~1 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=93395679b886f9e4d6df66f2fe125742bc1c9d53;p=GitHub%2FWoltLab%2FWCF.git Merge branch 'master' into next # Conflicts: # com.woltlab.wcf/package.xml # wcfsetup/install/files/lib/acp/page/TemplateListPage.class.php # wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php # wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php --- 93395679b886f9e4d6df66f2fe125742bc1c9d53 diff --cc wcfsetup/install/files/lib/acp/page/TemplateListPage.class.php index 96859cf220,91ec16e714..4166e44f09 --- a/wcfsetup/install/files/lib/acp/page/TemplateListPage.class.php +++ b/wcfsetup/install/files/lib/acp/page/TemplateListPage.class.php @@@ -99,11 -95,13 +99,13 @@@ class TemplateListPage extends Sortable protected function initObjectList() { parent::initObjectList(); - if ($this->templateGroupID) $this->objectList->getConditionBuilder()->add('template.templateGroupID = ?', array($this->templateGroupID)); + if ($this->templateGroupID) $this->objectList->getConditionBuilder()->add('template.templateGroupID = ?', [$this->templateGroupID]); else $this->objectList->getConditionBuilder()->add('template.templateGroupID IS NULL'); - if ($this->searchTemplateName) $this->objectList->getConditionBuilder()->add('templateName LIKE ?', array('%'.$this->searchTemplateName.'%')); - if ($this->application) $this->objectList->getConditionBuilder()->add('application = ?', array($this->application)); + if ($this->searchTemplateName) $this->objectList->getConditionBuilder()->add('templateName LIKE ?', ['%'.$this->searchTemplateName.'%']); + if ($this->application) $this->objectList->getConditionBuilder()->add('application = ?', [$this->application]); + - $this->objectList->getConditionBuilder()->add('templateName <> ?', array('.htac')); ++ $this->objectList->getConditionBuilder()->add('templateName <> ?', ['.htac']); } /** diff --cc wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php index 89397bc690,edc253aff8..8f3db626be --- a/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php +++ b/wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php @@@ -50,8 -50,16 +50,16 @@@ class GDImageAdapter implements IImageA */ protected $width = 0; + /** + * GDImageAdapter constructor. + */ + public function __construct() { + // suppress warnings like "recoverable error: Invalid SOS parameters for sequential JPEG" + @ini_set('gd.jpeg_ignore_warning', 1); + } + /** - * @see \wcf\system\image\adapter\IImageAdapter::load() + * @inheritDoc */ public function load($image, $type = '') { if (!is_resource($image)) { @@@ -81,7 -89,11 +89,11 @@@ break; case IMAGETYPE_JPEG: - $this->image = imagecreatefromjpeg($file); + // suppress warnings and properly handle errors - $this->image = @imageCreateFromJpeg($file); ++ $this->image = @imagecreatefromjpeg($file); + if ($this->image === false) { + throw new SystemException("Could not read jpeg image '".$file."'."); + } break; case IMAGETYPE_PNG: diff --cc wcfsetup/install/files/lib/system/upload/DefaultUploadFileSaveStrategy.class.php index b1ba5fce89,0000000000..c21d350ee6 mode 100644,000000..100644 --- a/wcfsetup/install/files/lib/system/upload/DefaultUploadFileSaveStrategy.class.php +++ b/wcfsetup/install/files/lib/system/upload/DefaultUploadFileSaveStrategy.class.php @@@ -1,257 -1,0 +1,267 @@@ + + * @package com.woltlab.wcf + * @subpackage system.upload + * @category Community Framework + * @since 2.2 + */ +class DefaultUploadFileSaveStrategy implements IUploadFileSaveStrategy { + /** + * name of the database object action class name + * @var string + */ + public $actionClassName = ''; + + /** + * name of the database object editor class name + * @var string + */ + public $editorClassName = ''; + + /** + * additional data stored with the default file data + * @var array + */ + public $data = []; + + /** + * created objects + * @var IFile[] + */ + public $objects = []; + + /** + * options handing saving details + * + * - bool rotateImages: if true, images are automatically rotated + * - bool generateThumbnails: if true, thumbnails are automatically generated after saving file + * + * @var array + */ + public $options = []; + + /** + * Creates a new instance of DefaultUploadFileSaveStrategy. + * + * @param string $actionClassName + * @param array $options + * @param array $data + * @throws SystemException + */ + public function __construct($actionClassName, array $options = [], array $data = []) { + $this->actionClassName = $actionClassName; + $this->options = $options; + $this->data = $data; + + if (!is_subclass_of($this->actionClassName, AbstractDatabaseObjectAction::class)) { + throw new ParentClassException($this->actionClassName, AbstractDatabaseObjectAction::class); + } + + /** @noinspection PhpUndefinedMethodInspection */ + $this->editorClassName = (new $this->actionClassName([], ''))->getClassName(); + $baseClass = call_user_func([$this->editorClassName, 'getBaseClass']); + if (!is_subclass_of($baseClass, IFile::class)) { + throw new ImplementationException($baseClass, IFile::class); + } + if (is_subclass_of($baseClass, IThumbnailFile::class)) { + $this->options['thumbnailSizes'] = call_user_func([$baseClass, 'getThumbnailSizes']); + } + } + + /** + * Returns the successfully created file objects. + * + * @return IFile[] + */ + public function getObjects() { + return $this->objects; + } + + /** + * @inheritdoc + */ + public function save(UploadFile $uploadFile) { + $data = array_merge([ + 'filename' => $uploadFile->getFilename(), + 'filesize' => $uploadFile->getFilesize(), + 'fileType' => $uploadFile->getMimeType(), + 'fileHash' => sha1_file($uploadFile->getLocation()), + 'uploadTime' => TIME_NOW, + 'userID' => (WCF::getUser()->userID ?: null) + ], $this->data); + + // get image data + if (($imageData = $uploadFile->getImageData()) !== null) { + $data['width'] = $imageData['width']; + $data['height'] = $imageData['height']; + $data['fileType'] = $imageData['mimeType']; + + if (preg_match('~^image/(gif|jpe?g|png)$~i', $data['fileType'])) { + $data['isImage'] = 1; + } + } + + /** @var IDatabaseObjectAction $action */ + $action = new $this->actionClassName([], 'create', [ + 'data' => $data + ]); + + /** @var IThumbnailFile $object */ + $object = $action->executeAction()['returnValues']; + + $dir = dirname($object->getLocation()); + if (!@file_exists($dir)) { + FileUtil::makePath($dir); + } + + // move uploaded file + if (@move_uploaded_file($uploadFile->getLocation(), $object->getLocation())) { - // rotate image based on the exif data - if (!empty($this->options['rotateImages'])) { - if ($object->isImage) { - if (FileUtil::checkMemoryLimit($object->width * $object->height * ($object->fileType == 'image/png' ? 4 : 3) * 2.1)) { - $exifData = ExifUtil::getExifData($object->getLocation()); - if (!empty($exifData)) { - $orientation = ExifUtil::getOrientation($exifData); - if ($orientation != ExifUtil::ORIENTATION_ORIGINAL) { - $adapter = ImageHandler::getInstance()->getAdapter(); - $adapter->loadFile($object->getLocation()); - - $newImage = null; - switch ($orientation) { - case ExifUtil::ORIENTATION_180_ROTATE: - $newImage = $adapter->rotate(180); - break; ++ try { ++ // rotate image based on the exif data ++ if (!empty($this->options['rotateImages'])) { ++ if ($object->isImage) { ++ if (FileUtil::checkMemoryLimit($object->width * $object->height * ($object->fileType == 'image/png' ? 4 : 3) * 2.1)) { ++ $exifData = ExifUtil::getExifData($object->getLocation()); ++ if (!empty($exifData)) { ++ $orientation = ExifUtil::getOrientation($exifData); ++ if ($orientation != ExifUtil::ORIENTATION_ORIGINAL) { ++ $adapter = ImageHandler::getInstance()->getAdapter(); ++ $adapter->loadFile($object->getLocation()); + - case ExifUtil::ORIENTATION_90_ROTATE: - $newImage = $adapter->rotate(90); - break; ++ $newImage = null; ++ switch ($orientation) { ++ case ExifUtil::ORIENTATION_180_ROTATE: ++ $newImage = $adapter->rotate(180); ++ break; ++ ++ case ExifUtil::ORIENTATION_90_ROTATE: ++ $newImage = $adapter->rotate(90); ++ break; ++ ++ case ExifUtil::ORIENTATION_270_ROTATE: ++ $newImage = $adapter->rotate(270); ++ break; ++ ++ case ExifUtil::ORIENTATION_HORIZONTAL_FLIP: ++ case ExifUtil::ORIENTATION_VERTICAL_FLIP: ++ case ExifUtil::ORIENTATION_VERTICAL_FLIP_270_ROTATE: ++ case ExifUtil::ORIENTATION_HORIZONTAL_FLIP_270_ROTATE: ++ // unsupported ++ break; ++ } + - case ExifUtil::ORIENTATION_270_ROTATE: - $newImage = $adapter->rotate(270); - break; ++ if ($newImage !== null) { ++ $adapter->load($newImage, $adapter->getType()); ++ } + - case ExifUtil::ORIENTATION_HORIZONTAL_FLIP: - case ExifUtil::ORIENTATION_VERTICAL_FLIP: - case ExifUtil::ORIENTATION_VERTICAL_FLIP_270_ROTATE: - case ExifUtil::ORIENTATION_HORIZONTAL_FLIP_270_ROTATE: - // unsupported - break; - } - - if ($newImage !== null) { - $adapter->load($newImage, $adapter->getType()); - } - - $adapter->writeImage($object->getLocation()); - - // update width, height and filesize of the object - if ($newImage !== null && ($orientation == ExifUtil::ORIENTATION_90_ROTATE || $orientation == ExifUtil::ORIENTATION_270_ROTATE)) { - (new $this->editorClassName($object))->update([ - 'height' => $object->width, - 'width' => $object->height, - 'filesize' => filesize($object->getLocation()) - ]); ++ $adapter->writeImage($object->getLocation()); ++ ++ // update width, height and filesize of the object ++ if ($newImage !== null && ($orientation == ExifUtil::ORIENTATION_90_ROTATE || $orientation == ExifUtil::ORIENTATION_270_ROTATE)) { ++ (new $this->editorClassName($object))->update([ ++ 'height' => $object->width, ++ 'width' => $object->height, ++ 'filesize' => filesize($object->getLocation()) ++ ]); ++ } + } + } + } + } + } ++ ++ $this->objects[$uploadFile->getInternalFileID()] = $object; ++ } ++ catch (SystemException $e) { ++ (new $this->editorClassName($object))->delete(); + } - - $this->objects[$uploadFile->getInternalFileID()] = $object; + } + else { + (new $this->editorClassName($object))->delete(); + } + + if ($object->isImage && !empty($this->options['generateThumbnails']) && $object instanceof IThumbnailFile) { - $this->generateThumbnails($object); ++ try { ++ $this->generateThumbnails($object); ++ } ++ catch (SystemException $e) { ++ (new $this->editorClassName($object))->delete(); ++ } + } + } + + /** + * Generates thumbnails for the given file. + * + * @param IThumbnailFile $file + */ + public function generateThumbnails(IThumbnailFile $file) { + $smallestThumbnailSize = reset($this->options['thumbnailSizes']); + + // image is smaller than smallest thumbnail size + if ($file->width <= $smallestThumbnailSize['width'] && $file->height <= $smallestThumbnailSize['height']) { + return; + } + + // check memory limit + if (!FileUtil::checkMemoryLimit($file->width * $file->height * ($file->fileType == 'image/png' ? 4 : 3) * 2.1)) { + return; + } + + $adapter = ImageHandler::getInstance()->getAdapter(); + $adapter->loadFile($file->getLocation()); + + $updateData = []; + foreach ($this->options['thumbnailSizes'] as $type => $sizeData) { + $prefix = 'thumbnail'; + if (!empty($type)) { + $prefix = $type.'Thumbnail'; + } + + $thumbnailLocation = $file->getThumbnailLocation($type); + + // delete old thumbnails + if ($file->{$prefix.'Type'}) { + @unlink($thumbnailLocation); + $updateData[$prefix.'Type'] = ''; + $updateData[$prefix.'Size'] = 0; + $updateData[$prefix.'Width'] = 0; + $updateData[$prefix.'Height'] = 0; + } + + if ($file->width > $sizeData['width'] || $file->height > $sizeData['height']) { + $thumbnail = $adapter->createThumbnail($sizeData['width'], $sizeData['height'], isset($sizeData['retainDimensions']) ? $sizeData['retainDimensions'] : true); + $adapter->writeImage($thumbnail, $thumbnailLocation); + if (file_exists($thumbnailLocation) && ($imageData = @getimagesize($thumbnailLocation)) !== false) { + $updateData[$prefix.'Type'] = $imageData['mime']; + $updateData[$prefix.'Size'] = @filesize($thumbnailLocation); + $updateData[$prefix.'Width'] = $imageData[0]; + $updateData[$prefix.'Height'] = $imageData[1]; + } + } + } + + if (!empty($updateData)) { + /** @noinspection PhpUndefinedMethodInspection */ + (new $this->editorClassName($file))->update($updateData); + } + } +}