| @@ -23,11 +23,10 @@ | ||
| 23 | 23 | */ |
| 24 | 24 | final class FileUpload |
| 25 | 25 | { |
| 26 | 26 | use \Packetery\Nette\SmartObject; |
| 27 | - public const ImageMimeTypes = ['image/gif', 'image/png', 'image/jpeg', 'image/webp']; | |
| 28 | - /** @deprecated use FileUpload::ImageMimeTypes */ | |
| 29 | - public const IMAGE_MIME_TYPES = self::ImageMimeTypes; | |
| 27 | + /** @deprecated */ | |
| 28 | + public const IMAGE_MIME_TYPES = ['image/gif', 'image/png', 'image/jpeg', 'image/webp']; | |
| 30 | 29 | /** @var string */ |
| 31 | 30 | private $name; |
| 32 | 31 | /** @var string|null */ |
| 33 | 32 | private $fullPath; |
| @@ -32,8 +31,10 @@ | ||
| 32 | 31 | /** @var string|null */ |
| 33 | 32 | private $fullPath; |
| 34 | 33 | /** @var string|false|null */ |
| 35 | 34 | private $type; |
| 35 | + /** @var string|false|null */ | |
| 36 | + private $extension; | |
| 36 | 37 | /** @var int */ |
| 37 | 38 | private $size; |
| 38 | 39 | /** @var string */ |
| 39 | 40 | private $tmpName; |
| @@ -79,11 +80,11 @@ | ||
| 79 | 80 | $name = \Packetery\Nette\Utils\Strings::webalize($this->name, '.', \false); |
| 80 | 81 | $name = \str_replace(['-.', '.-'], '.', $name); |
| 81 | 82 | $name = \trim($name, '.-'); |
| 82 | 83 | $name = $name === '' ? 'unknown' : $name; |
| 83 | - if ($this->isImage()) { | |
| 84 | + if ($ext = $this->getSuggestedExtension()) { | |
| 84 | 85 | $name = \preg_replace('#\\.[^.]+$#D', '', $name); |
| 85 | - $name .= '.' . ($this->getImageFileExtension() ?? 'unknown'); | |
| 86 | + $name .= '.' . $ext; | |
| 86 | 87 | } |
| 87 | 88 | return $name; |
| 88 | 89 | } |
| 89 | 90 | /** |
| @@ -108,10 +109,29 @@ | ||
| 108 | 109 | } |
| 109 | 110 | return $this->type ?: null; |
| 110 | 111 | } |
| 111 | 112 | /** |
| 112 | - * Returns the path of the temporary location of the uploaded file. | |
| 113 | + * Returns the appropriate file extension (without the period) corresponding to the detected MIME type. Requires the PHP extension fileinfo. | |
| 113 | 114 | */ |
| 115 | + public function getSuggestedExtension() : ?string | |
| 116 | + { | |
| 117 | + if ($this->isOk() && $this->extension === null) { | |
| 118 | + $exts = \finfo_file(\finfo_open(\FILEINFO_EXTENSION), $this->tmpName); | |
| 119 | + if ($exts && $exts !== '???') { | |
| 120 | + return $this->extension = \preg_replace('~[/,].*~', '', $exts); | |
| 121 | + } | |
| 122 | + [, , $type] = @\getimagesize($this->tmpName); | |
| 123 | + // @ - files smaller than 12 bytes causes read error | |
| 124 | + if ($type) { | |
| 125 | + return $this->extension = \image_type_to_extension($type, \false); | |
| 126 | + } | |
| 127 | + $this->extension = \false; | |
| 128 | + } | |
| 129 | + return $this->extension ?: null; | |
| 130 | + } | |
| 131 | + /** | |
| 132 | + * Returns the size of the uploaded file in bytes. | |
| 133 | + */ | |
| 114 | 134 | public function getSize() : int |
| 115 | 135 | { |
| 116 | 136 | return $this->size; |
| 117 | 137 | } |
| @@ -169,17 +189,19 @@ | ||
| 169 | 189 | $this->tmpName = $dest; |
| 170 | 190 | return $this; |
| 171 | 191 | } |
| 172 | 192 | /** |
| 173 | - * Returns true if the uploaded file is a JPEG, PNG, GIF, or WebP image. | |
| 174 | - * Detection is based on its signature, the integrity of the file is not checked. Requires PHP extension fileinfo. | |
| 193 | + * Returns true if the uploaded file is an image and the format is supported by PHP, so it can be loaded using the toImage() method. | |
| 194 | + * Detection is based on its signature, the integrity of the file is not checked. Requires PHP extensions fileinfo & gd. | |
| 175 | 195 | */ |
| 176 | 196 | public function isImage() : bool |
| 177 | 197 | { |
| 178 | - return \in_array($this->getContentType(), self::ImageMimeTypes, \true); | |
| 198 | + $flag = \imagetypes(); | |
| 199 | + $types = \array_filter([$flag & \IMG_GIF ? 'image/gif' : null, $flag & \IMG_JPG ? 'image/jpeg' : null, $flag & \IMG_PNG ? 'image/png' : null, $flag & \IMG_WEBP ? 'image/webp' : null, $flag & 256 ? 'image/avif' : null]); | |
| 200 | + return \in_array($this->getContentType(), $types, \true); | |
| 179 | 201 | } |
| 180 | 202 | /** |
| 181 | - * Loads an image. | |
| 203 | + * Converts uploaded image to \Packetery\Nette\Utils\Image object. | |
| 182 | 204 | * @throws \Packetery\Nette\Utils\ImageException If the upload was not successful or is not a valid image |
| 183 | 205 | */ |
| 184 | 206 | public function toImage() : \Packetery\Nette\Utils\Image |
| 185 | 207 | { |
| @@ -193,12 +215,13 @@ | ||
| 193 | 215 | return $this->isImage() ? \array_intersect_key(\getimagesize($this->tmpName), [0, 1]) : null; |
| 194 | 216 | } |
| 195 | 217 | /** |
| 196 | 218 | * Returns image file extension based on detected content type (without dot). |
| 219 | + * @deprecated use getSuggestedExtension() | |
| 197 | 220 | */ |
| 198 | 221 | public function getImageFileExtension() : ?string |
| 199 | 222 | { |
| 200 | - return $this->isImage() ? \explode('/', $this->getContentType())[1] : null; | |
| 223 | + return $this->getSuggestedExtension(); | |
| 201 | 224 | } |
| 202 | 225 | /** |
| 203 | 226 | * Returns the contents of the uploaded file. If the upload was not successful, it returns null. |
| 204 | 227 | */ |