7) { throw new \Exception("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 = 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 \Exception 1: no valid flag set */ public static function stringByteFormat($number, int $flags = 0) { // 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 \Exception("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__