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: Breaking: Differentiate between kilobyte/kibibyte and megabyte/mebibyte #9277

Open
wants to merge 18 commits into
base: 4.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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 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}"),
};
}
}
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,
],
];
}
}
5 changes: 5 additions & 0 deletions user_guide_src/source/changelogs/v4.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ Model
Libraries
=========

- **File:** Added ``getSizeByBinaryUnit()`` and ``getSizeByMetricUnit()`` to ``File`` class.
See :ref:`File::getSizeByBinaryUnit() <file-get-size-by-binary-unit>` and :ref:`File::getSizeByMetricUnit() <file-get-size-by-metric-unit>`.
- **FileCollection:** Added ``retainMultiplePatterns()`` to ``FileCollection`` class.
See :ref:`FileCollection::retainMultiplePatterns() <file-collections-retain-multiple-patterns>`.
- **Validation:** Added ``min_dims`` validation rule to ``FileRules`` class. See
Expand Down Expand Up @@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do. Two separate bullet point, or both in one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line would be sufficient.


**********
Bugs Fixed
Expand Down
38 changes: 37 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,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()
=====================

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. versionadded:: 4.6.0

.. 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()
=====================

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. versionadded:: 4.6.0

.. 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()
=============

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