Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Differentiate between kilobyte/kibibyte and megabyte/mebibyte #9277

Merged
merged 18 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions system/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')
paulbalandan marked this conversation as resolved.
Show resolved Hide resolved
{
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()
};
}

Expand Down Expand Up @@ -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;
}
}
42 changes: 42 additions & 0 deletions system/Files/FileSizeUnit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Files;

use InvalidArgumentException;
paulbalandan marked this conversation as resolved.
Show resolved Hide resolved

enum FileSizeUnit: int
{
/**
* 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}"),
};
}

case B = 0;
case KB = 1;
case MB = 2;
case GB = 3;
case TB = 4;
paulbalandan marked this conversation as resolved.
Show resolved Hide resolved
}
ThomasMeschke marked this conversation as resolved.
Show resolved Hide resolved
54 changes: 54 additions & 0 deletions tests/system/Files/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -135,4 +168,25 @@ public function testGetDestination(): void
unlink(SYSTEMPATH . 'Common_Copy.php');
unlink(SYSTEMPATH . 'Common_Copy_5.php');
}

/**
* @return array<string, array<int, FileSizeUnit>>
*/
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,
],
];
}
}
3 changes: 3 additions & 0 deletions user_guide_src/source/changelogs/v4.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,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.
paulbalandan marked this conversation as resolved.
Show resolved Hide resolved

**********
Bugs Fixed
Expand Down
28 changes: 27 additions & 1 deletion user_guide_src/source/libraries/files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,40 @@ 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.

getSizeByBinaryUnit()
=====================

paulbalandan marked this conversation as resolved.
Show resolved Hide resolved
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.

getSizeByMetricUnit()
=====================

paulbalandan marked this conversation as resolved.
Show resolved Hide resolved
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()
=============

Expand Down
7 changes: 7 additions & 0 deletions user_guide_src/source/libraries/files/017.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

use CodeIgniter\Files\FileSizeUnit;

$bytes = $file->getSizeByBinaryUnit(); // 256901
$kibibytes = $file->getSizeByBinaryUnit(FileSizeUnit::KB); // 250.880
$mebibytes = $file->getSizeByBinaryUnit(FileSizeUnit::MB); // 0.245
7 changes: 7 additions & 0 deletions user_guide_src/source/libraries/files/018.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

use CodeIgniter\Files\FileSizeUnit;

$bytes = $file->getSizeByMetricUnit(); // 256901
$kilobytes = $file->getSizeByMetricUnit(FileSizeUnit::KB); // 256.901
$megabytes = $file->getSizeByMetricUnit(FileSizeUnit::MB); // 0.256
Loading