diff --git a/system/Files/File.php b/system/Files/File.php index 15b53262e9c2..1b9aefbb6694 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -70,17 +70,39 @@ public function getSize() return $this->size ?? ($this->size = parent::getSize()); } + /** + * Retrieve the file size by unit, calculated in IEC standards with 1024 as base value. + * + * @phpstan-param positive-int $precision + */ + public function getSizeByBinaryUnit(FileSizeUnit $unit = FileSizeUnit::B, int $precision = 3): int|string + { + return $this->getSizeByUnitInternal(1024, $unit, $precision); + } + + /** + * Retrieve the file size by unit, calculated in metric standards with 1000 as base value. + * + * @phpstan-param positive-int $precision + */ + public function getSizeByMetricUnit(FileSizeUnit $unit = FileSizeUnit::B, int $precision = 3): int|string + { + return $this->getSizeByUnitInternal(1000, $unit, $precision); + } + /** * Retrieve the file size by unit. * + * @deprecated 4.6.0 Use getSizeByBinaryUnit() or getSizeByMetricUnit() instead + * * @return false|int|string */ public function getSizeByUnit(string $unit = 'b') { return match (strtolower($unit)) { - 'kb' => number_format($this->getSize() / 1024, 3), - 'mb' => number_format(($this->getSize() / 1024) / 1024, 3), - default => $this->getSize(), + 'kb' => $this->getSizeByBinaryUnit(FileSizeUnit::KB), + 'mb' => $this->getSizeByBinaryUnit(FileSizeUnit::MB), + default => $this->getSize() }; } @@ -189,4 +211,17 @@ public function getDestination(string $destination, string $delimiter = '_', int return $destination; } + + private function getSizeByUnitInternal(int $fileSizeBase, FileSizeUnit $unit, int $precision): int|string + { + $exponent = $unit->value; + $divider = $fileSizeBase ** $exponent; + $size = $this->getSize() / $divider; + + if ($unit !== FileSizeUnit::B) { + $size = number_format($size, $precision); + } + + return $size; + } } diff --git a/system/Files/FileSizeUnit.php b/system/Files/FileSizeUnit.php new file mode 100644 index 000000000000..84c2ba44ca13 --- /dev/null +++ b/system/Files/FileSizeUnit.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Files; + +use CodeIgniter\Exceptions\InvalidArgumentException; + +enum FileSizeUnit: int +{ + case B = 0; + case KB = 1; + case MB = 2; + case GB = 3; + case TB = 4; + + /** + * Allows the creation of a FileSizeUnit from Strings like "kb" or "mb" + * + * @throws InvalidArgumentException + */ + public static function fromString(string $unit): self + { + return match (strtolower($unit)) { + 'b' => self::B, + 'kb' => self::KB, + 'mb' => self::MB, + 'gb' => self::GB, + 'tb' => self::TB, + default => throw new InvalidArgumentException("Invalid unit: {$unit}"), + }; + } +} diff --git a/tests/system/Files/FileTest.php b/tests/system/Files/FileTest.php index 800a1ac278f1..b8e82edd02fd 100644 --- a/tests/system/Files/FileTest.php +++ b/tests/system/Files/FileTest.php @@ -15,6 +15,7 @@ use CodeIgniter\Files\Exceptions\FileNotFoundException; use CodeIgniter\Test\CIUnitTestCase; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use ZipArchive; @@ -113,6 +114,38 @@ public function testGetSizeReturnsBytes(): void $this->assertSame($size, $file->getSizeByUnit('b')); } + #[DataProvider('provideGetSizeData')] + public function testGetSizeBinary(FileSizeUnit $unit): void + { + $divider = 1024 ** $unit->value; + $file = new File(SYSTEMPATH . 'Common.php'); + $size = number_format(filesize(SYSTEMPATH . 'Common.php') / $divider, 3); + $this->assertSame($size, $file->getSizeByBinaryUnit($unit)); + } + + public function testGetSizeBinaryBytes(): void + { + $file = new File(SYSTEMPATH . 'Common.php'); + $size = filesize(SYSTEMPATH . 'Common.php'); + $this->assertSame($size, $file->getSizeByBinaryUnit(FileSizeUnit::B)); + } + + #[DataProvider('provideGetSizeData')] + public function testGetSizeMetric(FileSizeUnit $unit): void + { + $divider = 1000 ** $unit->value; + $file = new File(SYSTEMPATH . 'Common.php'); + $size = number_format(filesize(SYSTEMPATH . 'Common.php') / $divider, 3); + $this->assertSame($size, $file->getSizeByMetricUnit($unit)); + } + + public function testGetSizeMetricBytes(): void + { + $file = new File(SYSTEMPATH . 'Common.php'); + $size = filesize(SYSTEMPATH . 'Common.php'); + $this->assertSame($size, $file->getSizeByMetricUnit(FileSizeUnit::B)); + } + public function testThrowsExceptionIfNotAFile(): void { $this->expectException(FileNotFoundException::class); @@ -135,4 +168,25 @@ public function testGetDestination(): void unlink(SYSTEMPATH . 'Common_Copy.php'); unlink(SYSTEMPATH . 'Common_Copy_5.php'); } + + /** + * @return array> + */ + public static function provideGetSizeData() + { + return [ + 'returns KB binary' => [ + FileSizeUnit::KB, + ], + 'returns MB binary' => [ + FileSizeUnit::MB, + ], + 'returns GB binary' => [ + FileSizeUnit::GB, + ], + 'returns TB binary' => [ + FileSizeUnit::TB, + ], + ]; + } } diff --git a/user_guide_src/source/changelogs/v4.6.0.rst b/user_guide_src/source/changelogs/v4.6.0.rst index d3dc4529d512..e68f60a0d4c4 100644 --- a/user_guide_src/source/changelogs/v4.6.0.rst +++ b/user_guide_src/source/changelogs/v4.6.0.rst @@ -215,6 +215,8 @@ Model Libraries ========= +- **File:** Added ``getSizeByBinaryUnit()`` and ``getSizeByMetricUnit()`` to ``File`` class. + See :ref:`File::getSizeByBinaryUnit() ` and :ref:`File::getSizeByMetricUnit() `. - **FileCollection:** Added ``retainMultiplePatterns()`` to ``FileCollection`` class. See :ref:`FileCollection::retainMultiplePatterns() `. - **Validation:** Added ``min_dims`` validation rule to ``FileRules`` class. See @@ -277,6 +279,9 @@ Deprecations - The properties ``$arguments`` and ``$argumentsClass`` of ``Filters`` have been deprecated. No longer used. - The ``Filters::getArguments()`` method has been deprecated. No longer used. +- **File:** + - The function ``getSizeByUnit()`` of ``File`` has been deprecated. + Use either ``getSizeByBinaryUnit()`` or ``getSizeByMetricUnit()`` instead. ********** Bugs Fixed diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 1622c3345c51..df9f2f4b89dc 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -56,14 +56,50 @@ A ``RuntimeException`` will be thrown if the file does not exist or an error occ getSizeByUnit() =============== +.. deprecated:: 4.6.0 + Returns the size of the file default in bytes. You can pass in either ``'kb'`` or ``'mb'`` as the first parameter to get -the results in kilobytes or megabytes, respectively: +the results in kibibytes or mebibytes, respectively: .. literalinclude:: files/005.php :lines: 2- A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. + +.. _file-get-size-by-binary-unit: + +getSizeByBinaryUnit() +===================== + +.. versionadded:: 4.6.0 + +Returns the size of the file default in bytes. You can pass in different FileSizeUnit values as the first parameter to get +the results in kibibytes, mebibytes etc. respectively. You can pass in a precision value as the second parameter to define +the amount of decimal places. + +.. literalinclude:: files/017.php + :lines: 4- + +A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. + + +.. _file-get-size-by-metric-unit: + +getSizeByMetricUnit() +===================== + +.. versionadded:: 4.6.0 + +Returns the size of the file default in bytes. You can pass in different FileSizeUnit values as the first parameter to get +the results in kilobytes, megabytes etc. respectively. You can pass in a precision value as the second parameter to define +the amount of decimal places. + +.. literalinclude:: files/018.php + :lines: 4- + +A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. + getMimeType() ============= diff --git a/user_guide_src/source/libraries/files/017.php b/user_guide_src/source/libraries/files/017.php new file mode 100644 index 000000000000..ad4d89476180 --- /dev/null +++ b/user_guide_src/source/libraries/files/017.php @@ -0,0 +1,7 @@ +getSizeByBinaryUnit(); // 256901 +$kibibytes = $file->getSizeByBinaryUnit(FileSizeUnit::KB); // 250.880 +$mebibytes = $file->getSizeByBinaryUnit(FileSizeUnit::MB); // 0.245 diff --git a/user_guide_src/source/libraries/files/018.php b/user_guide_src/source/libraries/files/018.php new file mode 100644 index 000000000000..07521b4bbe1c --- /dev/null +++ b/user_guide_src/source/libraries/files/018.php @@ -0,0 +1,7 @@ +getSizeByMetricUnit(); // 256901 +$kilobytes = $file->getSizeByMetricUnit(FileSizeUnit::KB); // 256.901 +$megabytes = $file->getSizeByMetricUnit(FileSizeUnit::MB); // 0.256