index/src/ByteFormat.php

88 lines
2.4 KiB
PHP

<?php
// ByteFormat.php
// Created: 2023-07-05
// Updated: 2024-08-01
namespace Index;
/**
* Implements a byte formatter for file sizes.
*/
final class ByteFormat {
/**
* Whether the default behaviour for the format function is decimal (power of 10) or not (power of 2).
*
* @var bool
*/
public const DECIMAL_DEFAULT = true;
private const SYMBOLS = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'];
private const DIV_DECIMAL = 1000;
private const DIV_BINARY = 1024;
/**
* Formats a raw amount of bytes as a human readable string.
*
* @param int $bytes Number of bytes.
* @param bool $decimal Whether format as a power of 10 (e.g. MB) or a power of 2 (e.g. MiB).
* @return string Formatted byte string.
*/
public static function format(int $bytes, bool $decimal = self::DECIMAL_DEFAULT): string {
// this whole thing will be fun if i ever decide to do localisation
if($bytes === 0)
return 'Zero Bytes';
$negative = $bytes < 0;
$bytes = abs($bytes);
$power = $decimal ? self::DIV_DECIMAL : self::DIV_BINARY;
$exp = floor(log($bytes) / log($power));
$number = $bytes / pow($power, $exp);
$symbol = self::SYMBOLS[$exp];
$string = '';
if($negative)
$string .= '-';
if($bytes < $power)
$string .= $number;
else if($number < 10)
$string .= sprintf('%.2f', $number);
else
$string .= sprintf('%.1f', $number);
$string .= ' ' . $symbol;
if($symbol === '') {
$string .= 'Byte';
if($number > 1)
$string .= 's';
} else {
if(!$decimal)
$string .= 'i';
$string .= 'B';
}
return $string;
}
/**
* Formats a raw amount of bytes as a human readable string in the power of 10 (e.g. MB).
*
* @param int $bytes Number of bytes.
* @return string Formatted byte string.
*/
public static function formatDecimal(int $bytes): string {
return self::format($bytes, true);
}
/**
* Formats a raw amount of bytes as a human readable string in the power of 2 (e.g. MiB).
*
* @param int $bytes Number of bytes.
* @return string Formatted byte string.
*/
public static function formatBinary(int $bytes): string {
return self::format($bytes, false);
}
}