diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index a1bb458a2804..884e76bc6f53 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -102,8 +102,6 @@ class Mimes ], 'pptx' => [ 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'application/x-zip', - 'application/zip', ], 'wbxml' => 'application/wbxml', 'wmlc' => 'application/wmlc', @@ -512,20 +510,19 @@ public static function guessExtensionFromType(string $type, ?string $proposedExt $proposedExtension = trim(strtolower($proposedExtension ?? '')); - if ($proposedExtension !== '') { - if (array_key_exists($proposedExtension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposedExtension]) ? [static::$mimes[$proposedExtension]] : static::$mimes[$proposedExtension], true)) { - // The detected mime type matches with the proposed extension. - return $proposedExtension; - } - - // An extension was proposed, but the media type does not match the mime type list. - return null; + if ( + $proposedExtension !== '' + && array_key_exists($proposedExtension, static::$mimes) + && in_array($type, (array) static::$mimes[$proposedExtension], true) + ) { + // The detected mime type matches with the proposed extension. + return $proposedExtension; } // Reverse check the mime type list if no extension was proposed. // This search is order sensitive! foreach (static::$mimes as $ext => $types) { - if ((is_string($types) && $types === $type) || (is_array($types) && in_array($type, $types, true))) { + if (in_array($type, (array) $types, true)) { return $ext; } } diff --git a/system/Files/File.php b/system/Files/File.php index b3bdb47b90de..4d4067d4caa5 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -89,7 +89,12 @@ public function getSizeByUnit(string $unit = 'b') */ public function guessExtension(): ?string { - return Mimes::guessExtensionFromType($this->getMimeType()); + // naively get the path extension using pathinfo + $pathinfo = pathinfo($this->getRealPath() ?: $this->__toString()) + ['extension' => '']; + + $proposedExtension = $pathinfo['extension']; + + return Mimes::guessExtensionFromType($this->getMimeType(), $proposedExtension); } /** diff --git a/tests/system/Files/FileTest.php b/tests/system/Files/FileTest.php index 573c8cdb3499..1176bd2e2622 100644 --- a/tests/system/Files/FileTest.php +++ b/tests/system/Files/FileTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Files\Exceptions\FileNotFoundException; use CodeIgniter\Test\CIUnitTestCase; +use ZipArchive; /** * @internal @@ -44,10 +45,34 @@ public function testGuessExtension() { $file = new File(SYSTEMPATH . 'Common.php'); $this->assertSame('php', $file->guessExtension()); + $file = new File(SYSTEMPATH . 'index.html'); $this->assertSame('html', $file->guessExtension()); + $file = new File(ROOTPATH . 'phpunit.xml.dist'); $this->assertSame('xml', $file->guessExtension()); + + $tmp = tempnam(SUPPORTPATH, 'foo'); + $file = new File($tmp, true); + $this->assertNull($file->guessExtension()); + unlink($tmp); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/6046 + */ + public function testGuessExtensionOnZip(): void + { + $tmp = SUPPORTPATH . 'foobar.zip'; + + $zip = new ZipArchive(); + $zip->open($tmp, ZipArchive::CREATE | ZipArchive::CHECKCONS | ZipArchive::EXCL); + $zip->addFile(SYSTEMPATH . 'Common.php'); + $zip->close(); + + $file = new File($tmp, true); + $this->assertSame('zip', $file->guessExtension()); + unlink($tmp); } public function testRandomName() diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 6b3c7533ff96..c870099108cc 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -194,7 +194,7 @@ public function testExtensionGuessing() $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame('txt', $file->getExtension()); // but not client mime type - $this->assertNull(Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); + $this->assertSame('csv', Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); // proposed extension does not match finfo_open mime type (text/plain) // but can be resolved by reverse searching @@ -208,14 +208,12 @@ public function testExtensionGuessing() $this->assertSame('zip', $file->getExtension()); // proposed extension matches client mime type, but not finfo_open mime type (application/zip) - // this is a zip file (userFile4) but hat been renamed to 'rar' + // this is a zip file (userFile4) but has been renamed to 'rar' $file = $collection->getFile('userfile5'); $this->assertInstanceOf(UploadedFile::class, $file); - // getExtension falls back to clientExtension (insecure) - $this->assertSame('rar', $file->getExtension()); + $this->assertSame('zip', $file->getExtension()); $this->assertSame('rar', Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); - // guessExtension is secure and does not returns empty - $this->assertSame('', $file->guessExtension()); + $this->assertSame('zip', $file->guessExtension()); } /** diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index a6aefc4cd181..edef0a8e2208 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,6 +12,7 @@ See all the changes. .. toctree:: :titlesonly: + v4.2.1 v4.2.0 v4.1.9 v4.1.8 diff --git a/user_guide_src/source/changelogs/v4.2.1.rst b/user_guide_src/source/changelogs/v4.2.1.rst new file mode 100644 index 000000000000..d591d08cf008 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.2.1.rst @@ -0,0 +1,18 @@ +Version 4.2.1 +############# + +Release Date: Unreleased + +**4.2.1 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 2 + +BREAKING +******** + +Behavior Changes +================ + +- Guessing the file extension from the MIME type has been changed if the proposed extension is not valid. Previously, the guessing will early terminate and return ``null``. Now, if a proposed extension is given and is invalid, the MIME guessing will continue checking using the mapping of extension to MIME types. diff --git a/user_guide_src/source/installation/upgrade_421.rst b/user_guide_src/source/installation/upgrade_421.rst new file mode 100644 index 000000000000..fb5825179c10 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_421.rst @@ -0,0 +1,53 @@ +############################# +Upgrading from 4.2.0 to 4.2.1 +############################# + +Please refer to the upgrade instructions corresponding to your installation method. + +- :ref:`Composer Installation App Starter Upgrading ` +- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` +- :ref:`Manual Installation Upgrading ` + +.. contents:: + :local: + :depth: 2 + +Mandatory File Changes +********************** + +app/Config/Mimes.php +=================== + +- The mapping of file extensions to MIME types in **app/Config/Mimes.php** was updated to fix a bug. Also, the logic of ``Mimes::getExtensionFromType()`` was changed. + +Breaking Changes +**************** + + +Breaking Enhancements +********************* + + +Project Files +************* + +Numerous files in the **project space** (root, app, public, writable) received updates. Due to +these files being outside of the **system** scope they will not be changed without your intervention. +There are some third-party CodeIgniter modules available to assist with merging changes to +the project space: `Explore on Packagist `_. + +.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space + will break your application. All changes noted here are optional until the next major version, + and any mandatory changes will be covered in the sections above. + +Content Changes +=============== + + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +* app/Config/Mimes.php diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index aa79ef0d6bc7..3570419e19c2 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -12,6 +12,7 @@ upgrading from. .. toctree:: :titlesonly: + upgrade_421 upgrade_420 upgrade_418 upgrade_417