The logging line number and file was for the previous call position, not for where the actual log entry was called Also fix for ErrorMessage class calls with shifting the start position up depending on which method is called. Output shows file and line where the message/log call was done and the function/class method where the log call was done
168 lines
5.3 KiB
PHP
168 lines
5.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* byte conversion from and to human readable
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace CoreLibs\Convert;
|
|
|
|
class Byte
|
|
{
|
|
// define byteFormat
|
|
public const BYTE_FORMAT_NOSPACE = 1;
|
|
public const BYTE_FORMAT_ADJUST = 2;
|
|
public const BYTE_FORMAT_SI = 4;
|
|
|
|
/**
|
|
* This function replaces the old byteStringFormat
|
|
*
|
|
* Converts any number string to human readable byte format
|
|
* Maxium is Exobytes and above that the Exobytes suffix is used for all
|
|
* If more are needed only the correct short name for the suffix has to be
|
|
* added to the labels array
|
|
* On no number string it returns string as is
|
|
* Source Idea: SOURCE: https://programming.guide/worlds-most-copied-so-snippet.html
|
|
*
|
|
* The class itself hast the following defined
|
|
* BYTE_FORMAT_NOSPACE [1] turn off spaces between number and suffix
|
|
* BYTE_FORMAT_ADJUST [2] use sprintf to always print two decimals
|
|
* BYTE_FORMAT_SI [4] use si standard 1000 instead of bytes 1024
|
|
* To use the constant from outside use class::CONSTANT
|
|
*
|
|
* @param string|int|float $bytes bytes as string int or pure int
|
|
* @param int $flags bitwise flag with use space turned on
|
|
* BYTE_FORMAT_NOSPACE: no space between number and suffix
|
|
* BYTE_FORMAT_ADJUST: sprintf adjusted two 2 decimals
|
|
* BYTE_FORMAT_SI: use 1000 instead of 1024
|
|
* @return string converted byte number (float) with suffix
|
|
* @throws \InvalidArgumentException 1: no valid flag set
|
|
*/
|
|
public static function humanReadableByteFormat(string|int|float $bytes, int $flags = 0): string
|
|
{
|
|
// if not numeric, return as is
|
|
if (is_numeric($bytes)) {
|
|
// flags bit wise check
|
|
// remove space between number and suffix
|
|
if ($flags & self::BYTE_FORMAT_NOSPACE) {
|
|
$space = false;
|
|
} else {
|
|
$space = true;
|
|
}
|
|
// use sprintf instead of round
|
|
if ($flags & self::BYTE_FORMAT_ADJUST) {
|
|
$adjust = true;
|
|
} else {
|
|
$adjust = false;
|
|
}
|
|
// use SI 1000 mod and not 1024 mod
|
|
if ($flags & self::BYTE_FORMAT_SI) {
|
|
$si = true;
|
|
} else {
|
|
$si = false;
|
|
}
|
|
if ($flags > 7) {
|
|
throw new \InvalidArgumentException("Invalid flags parameter: $flags", 1);
|
|
}
|
|
|
|
// si or normal
|
|
$unit = $si ? 1000 : 1024;
|
|
// always positive
|
|
$abs_bytes = $bytes == PHP_INT_MIN ? PHP_INT_MAX : abs((float)$bytes);
|
|
// smaller than unit is always B
|
|
if ($abs_bytes < $unit) {
|
|
return $bytes . 'B';
|
|
}
|
|
// labels in order of size [Y, Z]
|
|
$labels = ['', 'K', 'M', 'G', 'T', 'P', 'E'];
|
|
// exp position calculation
|
|
$exp = (int)floor(log($abs_bytes, $unit));
|
|
// avoid printing out anything larger than max labels
|
|
if ($exp >= count($labels)) {
|
|
$exp = count($labels) - 1;
|
|
}
|
|
// deviation calculation
|
|
$dev = pow($unit, $exp) * ($unit - 0.05);
|
|
// shift the exp +1 for on the border units
|
|
if (
|
|
$exp < 6 &&
|
|
$abs_bytes > ($dev - (((int)$dev & 0xfff) == 0xd00 ? 52 : 0))
|
|
) {
|
|
$exp++;
|
|
}
|
|
// label name, including leading space if flagged
|
|
$pre = ($space ? ' ' : '') . ($labels[$exp] ?? '>E') . ($si ? 'i' : '') . 'B';
|
|
$bytes_calc = $abs_bytes / pow($unit, $exp);
|
|
// if original is negative, reverse
|
|
if ($bytes < 0) {
|
|
$bytes_calc *= -1;
|
|
}
|
|
if ($adjust) {
|
|
return sprintf("%.2f%s", $bytes_calc, $pre);
|
|
} else {
|
|
return round($bytes_calc, 2) . $pre;
|
|
}
|
|
} else {
|
|
// if anything other return as string
|
|
return (string)$bytes;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* calculates the bytes based on a string with nnG, nnGB, nnM, etc
|
|
* NOTE: large exabyte numbers will overflow
|
|
* flag allowed:
|
|
* BYTE_FORMAT_SI [4] use si standard 1000 instead of bytes 1024
|
|
*
|
|
* @param string|int|float $number any string or number to convert
|
|
* @param int $flags bitwise flag with use space turned on
|
|
* BYTE_FORMAT_SI: use 1000 instead of 1024
|
|
* @return string|int|float converted value or original value
|
|
* @throws \InvalidArgumentException 1: no valid flag set
|
|
*/
|
|
public static function stringByteFormat(string|int|float $number, int $flags = 0): string|int|float
|
|
{
|
|
// use SI 1000 mod and not 1024 mod
|
|
if ($flags & self::BYTE_FORMAT_SI) {
|
|
$si = true;
|
|
} else {
|
|
$si = false;
|
|
}
|
|
if ($flags != 0 && $flags != 4) {
|
|
throw new \InvalidArgumentException("Invalid flags parameter: $flags", 1);
|
|
}
|
|
// matches in regex
|
|
$matches = [];
|
|
// all valid units
|
|
$valid_units_ = 'bkmgtpezy';
|
|
// detects up to exo bytes
|
|
preg_match(
|
|
"/(-)?([\d.,]*)\s?(eib|pib|tib|gib|mib|kib|eb|pb|tb|gb|mb|kb|e|p|t|g|m|k|b)$/i",
|
|
strtolower((string)$number),
|
|
$matches
|
|
);
|
|
if (isset($matches[2]) && isset($matches[3])) {
|
|
// remove all non valid characters from the number
|
|
$number = preg_replace('/[^0-9\.]/', '', $matches[2]);
|
|
// final clean up and convert to float
|
|
$number = (float)trim((string)$number);
|
|
// convert any mb/gb/etc to single m/b
|
|
$unit = preg_replace('/[^bkmgtpezy]/i', '', $matches[3]);
|
|
if ($unit) {
|
|
$number = $number * pow($si ? 1000 : 1024, stripos($valid_units_, $unit[0]) ?: 0);
|
|
}
|
|
// convert to INT to avoid +E output
|
|
$number = (int)round($number);
|
|
// if negative input, keep nnegative
|
|
if (!empty($matches[1])) {
|
|
$number *= -1;
|
|
}
|
|
}
|
|
// if not matching return as is
|
|
return $number;
|
|
}
|
|
}
|
|
|
|
// __END__
|