From b6f6eeac9bdbedc95f16c81c2396fa758bb73cf2 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Fri, 6 Dec 2019 15:29:06 +0900 Subject: [PATCH] Update byteStringFormat with si units and bitwise mask The old method name byteStringFormat is currently deprecated and it is recommended to move to the new humanReadableByteFormat method. Difference is that the new version uses a bitfield settings mask BYTE_FORMAT_NOSPACE, BYTE_FORMAT_ADJUST, BYTE_FORMAT_SI --- www/admin/class_test.php | 40 +++++++++- www/admin/namespace_test.php | 4 +- www/lib/CoreLibs/Admin/Backend.php | 2 +- www/lib/CoreLibs/Basic.php | 119 ++++++++++++++++++++++++++--- 4 files changed, 152 insertions(+), 13 deletions(-) diff --git a/www/admin/class_test.php b/www/admin/class_test.php index 15878160..ea29028f 100644 --- a/www/admin/class_test.php +++ b/www/admin/class_test.php @@ -254,6 +254,45 @@ echo "SOURCE ARRAY: ".$basic->printAr($test_array)."
"; echo "FOUND ELEMENTS [base]: ".$basic->printAr($basic->arraySearchRecursive('email', $test_array, 'type'))."
"; echo "FOUND ELEMENTS [input]: ".$basic->printAr($basic->arraySearchRecursive('email', $test_array['input'], 'type'))."
"; +// *** BYTES TEST *** +$bytes = array( + -123123123, + 999999, // KB-1 + 999999999, // MB-1 + 254779258, // MB-n + 999999999999999, // TB-1 + 588795544887632, // TB-n + 999999999999999999, // PB-1 + 9223372036854775807, // MAX INT + 999999999999999999999, // EB-1 +); +print "BYTE FORMAT TESTS
"; +foreach ($bytes as $byte) { + print '
'; + // + print '
'; + print "(".number_format($byte)."/".$byte.") bytes :"; + print '
'; + print $basic->humanReadableByteFormat($byte); + print "
"; + // + print "
"; + // + print '
'; + // + print '
'; + print "bytes [si]:"; + print '
'; + // print $basic->byteStringFormat($byte, true, false, true); + print $basic->humanReadableByteFormat($byte, $basic::BYTE_FORMAT_SI); + print "
"; + // + print "
"; +} + + +// *** IMAGE TESTS *** +echo "
"; // image thumbnail $images = array( // height bigger @@ -272,7 +311,6 @@ $images = array( // Photoshop 'photoshop_test.psd', ); -echo "
"; $thumb_width = 250; $thumb_height = 300; // return mime type ala mimetype diff --git a/www/admin/namespace_test.php b/www/admin/namespace_test.php index 89e90e13..efebe1e3 100755 --- a/www/admin/namespace_test.php +++ b/www/admin/namespace_test.php @@ -21,8 +21,8 @@ if ($base->getConnectionStatus()) { } print "Start time: ".$base->runningTime()."
"; -print "ByteStringFormat: ".$base->ByteStringFormat(1234567.12)."
"; -print "byteStringFormat: ".$base->byteStringFormat(1234567.12)."
"; +print "HumanReadableByteFormat: ".$base->HumanReadableByteFormat(1234567.12)."
"; +print "humanReadableByteFormat: ".$base->humanReadableByteFormat(1234567.12)."
"; // print "get_page_name [DEPRECATED]: ".$base->get_page_name()."
"; print "getPageName: ".$base->getPageName()."
"; diff --git a/www/lib/CoreLibs/Admin/Backend.php b/www/lib/CoreLibs/Admin/Backend.php index edefe756..a72ff1d7 100644 --- a/www/lib/CoreLibs/Admin/Backend.php +++ b/www/lib/CoreLibs/Admin/Backend.php @@ -364,7 +364,7 @@ class Backend extends \CoreLibs\DB\IO public function adbByteStringFormat($number): string { trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED); - return $this->byteStringFormat($number); + return $this->humanReadableByteFormat($number); } /** diff --git a/www/lib/CoreLibs/Basic.php b/www/lib/CoreLibs/Basic.php index aa4d4dd1..3ea5bb20 100644 --- a/www/lib/CoreLibs/Basic.php +++ b/www/lib/CoreLibs/Basic.php @@ -100,6 +100,10 @@ class Basic // define check vars for the flags we can have const CLASS_STRICT_MODE = 1; const CLASS_OFF_COMPATIBLE_MODE = 2; + // define byteFormat + const BYTE_FORMAT_NOSPACE = 1; + const BYTE_FORMAT_ADJUST = 2; + const BYTE_FORMAT_SI = 4; // control vars /** @var bool compatible mode sets variable even if it is not defined */ private $set_compatible = true; @@ -1592,20 +1596,117 @@ class Basic } /** + * WRAPPER call to new humanReadableByteFormat * converts bytes into formated string with KB, MB, etc - * @param string|int|float $number bytes as string int or pure int - * @param bool $space true (default) to add space between number and suffix + * @param string|int|float $bytes bytes as string int or pure int + * @param bool $space default true, to add space between number and suffix + * @param bool $adjust default false, always print two decimals (sprintf) + * @param bool $si default false, if set to true, use 1000 for calculation * @return string converted byte number (float) with suffix + * @deprecated Use humanReadableByteFormat instead */ - public static function byteStringFormat($number, bool $space = true): string + public static function byteStringFormat($bytes, bool $space = true, bool $adjust = false, bool $si = false): string { - if (is_numeric($number) && $number > 0) { - // labels in order of size - $labels = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'); - // calc file size, round down too two digits, add label based max change - return round((float)$number / pow(1024, ($i = floor(log((float)$number, 1024)))), 2).($space ? ' ' : '').(isset($labels[(int)$i]) ? $labels[(int)$i] : '>EB'); + // trigger_error('Method '.__METHOD__.' is deprecated, use humanReadableByteFormat', E_USER_DEPRECATED); + $flags = 0; + // match over the true/false flags to the new int style flag + // if space need to set 1 + if ($space === false) { + $flags |= self::BYTE_FORMAT_NOSPACE; + } + // if adjust need to set 2 + if ($adjust === true) { + $flags |= self::BYTE_FORMAT_ADJUST; + } + // if si need to set 3 + if ($si === true) { + $flags |= self::BYTE_FORMAT_SI; + } + + // call + return self::humanReadableByteFormat($bytes, $flags); + } + + + /** + * 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 extension + * BYTE_FORMAT_ADJUST [2] use sprintf to always print two decimals + * BYTE_FORMAT_SI [3] 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 + * @return string converted byte number (float) with suffix + */ + public static function humanReadableByteFormat($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; + } + + // si or normal + $unit = $si ? 1000 : 1024; + // always positive + $abs_bytes = $bytes == PHP_INT_MIN ? PHP_INT_MAX : abs($bytes); + // smaller than unit is always B + if ($abs_bytes < $unit) { + return $bytes.'B'; + } + // labels in order of size [Y, Z] + $labels = array('', 'K', 'M', 'G', 'T', 'P', 'E'); + // exp position calculation + $exp = 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 ? ' ' : '').(isset($labels[$exp]) ? $labels[$exp] : '>E').($si ? 'i' : '').'B'; + $bytes_calc = $abs_bytes / pow($unit, $exp); + if ($adjust) { + return sprintf("%.2f%sB", $bytes_calc, $pre); + } else { + return round($bytes_calc, 2).$pre; + } + } else { + // if anything other return as string + return (string)$bytes; } - return (string)$number; } /**