diff --git a/src/Http/FileUpload.php b/src/Http/FileUpload.php index 52982b6c..cefbf8d1 100644 --- a/src/Http/FileUpload.php +++ b/src/Http/FileUpload.php @@ -41,6 +41,9 @@ final class FileUpload /** @var string|false|null */ private $type; + /** @var string|false|null */ + private $extension; + /** @var int */ private $size; @@ -98,9 +101,9 @@ public function getSanitizedName(): string $name = str_replace(['-.', '.-'], '.', $name); $name = trim($name, '.-'); $name = $name === '' ? 'unknown' : $name; - if ($this->isImage()) { + if ($ext = $this->getSuggestedExtension()) { $name = preg_replace('#\.[^.]+$#D', '', $name); - $name .= '.' . ($this->getImageFileExtension() ?? 'unknown'); + $name .= '.' . $ext; } return $name; @@ -134,6 +137,27 @@ public function getContentType(): ?string } + /** + * Returns the appropriate file extension (without the period) corresponding to the detected MIME type. Requires the PHP extension fileinfo. + */ + public function getSuggestedExtension(): ?string + { + if ($this->isOk() && $this->extension === null) { + $exts = finfo_file(finfo_open(FILEINFO_EXTENSION), $this->tmpName); + if ($exts && $exts !== '???') { + return $this->extension = preg_replace('~[/,].*~', '', $exts); + } + [, , $type] = @getimagesize($this->tmpName); // @ - files smaller than 12 bytes causes read error + if ($type) { + return $this->extension = image_type_to_extension($type, false); + } + $this->extension = false; + } + + return $this->extension ?: null; + } + + /** * Returns the size of the uploaded file in bytes. */ @@ -252,12 +276,11 @@ public function getImageSize(): ?array /** * Returns image file extension based on detected content type (without dot). + * @deprecated use getSuggestedExtension() */ public function getImageFileExtension(): ?string { - return $this->isImage() - ? explode('/', $this->getContentType())[1] - : null; + return $this->getSuggestedExtension(); } diff --git a/tests/Http/FileUpload.basic.phpt b/tests/Http/FileUpload.basic.phpt index 573568af..505774dc 100644 --- a/tests/Http/FileUpload.basic.phpt +++ b/tests/Http/FileUpload.basic.phpt @@ -33,7 +33,7 @@ test('', function () { Assert::true($upload->isOk()); Assert::true($upload->hasFile()); Assert::false($upload->isImage()); - Assert::null($upload->getImageFileExtension()); + Assert::null($upload->getSuggestedExtension()); Assert::same(file_get_contents(__DIR__ . '/files/file.txt'), $upload->getContents()); }); @@ -51,7 +51,7 @@ test('', function () { Assert::same('image.png', $upload->getSanitizedName()); Assert::same('../.image.png', $upload->getUntrustedFullPath()); Assert::same('image/png', $upload->getContentType()); - Assert::same('png', $upload->getImageFileExtension()); + Assert::same('png', $upload->getSuggestedExtension()); Assert::same([108, 46], $upload->getImageSize()); Assert::true($upload->isImage()); }); @@ -68,6 +68,7 @@ test('', function () { Assert::false($upload->isOk()); Assert::false($upload->hasFile()); + Assert::null($upload->getContentType()); Assert::false($upload->isImage()); - Assert::null($upload->getImageFileExtension()); + Assert::null($upload->getSuggestedExtension()); }); diff --git a/tests/Http/FileUpload.getSanitizedName.phpt b/tests/Http/FileUpload.getSanitizedName.phpt index 825c147f..0b0c6cce 100644 --- a/tests/Http/FileUpload.getSanitizedName.phpt +++ b/tests/Http/FileUpload.getSanitizedName.phpt @@ -43,7 +43,7 @@ Assert::with(new FileUpload([]), function () { Assert::with(new FileUpload([]), function () { - $this->type = 'image/jpeg'; + $this->extension = 'jpeg'; $this->name = ''; Assert::same('unknown.jpeg', $this->getSanitizedName());