I'm asking how to convert KB MB GB TB & co. into bytes.
For example:
byteconvert("10KB") // => 10240
byteconvert("10.5KB") // => 10752
byteconvert("1GB") // => 1073741824
byteconvert("1TB") // => 1099511627776
and so on...
EDIT: wow. I've asked this question over 4 years ago. Thise kind of things really show you how much you've improved over time!
Here's a function to achieve this:
function convertToBytes(string $from): ?int {
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
$number = substr($from, 0, -2);
$suffix = strtoupper(substr($from,-2));
//B or no suffix
if(is_numeric(substr($suffix, 0, 1))) {
return preg_replace('/[^\d]/', '', $from);
}
$exponent = array_flip($units)[$suffix] ?? null;
if($exponent === null) {
return null;
}
return $number * (1024 ** $exponent);
}
$testCases = ["13", "13B", "13KB", "10.5KB", "123Mi"];
var_dump(array_map('convertToBytes', $testCases));
Output:
array(5) { [0]=> int(13) [1]=> int(13) [2]=> int(13312) [3]=>
int(10752) [4]=> NULL } int(1)
function toByteSize($p_sFormatted) {
$aUnits = array('B'=>0, 'KB'=>1, 'MB'=>2, 'GB'=>3, 'TB'=>4, 'PB'=>5, 'EB'=>6, 'ZB'=>7, 'YB'=>8);
$sUnit = strtoupper(trim(substr($p_sFormatted, -2)));
if (intval($sUnit) !== 0) {
$sUnit = 'B';
}
if (!in_array($sUnit, array_keys($aUnits))) {
return false;
}
$iUnits = trim(substr($p_sFormatted, 0, strlen($p_sFormatted) - 2));
if (!intval($iUnits) == $iUnits) {
return false;
}
return $iUnits * pow(1024, $aUnits[$sUnit]);
}
Here's what I've come up with so far, that I think is a much more elegant solution:
/**
* Converts a human readable file size value to a number of bytes that it
* represents. Supports the following modifiers: K, M, G and T.
* Invalid input is returned unchanged.
*
* Example:
* <code>
* $config->human2byte(10); // 10
* $config->human2byte('10b'); // 10
* $config->human2byte('10k'); // 10240
* $config->human2byte('10K'); // 10240
* $config->human2byte('10kb'); // 10240
* $config->human2byte('10Kb'); // 10240
* // and even
* $config->human2byte(' 10 KB '); // 10240
* </code>
*
* #param number|string $value
* #return number
*/
public function human2byte($value) {
return preg_replace_callback('/^\s*(\d+)\s*(?:([kmgt]?)b?)?\s*$/i', function ($m) {
switch (strtolower($m[2])) {
case 't': $m[1] *= 1024;
case 'g': $m[1] *= 1024;
case 'm': $m[1] *= 1024;
case 'k': $m[1] *= 1024;
}
return $m[1];
}, $value);
}
I use a function to determine the memory limit set for PHP in some cron scripts that looks like:
$memoryInBytes = function ($value) {
$unit = strtolower(substr($value, -1, 1));
return (int) $value * pow(1024, array_search($unit, array(1 =>'k','m','g')));
}
A similar approach that will work better with floats and accept the two letter abbreviation would be something like:
function byteconvert($value) {
preg_match('/(.+)(.{2})$/', $value, $matches);
list($_,$value,$unit) = $matches;
return (int) ($value * pow(1024, array_search(strtolower($unit), array(1 => 'kb','mb','gb','tb'))));
}
Wanting something similar to this and not quite liking the other solutions posted here for various reasons, I decided to write my own function:
function ConvertUserStrToBytes($str)
{
$str = trim($str);
$num = (double)$str;
if (strtoupper(substr($str, -1)) == "B") $str = substr($str, 0, -1);
switch (strtoupper(substr($str, -1)))
{
case "P": $num *= 1024;
case "T": $num *= 1024;
case "G": $num *= 1024;
case "M": $num *= 1024;
case "K": $num *= 1024;
}
return $num;
}
It adapts a few of the ideas presented here by Al Jey (whitespace handling) and John V (switch-case) but without the regex, doesn't call pow(), lets switch-case do its thing when there aren't breaks, and can handle some weird user inputs (e.g. " 123 wonderful KB " results in 125952). I'm sure there is a more optimal solution that involves fewer instructions but the code would be less clean/readable.
<?php
function byteconvert($input)
{
preg_match('/(\d+)(\w+)/', $input, $matches);
$type = strtolower($matches[2]);
switch ($type) {
case "b":
$output = $matches[1];
break;
case "kb":
$output = $matches[1]*1024;
break;
case "mb":
$output = $matches[1]*1024*1024;
break;
case "gb":
$output = $matches[1]*1024*1024*1024;
break;
case "tb":
$output = $matches[1]*1024*1024*1024;
break;
}
return $output;
}
$foo = "10mb";
echo "$foo = ".byteconvert($foo)." byte";
?>
Based on https://stackoverflow.com/a/17364338/1041470
Improvements:
Fixed bug with bytes suffix length,
Allowed to use double (float) values but only integers,
Reverted array which holds units,
Renamed variables,
Added comments.
/**
* Converts human readable file size into bytes.
*
* Note: This is 1024 based version which assumes that a 1 KB has 1024 bytes.
* Based on https://stackoverflow.com/a/17364338/1041470
*
* #param string $from
* Required. Human readable size (file, memory or traffic).
* For example: '5Gb', '533Mb' and etc.
* Allowed integer and float values. Eg., 10.64GB.
*
* #return int
* Returns given size in bytes.
*/
function cm_common_convert_to_bytes(string $from): ?int {
static $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
$from = trim($from);
// Get suffix.
$suffix = strtoupper(trim(substr($from, -2)));
// Check one char suffix 'B'.
if (intval($suffix) !== 0) {
$suffix = 'B';
}
if (!in_array($suffix, $units)) {
return FALSE;
}
$number = trim(substr($from, 0, strlen($from) - strlen($suffix)));
if (!is_numeric($number)) {
// Allow only float and integer. Strings produces '0' which is not corect.
return FALSE;
}
return (int) ($number * pow(1024, array_flip($units)[$suffix]));
}
I was just looking for this function and took on the challenge to try to improve in it and got it to TWO lines :) Uses a similar regex to Eugene's to validate/extract values, but avoids the switch statement. Can accept long '10MB','10mb' and short '10M','10m' values, decimal values and always returns an integer. Invalid strings return 0
function to_bytes( $str )
{
if( ! preg_match('/^([\d.]+)([BKMGTPE]?)(B)?$/i', trim($str), $m) ) return 0;
return (int) floor($m[1] * ( $m[2] ? (1024**strpos('BKMGTPE', strtoupper($m[2]))) : 1 ));
}
One more solution (IEC):
<?php
class Filesize
{
const UNIT_PREFIXES_POWERS = [
'B' => 0,
'' => 0,
'K' => 1,
'k' => 1,
'M' => 2,
'G' => 3,
'T' => 4,
'P' => 5,
'E' => 6,
'Z' => 7,
'Y' => 8,
];
public static function humanize($size, int $precision = 2, bool $useBinaryPrefix = false)
{
$base = $useBinaryPrefix ? 1024 : 1000;
$limit = array_values(self::UNIT_PREFIXES_POWERS)[count(self::UNIT_PREFIXES_POWERS) - 1];
$power = ($_ = floor(log($size, $base))) > $limit ? $limit : $_;
$prefix = array_flip(self::UNIT_PREFIXES_POWERS)[$power];
$multiple = ($useBinaryPrefix ? strtoupper($prefix) . 'iB' : $prefix . 'B');
return round($size / pow($base, $power), $precision) . $multiple;
}
// ...
}
Source:
https://github.com/mingalevme/utils/blob/master/src/Filesize.php
https://github.com/mingalevme/utils/blob/master/tests/FilesizeTest.php
I know this is a relative old topic, but here's a function that I sometimes have to use when I need this kind of stuff; You may excuse for if the functions dont work, I wrote this for hand in a mobile:
function intobytes($bytes, $stamp = 'b') {
$indx = array_search($stamp, array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'yb'));
if ($indx > 0) {
return $bytes * pow(1024, $indx);
}
return $bytes;
}
and as compact
function intobytes($bytes, $stamp='b') {$indx=array_search($stamp,array('b','kb','mb','gb','tb','pb','yb'));if($indx > 0){return $bytes * pow(1024,$indx);} return $bytes;}
Take care!
Brodde85 ;)
Here is a little more cleaned version according to the standards (Using answer above):
/**
* Format kb, mb, gb, tb to bytes
*
* #param integer $size
* #return integer
*/
function formatToBytes ($size)
{
$aUnits = array('bytes' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4);
$sUnit = strtoupper(trim(substr($size, -2)));
if (intval($sUnit) !== 0) {
$sUnit = 'bytes';
}
if (!in_array($sUnit, array_keys($aUnits))) {
return false;
}
$iUnits = trim(substr($size, 0, strlen($size) - 2));
if (!intval($iUnits) == $iUnits) {
return false;
}
return $iUnits * pow(1024, $aUnits[$sUnit]);
}
Related
I was adding a modification for my phpBB3 discussion board and one of the steps was to add a line of code to includes/functions.php
So when I copied that file and opened in wordpad I saw that it looked all scrambled. Here is how it looks partly:
<?php /** * * #package phpBB3 * #version $Id$ * #copyright (c) 2005 phpBB Group * #license http://opensource.org/licenses/gpl-license.php GNU Public License * */ /** * #ignore */ if (!defined('IN_PHPBB')) { exit; } // Common global functions /** * set_var * * Set variable, used by {#link request_var the request_var function} * * #access private */ function set_var(&$result, $var, $type, $multibyte = false) { settype($var, $type); $result = $var; if ($type == 'string') { $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result), ENT_COMPAT, 'UTF-8')); if (!empty($result)) { // Make sure multibyte characters are wellformed if ($multibyte) { if (!preg_match('/^./u', $result)) { $result = ''; } } else { // no multibyte, allow only ASCII (0-127) $result = preg_replace('/[\x80-\xFF]/', '?', $result); } } $result = (STRIP) ? stripslashes($result) : $result; } } /** * request_var * * Used to get passed variable */ function request_var($var_name, $default, $multibyte = false, $cookie = false) { if (!$cookie && isset($_COOKIE[$var_name])) { if (!isset($_GET[$var_name]) && !isset($_POST[$var_name])) { return (is_array($default)) ? array() : $default; } $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name]; } $super_global = ($cookie) ? '_COOKIE' : '_REQUEST'; if (!isset($GLOBALS[$super_global][$var_name]) || is_array($GLOBALS[$super_global][$var_name]) != is_array($default)) { return (is_array($default)) ? array() : $default; } $var = $GLOBALS[$super_global][$var_name]; if (!is_array($default)) { $type = gettype($default); } else { list($key_type, $type) = each($default); $type = gettype($type); $key_type = gettype($key_type); if ($type == 'array') { reset($default); $default = current($default); list($sub_key_type, $sub_type) = each($default); $sub_type = gettype($sub_type); $sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type; $sub_key_type = gettype($sub_key_type); } } if (is_array($var)) { $_var = $var; $var = array(); foreach ($_var as $k => $v) { set_var($k, $k, $key_type); if ($type == 'array' && is_array($v)) { foreach ($v as $_k => $_v) { if (is_array($_v)) { $_v = null; } set_var($_k, $_k, $sub_key_type, $multibyte); set_var($var[$k][$_k], $_v, $sub_type, $multibyte); } } else { if ($type == 'array' || is_array($v)) { $v = null; } set_var($var[$k], $v, $type, $multibyte); } } } else { set_var($var, $var, $type, $multibyte); } return $var; } /** * Set config value. Creates missing config entry. */ function set_config($config_name, $config_value, $is_dynamic = false) { global $db, $cache, $config; $sql = 'UPDATE ' . CONFIG_TABLE . " SET config_value = '" . $db->sql_escape($config_value) . "' WHERE config_name = '" . $db->sql_escape($config_name) . "'"; $db->sql_query($sql); if (!$db->sql_affectedrows() && !isset($config[$config_name])) { $sql = 'INSERT INTO ' . CONFIG_TABLE . ' ' . $db->sql_build_array('INSERT', array( 'config_name' => $config_name, 'config_value' => $config_value, 'is_dynamic' => ($is_dynamic) ? 1 : 0)); $db->sql_query($sql); } $config[$config_name] = $config_value; if (!$is_dynamic) { $cache->destroy('config'); } } /** * Set dynamic config value with arithmetic operation. */ function set_config_count($config_name, $increment, $is_dynamic = false) { global $db, $cache; switch ($db->sql_layer) { case 'firebird': case 'postgres': $sql_update = 'CAST(CAST(config_value as DECIMAL(255, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; break; // MySQL, SQlite, mssql, mssql_odbc, oracle default: $sql_update = 'config_value + ' . (int) $increment; break; } $db->sql_query('UPDATE ' . CONFIG_TABLE . ' SET config_value = ' . $sql_update . " WHERE config_name = '" . $db->sql_escape($config_name) . "'"); if (!$is_dynamic) { $cache->destroy('config'); } } /** * Generates an alphanumeric random string of given length * * #return string */ function gen_rand_string($num_chars = 8) { // [a, z] + [0, 9] = 36 return substr(strtoupper(base_convert(unique_id(), 16, 36)), 0, $num_chars); } /** * Generates a user-friendly alphanumeric random string of given length * We remove 0 and O so users cannot confuse those in passwords etc. * * #return string */ function gen_rand_string_friendly($num_chars = 8) { $rand_str = unique_id(); // Remove Z and Y from the base_convert(), replace 0 with Z and O with Y // [a, z] + [0, 9] - {z, y} = [a, z] + [0, 9] - {0, o} = 34 $rand_str = str_replace(array('0', 'O'), array('Z', 'Y'), strtoupper(base_convert($rand_str, 16, 34))); return substr($rand_str, 0, $num_chars); } /** * Return unique id * #param string $extra additional entropy */ function unique_id($extra = 'c') { static $dss_seeded = false; global $config; $val = $config['rand_seed'] . microtime(); $val = md5($val); $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra); if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10))) { set_config('rand_seed', $config['rand_seed'], true); set_config('rand_seed_last_update', time(), true); $dss_seeded = true; } return substr($val, 4, 16); } /** * Return formatted string for filesizes * * #param int $value filesize in bytes * #param bool $string_only true if language string should be returned * #param array $allowed_units only allow these units (data array indexes) * * #return mixed data array if $string_only is false * #author bantu */ function get_formatted_filesize($value, $string_only = true, $allowed_units = false) { global $user; $available_units = array( 'gb' => array( 'min' => 1073741824, // pow(2, 30) 'index' => 3, 'si_unit' => 'GB', 'iec_unit' => 'GIB', ), 'mb' => array( 'min' => 1048576, // pow(2, 20) 'index' => 2, 'si_unit' => 'MB', 'iec_unit' => 'MIB', ), 'kb' => array( 'min' => 1024, // pow(2, 10) 'index' => 1, 'si_unit' => 'KB', 'iec_unit' => 'KIB', ), 'b' => array( 'min' => 0, 'index' => 0, 'si_unit' => 'BYTES', // Language index 'iec_unit' => 'BYTES', // Language index ), ); foreach ($available_units as $si_identifier => $unit_info) { if (!empty($allowed_units) && $si_identifier != 'b' && !in_array($si_identifier, $allowed_units)) { continue; } if ($value >= $unit_info['min']) { $unit_info['si_identifier'] = $si_identifier; break; } } unset($available_units); for ($i = 0; $i < $unit_info['index']; $i++) { $value /= 1024; } $value = round($value, 2); // Lookup units in language dictionary $unit_info['si_unit'] = (isset($user->lang[$unit_info['si_unit']])) ? $user->lang[$unit_info['si_unit']] : $unit_info['si_unit']; $unit_info['iec_unit'] = (isset($user->lang[$unit_info['iec_unit']])) ? $user->lang[$unit_info['iec_unit']] : $unit_info['iec_unit']; // Default to IEC $unit_info['unit'] = $unit_info['iec_unit']; if (!$string_only) { $unit_info['value'] = $value; return $unit_info; } return $value . ' ' . $unit_info['unit']; } /** * Determine whether we are approaching the maximum execution time. Should be called once * at the beginning of the script in which it's used. * #return bool Either true if the maximum execution time is nearly reached, or false * if some time is still left. */ function still_on_time($extra_time = 15) { static $max_execution_time, $start_time; $time = explode(' ', microtime()); $current_time = $time[0] + $time[1]; if (empty($max_execution_time)) { $max_execution_time = (function_exists('ini_get')) ? (int) #ini_get('max_execution_time') : (int) #get_cfg_var('max_execution_time'); // If zero, then set to something higher to not let the user catch the ten seconds barrier. if ($max_execution_time === 0) { $max_execution_time = 50 + $extra_time; } $max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50); // For debugging purposes // $max_execution_time = 10; global $starttime; $start_time = (empty($starttime)) ? $current_time : $starttime; } return (ceil($current_time - $start_time) < $max_execution_time) ? true : false; } /** * * #version Version 0.1 / slightly modified for phpBB 3.0.x (using $H$ as hash type identifier) * * Portable PHP password hashing framework. * * Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in * the public domain. * * There's absolutely no warranty. * * The homepage URL for this framework is: * * http://www.openwall.com/phpass/ * * Please be sure to update the Version line if you edit this file in any way. * It is suggested that you leave the main version number intact, but indicate * your project name (after the slash) and add your own revision information. * * Please do not change the "private" password hashing method implemented in * here, thereby making your hashes incompatible. However, if you must, please * change the hash type identifier (the "$P$") to something different. * * Obviously, since this code is in the public domain, the above are not * requirements (there can be none), but merely suggestions. * * * Hash the password */ function phpbb_hash($password) { $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; $random_state = unique_id(); $random = ''; $count = 6; if (($fh = #fopen('/dev/urandom', 'rb'))) { $random = fread($fh, $count); fclose($fh); } if (strlen($random) < $count) { $random = ''; for ($i = 0; $i < $count; $i += 16) { $random_state = md5(unique_id() . $random_state); $random .= pack('H*', md5($random_state)); } $random = substr($random, 0, $count); } $hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64); if (strlen($hash) == 34) { return $hash; } return md5($password); } /** * Check for correct password * * #param string $password The password in plain text * #param string $hash The stored password hash * * #return bool Returns true if the password is correct, false if not. */ function phpbb_check_hash($password, $hash) { $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; if (strlen($hash) == 34) { return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false; } return (md5($password) === $hash) ? true : false; } /** * Generate salt for hash generation */ function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) { if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) { $iteration_count_log2 = 8; } $output = '$H$'; $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)]; $output .= _hash_encode64($input, 6, $itoa64); return $output; } /** * Encode hash */ function _hash_encode64($input, $count, &$itoa64) { $output = ''; $i = 0; do { $value = ord($input[$i++]); $output .= $itoa64[$value & 0x3f]; if ($i < $count) { $value |= ord($input[$i]) << 8; } $output .= $itoa64[($value >> 6) & 0x3f]; if ($i++ >= $count) { break; } if ($i < $count) { $value |= ord($input[$i]) << 16; } $output .= $itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) { break; } $output .= $itoa64[($value >> 18) & 0x3f]; } while ($i < $count); return $output; } /** * The crypt function/replacement */ function _hash_crypt_private($password, $setting, &$itoa64) { $output = '*'; // Check for correct hash if (substr($setting, 0, 3) != '$H$') { return $output; } $count_log2 = strpos($itoa64, $setting[3]); if ($count_log2 < 7 || $count_log2 > 30) { return $output; } $count = 1 << $count_log2; $salt = substr($setting, 4, 8); if (strlen($salt) != 8) { return $output; } /** * We're kind of forced to use MD5 here since it's the only * cryptographic primitive available in all versions of PHP * currently in use. To implement our own low-level crypto * in PHP would result in much worse performance and * consequently in lower iteration counts and hashes that are * quicker to crack (by non-PHP code). */ if (PHP_VERSION >= 5) { $hash = md5($salt . $password, true); do { $hash = md5($hash . $password, true); } while (--$count); } else { $hash = pack('H*', md5($salt . $password)); do { $hash = pack('H*', md5($hash . $password)); } while (--$count); } $output = substr($setting, 0, 12); $output .= _hash_encode64($hash, 16, $itoa64); return $output; } /** * Hashes an email address to a big integer * * #param string $email Email address * * #return string Unsigned Big Integer */ function phpbb_email_hash($email) { return sprintf('%u', crc32(strtolower($email))) . strlen($email); } /** * Global function for chmodding directories and files for internal use * * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions. * The function determines owner and group from common.php file and sets the same to the provided file. * The function uses bit fields to build the permissions. * The function sets the appropiate execute bit on directories. * * Supported constants representing bit fields are: * * CHMOD_ALL - all permissions (7) * CHMOD_READ - read permission (4) * CHMOD_WRITE - write permission (2) * CHMOD_EXECUTE - execute permission (1) * * NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions. * * #param string $filename The file/directory to be chmodded * #param int $perms Permissions to set * * #return bool true on success, otherwise false * #author faw, phpBB Group */ function phpbb_chmod($filename, $perms = CHMOD_READ) { static $_chmod_info; // Return if the file no longer exists. if (!file_exists($filename)) { return false; } // Determine some common vars if (empty($_chmod_info)) { if (!function_exists('fileowner') || !function_exists('filegroup')) { // No need to further determine owner/group - it is unknown $_chmod_info['process'] = false; } else { global $phpbb_root_path, $phpEx; // Determine owner/group of common.php file and the filename we want to change here $common_php_owner = #fileowner($phpbb_root_path . 'common.' . $phpEx); $common_php_group = #filegroup($phpbb_root_path . 'common.' . $phpEx); // And the owner and the groups PHP is running under. $php_uid = (function_exists('posix_getuid')) ? #posix_getuid() : false; $php_gids = (function_exists('posix_getgroups')) ? #posix_getgroups() : false; // If we are unable to get owner/group, then do not try to set them by guessing if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group) { $_chmod_info['process'] = false; } else { $_chmod_info = array( 'process' => true, 'common_owner' => $common_php_owner, 'common_group' => $common_php_group, 'php_uid' => $php_uid, 'php_gids' => $php_gids, ); } } } if ($_chmod_info['process']) { $file_uid = #fileowner($filename); $file_gid = #filegroup($filename); // Change owner if (#chown($filename, $_chmod_info['common_owner'])) { clearstatcache(); $file_uid = #fileowner($filename); } // Change group if (#chgrp($filename, $_chmod_info['common_group'])) { clearstatcache(); $file_gid = #filegroup($filename); } // If the file_uid/gid now match the one from common.php we can process further, else we are not able to change something if ($file_uid != $_chmod_info['common_owner'] || $file_gid != $_chmod_info['common_group']) { $_chmod_info['process'] = false; } } // Still able to process? if ($_chmod_info['process']) { if ($file_uid == $_chmod_info['php_uid']) { $php = 'owner'; } else if (in_array($file_gid, $_chmod_info['php_gids'])) { $php = 'group'; } else { // Since we are setting the everyone bit anyway, no need to do expensive operations $_chmod_info['process'] = false; } } // We are not able to determine or change something if (!$_chmod_info['process']) { $php = 'other'; } // Owner always has read/write permission $owner = CHMOD_READ | CHMOD_WRITE; if (is_dir($filename)) { $owner |= CHMOD_EXECUTE; // Only add execute bit to the permission if the dir needs to be readable if ($perms & CHMOD_READ) { $perms |= CHMOD_EXECUTE; } } switch ($php) { case 'owner': $result = #chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0)); clearstatcache(); if (is_readable($filename) && phpbb_is_writable($filename)) { break; } case 'group': $result = #chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0)); clearstatcache(); if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename))) { break; } case 'other': $result = #chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0)); clearstatcache(); if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename))) { break; } default: return false; break; } return $result; } /** * Test if a file/directory is writable * * This function calls the native is_writable() when not running under * Windows and it is not disabled. * * #param string $file Path to perform write test on * #return bool True when the path is writable, otherwise false. */ function phpbb_is_writable($file) { if (strtolower(substr(PHP_OS, 0, 3)) === 'win' || !function_exists('is_writable')) { if (file_exists($file)) { // Canonicalise path to absolute path $file = phpbb_realpath($file); if (is_dir($file)) { // Test directory by creating a file inside the directory $result = #tempnam($file, 'i_w'); if (is_string($result) && file_exists($result)) { unlink($result); // Ensure the file is actually in the directory (returned realpathed) return (strpos($result, $file) === 0) ? true : false; } } else { $handle = #fopen($file, 'r+'); if (is_resource($handle)) { fclose($handle); return true; } } } else { // file does not exist test if we can write to the directory $dir = dirname($file); if (file_exists($dir) && is_dir($dir) && phpbb_is_writable($dir)) { return true; } } return false; } else { return is_writable($file); } } // Compatibility functions if (!function_exists('array_combine')) { /** * A wrapper for the PHP5 function array_combine() * #param array $keys contains keys for the resulting array * #param array $values contains values for the resulting array * * #return Returns an array by using the values from the keys array as keys and the * values from the values array as the corresponding values. Returns false if the * number of elements for each array isn't equal or if the arrays are empty. */ function array_combine($keys, $values) { $keys = array_values($keys); $values = array_values($values); $n = sizeof($keys); $m = sizeof($values); if (!$n || !$m || ($n != $m)) { return false; } $combined = array(); for ($i = 0; $i < $n; $i++) { $combined[$keys[$i]] = $values[$i]; } return $combined; } } if (!function_exists('str_split')) { /** * A wrapper for the PHP5 function str_split() * #param array $string contains the string to be converted * #param array $split_length contains the length of each chunk * * #return Converts a string to an array. If the optional split_length parameter is specified, * the returned array will be broken down into
As you can see all the new lines are cut so its just a big mess. I did still add the new code and it messed everything up. What can I do? Is there some type of script or anything that I can run this php file through that will fix lines? Note that I have no experience with PHP so please be detailed in your reply!
Both WordPad and Notepad++ handle UNIX-style newlines fine. I'm guessing that you or someone else previously opened and saved it with another program such as Notepad, which doesn't understand such newlines and probably messed it up. If you haven't modified the file so far, the simplest solution might be to get a fresh copy of this file from the phpBB3 archive.
The file was probably created in *Nix, and uses the Unix newlines. Wordpad likely can't handle those.
Try opening it up with a program that can handle the different types of newline styles, like Notepad++.
http://beta.phpformatter.com/
This will make your code look better.
See the other solutions or try:
<?php
file_put_contents("source-fixed.php",
str_replace("\n", "\r\n", file_get_contents("source.php")));
?>
Adjust the file names accordingly, of course.
How can I check if a given number is within a range of numbers?
The expression:
($min <= $value) && ($value <= $max)
will be true if $value is between $min and $max, inclusively
See the PHP docs for more on comparison operators
You can use filter_var
filter_var(
$yourInteger,
FILTER_VALIDATE_INT,
array(
'options' => array(
'min_range' => $min,
'max_range' => $max
)
)
);
This will also allow you to specify whether you want to allow octal and hex notation of integers. Note that the function is type-safe. 5.5 is not an integer but a float and will not validate.
Detailed tutorial about filtering data with PHP:
https://phpro.org/tutorials/Filtering-Data-with-PHP.html
Might help:
if ( in_array(2, range(1,7)) ) {
echo 'Number 2 is in range 1-7';
}
http://php.net/manual/en/function.range.php
You could whip up a little helper function to do this:
/**
* Determines if $number is between $min and $max
*
* #param integer $number The number to test
* #param integer $min The minimum value in the range
* #param integer $max The maximum value in the range
* #param boolean $inclusive Whether the range should be inclusive or not
* #return boolean Whether the number was in the range
*/
function in_range($number, $min, $max, $inclusive = FALSE)
{
if (is_int($number) && is_int($min) && is_int($max))
{
return $inclusive
? ($number >= $min && $number <= $max)
: ($number > $min && $number < $max) ;
}
return FALSE;
}
And you would use it like so:
var_dump(in_range(5, 0, 10)); // TRUE
var_dump(in_range(1, 0, 1)); // FALSE
var_dump(in_range(1, 0, 1, TRUE)); // TRUE
var_dump(in_range(11, 0, 10, TRUE)); // FALSE
// etc...
if (($num >= $lower_boundary) && ($num <= $upper_boundary)) {
You may want to adjust the comparison operators if you want the boundary values not to be valid.
You can try the following one-statement:
if (($x-$min)*($x-$max) < 0)
or:
if (max(min($x, $max), $min) == $x)
Some other possibilities:
if (in_array($value, range($min, $max), true)) {
echo "You can be sure that $min <= $value <= $max";
}
Or:
if ($value === min(max($value, $min), $max)) {
echo "You can be sure that $min <= $value <= $max";
}
Actually this is what is use to cast a value which is out of the range to the closest end of it.
$value = min(max($value, $min), $max);
Example
/**
* This is un-sanitized user input.
*/
$posts_per_page = 999;
/**
* Sanitize $posts_per_page.
*/
$posts_per_page = min(max($posts_per_page, 5), 30);
/**
* Use.
*/
var_dump($posts_per_page); // Output: int(30)
using a switch case
switch ($num){
case ($num>= $value1 && $num<= $value2):
echo "within range 1";
break;
case ($num>= $value3 && $num<= $value4):
echo "within range 2";
break;
.
.
.
.
.
default: //default
echo "within no range";
break;
}
I've created a simple helper function.
if ( !function_exists('number_between') )
{
/**
* number_between
*
* #param {integer} $number
* #param {array} $range [min, max]
* #return {boolean}
*/
function number_between(
int $number,
array $range
){
if(
count($range) !== 2 ||
is_numeric($range[0]) === FALSE ||
is_numeric($range[1]) === FALSE
){
throw new \Exception("number_between second parameter must contain two numbers.", E_WARNING);
}
if(
in_array($number, range($range[0], $range[1]))
){
return TRUE;
}else{
return FALSE;
}
}
}
Another way to do this with simple if/else range. For ex:
$watermarkSize = 0;
if (($originalImageWidth >= 0) && ($originalImageWidth <= 640)) {
$watermarkSize = 10;
} else if (($originalImageWidth >= 641) && ($originalImageWidth <= 1024)) {
$watermarkSize = 25;
} else if (($originalImageWidth >= 1025) && ($originalImageWidth <= 2048)) {
$watermarkSize = 50;
} else if (($originalImageWidth >= 2049) && ($originalImageWidth <= 4096)) {
$watermarkSize = 100;
} else {
$watermarkSize = 200;
}
I created a function to check if times in an array overlap somehow:
/**
* Function to check if there are overlapping times in an array of \DateTime objects.
*
* #param $ranges
*
* #return \DateTime[]|bool
*/
public function timesOverlap($ranges) {
foreach ($ranges as $k1 => $t1) {
foreach ($ranges as $k2 => $t2) {
if ($k1 != $k2) {
/* #var \DateTime[] $t1 */
/* #var \DateTime[] $t2 */
$a = $t1[0]->getTimestamp();
$b = $t1[1]->getTimestamp();
$c = $t2[0]->getTimestamp();
$d = $t2[1]->getTimestamp();
if (($c >= $a && $c <= $b) || $d >= $a && $d <= $b) {
return true;
}
}
}
}
return false;
}
Here is my little contribution:
function inRange($number) {
$ranges = [0, 13, 17, 24, 34, 44, 54, 65, 200];
$n = count($ranges);
while($n--){
if( $number > $ranges[$n] )
return $ranges[$n]+1 .'-'. $ranges[$n + 1];
}
I have function for my case
Use:
echo checkRangeNumber(0);
echo checkRangeNumber(1);
echo checkRangeNumber(499);
echo checkRangeNumber(500);
echo checkRangeNumber(501);
echo checkRangeNumber(3001);
echo checkRangeNumber(999);
//return
0
1-500
1-500
1-500
501-1000
3000-3500
501-1000
function checkRangeNumber($number, $per_page = 500)
{
//$per_page = 500; // it's fixed number, but...
if ($number == 0) {
return "0";
}
$num_page = ceil($number / $per_page); // returns 65
$low_limit = ($num_page - 1) * $per_page + 1; // returns 32000
$up_limit = $num_page * $per_page; // returns 40
return "$low_limit-$up_limit";
}
function limit_range($num, $min, $max)
{
// Now limit it
return $num>$max?$max:$num<$min?$min:$num;
}
$min = 0; // Minimum number can be
$max = 4; // Maximum number can be
$num = 10; // Your number
// Number returned is limited to be minimum 0 and maximum 4
echo limit_range($num, $min, $max); // return 4
$num = 2;
echo limit_range($num, $min, $max); // return 2
$num = -1;
echo limit_range($num, $min, $max); // return 0
$ranges = [
1 => [
'min_range' => 0.01,
'max_range' => 199.99
],
2 => [
'min_range' => 200.00,
],
];
foreach($ranges as $value => $range){
if(filter_var($cartTotal, FILTER_VALIDATE_FLOAT, ['options' => $range])){
return $value;
}
}
Thank you so much and I got my answer by adding a break in the foreach loop and now it is working fine.
Here are the updated answer:
foreach ($this->crud->getDataAll('shipping_charges') as $ship) {
if ($weight >= $ship->low && $weight <= $ship->high) {
$val = $ship->amount;
break;
}
else
{
$val = 900;
}
}
echo $val ;
What does "6k views" mean and how can I format this number in PHP?
k is the abbreviation for the Kilo prefix and means thousand. So 6k means six thousand.
You can format a number in such a way with the following function using division:
function format($number) {
$prefixes = 'kMGTPEZY';
if ($number >= 1000) {
for ($i=-1; $number>=1000; ++$i) {
$number /= 1000;
}
return floor($number).$prefixes[$i];
}
return $number;
}
Or using logarithm base 10 and exponentiation:
function format($number) {
$prefixes = 'kMGTPEZY';
if ($number >= 1000) {
$log1000 = floor(log10($number)/3);
return floor($number/pow(1000, $log1000)).$prefixes[$log1000-1];
}
return $number;
}
'6k views' on StackOverflow refers to the number of views a question has received. It means 6000 views.
If you're looking to format a similar style number in php then try something like
$number = "";
if( $value > 1000 )
{
$number .= floor($value / 1000) . "k";
} else {
$number .= $value;
}
echo $number . " views".
Obviously you can add cases for m, g and t views if desired.
Abridged from http://tamlyn.org/2008/12/formatting-bytes-with-significant-figures-in-php/
/** Calculate $value to $sigFigs significant figures */
function sigFig($value, $sigFigs = 3) {
//convert to scientific notation e.g. 12345 -> 1.2345x10^4
//where $significand is 1.2345 and $exponent is 4
$exponent = floor(log10(abs($value))+1);
$significand = round(($value
/ pow(10, $exponent))
* pow(10, $sigFigs))
/ pow(10, $sigFigs);
return $significand * pow(10, $exponent);
}
/** Format $value with the appropriate SI prefix symbol */
function format($value, $sigFigs = 3)
{
//SI prefix symbols
$units = array('', 'k', 'M', 'G', 'T', 'P', 'E');
//how many powers of 1000 in the value?
$index = floor(log10($value)/3);
$value = $index ? $value/pow(1000, $index) : $value;
return sigFig($value, $sigFigs) . $units[$index];
}
Doing *11 because *10 is too obvious
for($number = 100; $number < 100000000000000000000; $number*=11) {
echo format($number), PHP_EOL;
}
gives
100 1.1k 12.1k 133k 1.46M 16.1M 177M 1.95G 21.4G 236G 2.59T 28.5T 314T 3.45P 38P 418P 4.59E 50.5E
If you need the decimals, use the above, else Gumbo's solution is more compact. Gives:
100 1k 12k 133k 1M 16M 177M 1G 21G 235G 2T 28T 313T 3P 37P 417P 4E 50E
$number="6000";
$val=($number/1000)."k";
//= 6k
or if the $number="6k";
echo str_replace("k","000",$number);
In 6k, the k means kilo (i hope you know) which equals to 6000. You replace the thousand figure with k, that's it. Hope that helps :)
k means 1000, so '6k views' = 6000 views.
normally, on every access to a page, a counter in a database is increased by 1. This just gets queried on every page access and printed.
after you queried the value, divide it by 1000 and add a 'k' to the number (if the number is > 1000).
function sigFig($value, $sigFigs = 3) {
setlocale(LC_ALL, 'it_IT#euro', 'it_IT', 'it');
$exponent = floor(log10(abs($value))+1);
$significand = round(($value
/ pow(10, $exponent))
* pow(10, $sigFigs))
/ pow(10, $sigFigs);
return $significand * pow(10, $exponent);
}
function format($value, $sigFigs = 3)
{
$numero = $value;
if ($numero > 9999) {
$units = array('', 'k', 'M', 'G', 'T', 'P', 'E');
$index = floor(log10($value)/3);
$value = $index ? $value/pow(1000, $index) : $value;
return sigFig($value, $sigFigs) . $units[$index];
}else{
return number_format($numero, 0, '', '.'); ;
}
//Resultados:
//9999 -> 9.999 views
//10000 -> 10k views
//10200 -> 10,2k views
}
Scenario: the size of various files are stored in a database as bytes. What's the best way to format this size info to kilobytes, megabytes and gigabytes? For instance I have an MP3 that Ubuntu displays as "5.2 MB (5445632 bytes)". How would I display this on a web page as "5.2 MB" AND have files less than one megabyte display as KB and files one gigabyte and above display as GB?
function formatBytes($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
// Uncomment one of the following alternatives
// $bytes /= pow(1024, $pow);
// $bytes /= (1 << (10 * $pow));
return round($bytes, $precision) . ' ' . $units[$pow];
}
(Taken from php.net, there are many other examples there, but I like this one best :-)
This is Chris Jester-Young's implementation, cleanest I've ever seen, combined with php.net's and a precision argument.
function formatBytes($size, $precision = 2)
{
$base = log($size, 1024);
$suffixes = array('', 'K', 'M', 'G', 'T');
return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)];
}
echo formatBytes(24962496);
// 23.81M
echo formatBytes(24962496, 0);
// 24M
echo formatBytes(24962496, 4);
// 23.8061M
Pseudocode:
$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;
Just divide it by 1024 for kb, 1024^2 for mb and 1024^3 for GB. As simple as that.
This is Kohana's implementation, you could use it:
public static function bytes($bytes, $force_unit = NULL, $format = NULL, $si = TRUE)
{
// Format string
$format = ($format === NULL) ? '%01.2f %s' : (string) $format;
// IEC prefixes (binary)
if ($si == FALSE OR strpos($force_unit, 'i') !== FALSE)
{
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
$mod = 1024;
}
// SI prefixes (decimal)
else
{
$units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB');
$mod = 1000;
}
// Determine unit to use
if (($power = array_search((string) $force_unit, $units)) === FALSE)
{
$power = ($bytes > 0) ? floor(log($bytes, $mod)) : 0;
}
return sprintf($format, $bytes / pow($mod, $power), $units[$power]);
}
use this function if you want a short code
bcdiv()
$size = 11485760;
echo bcdiv($size, 1048576, 0); // return: 10
echo bcdiv($size, 1048576, 2); // return: 10,9
echo bcdiv($size, 1048576, 2); // return: 10,95
echo bcdiv($size, 1048576, 3); // return: 10,953
Just my alternative, short and clean:
/**
* #param int $bytes Number of bytes (eg. 25907)
* #param int $precision [optional] Number of digits after the decimal point (eg. 1)
* #return string Value converted with unit (eg. 25.3KB)
*/
function formatBytes($bytes, $precision = 2) {
$unit = ["B", "KB", "MB", "GB"];
$exp = floor(log($bytes, 1024)) | 0;
return round($bytes / (pow(1024, $exp)), $precision).$unit[$exp];
}
or, more stupid and efficent:
function formatBytes($bytes, $precision = 2) {
if ($bytes > pow(1024,3)) return round($bytes / pow(1024,3), $precision)."GB";
else if ($bytes > pow(1024,2)) return round($bytes / pow(1024,2), $precision)."MB";
else if ($bytes > 1024) return round($bytes / 1024, $precision)."KB";
else return ($bytes)."B";
}
I know it's maybe a little late to answer this question but, more data is not going to kill someone. Here's a very fast function :
function format_filesize($B, $D=2){
$S = 'BkMGTPEZY';
$F = floor((strlen($B) - 1) / 3);
return sprintf("%.{$D}f", $B/pow(1024, $F)).' '.#$S[$F].'B';
}
EDIT: I updated my post to include the fix proposed by camomileCase:
function format_filesize($B, $D=2){
$S = 'kMGTPEZY';
$F = floor((strlen($B) - 1) / 3);
return sprintf("%.{$D}f", $B/pow(1024, $F)).' '.#$S[$F-1].'B';
}
Simple function
function formatBytes($size, $precision = 0){
$unit = ['Byte','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
for($i = 0; $size >= 1024 && $i < count($unit)-1; $i++){
$size /= 1024;
}
return round($size, $precision).' '.$unit[$i];
}
echo formatBytes('1876144', 2);
//returns 1.79 MiB
Extremely simple function to get human file size.
Original source: http://php.net/manual/de/function.filesize.php#106569
Copy/paste code:
<?php
function human_filesize($bytes, $decimals = 2) {
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . #$sz[$factor];
}
?>
function convertToReadableSize($size)
{
$base = log($size) / log(1024);
$suffix = array("B", "KB", "MB", "GB", "TB");
$f_base = floor($base);
return round(pow(1024, $base - floor($base)), 1) . $suffix[$f_base];
}
Just call the function
echo convertToReadableSize(1024); // Outputs '1KB'
echo convertToReadableSize(1024 * 1024); // Outputs '1MB'
Flexible solution:
function size($size, array $options=null) {
$o = [
'binary' => false,
'decimalPlaces' => 2,
'decimalSeparator' => '.',
'thausandsSeparator' => '',
'maxThreshold' => false, // or thresholds key
'suffix' => [
'thresholds' => ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
'decimal' => ' {threshold}B',
'binary' => ' {threshold}iB',
'bytes' => ' B'
]
];
if ($options !== null)
$o = array_replace_recursive($o, $options);
$base = $o['binary'] ? 1024 : 1000;
$exp = $size ? floor(log($size) / log($base)) : 0;
if (($o['maxThreshold'] !== false) &&
($o['maxThreshold'] < $exp)
)
$exp = $o['maxThreshold'];
return !$exp
? (round($size) . $o['suffix']['bytes'])
: (
number_format(
$size / pow($base, $exp),
$o['decimalPlaces'],
$o['decimalSeparator'],
$o['thausandsSeparator']
) .
str_replace(
'{threshold}',
$o['suffix']['thresholds'][$exp],
$o['suffix'][$o['binary'] ? 'binary' : 'decimal']
)
);
}
var_dump(size(disk_free_space('/')));
// string(8) "14.63 GB"
var_dump(size(disk_free_space('/'), ['binary' => true]));
// string(9) "13.63 GiB"
var_dump(size(disk_free_space('/'), ['maxThreshold' => 2]));
// string(11) "14631.90 MB"
var_dump(size(disk_free_space('/'), ['binary' => true, 'maxThreshold' => 2]));
// string(12) "13954.07 MiB"
My approach
function file_format_size($bytes, $decimals = 2) {
$unit_list = array('B', 'KB', 'MB', 'GB', 'PB');
if ($bytes == 0) {
return $bytes . ' ' . $unit_list[0];
}
$unit_count = count($unit_list);
for ($i = $unit_count - 1; $i >= 0; $i--) {
$power = $i * 10;
if (($bytes >> $power) >= 1)
return round($bytes / (1 << $power), $decimals) . ' ' . $unit_list[$i];
}
}
I don't know why you should make it so complicated as the others.
The following code is much simpler to understand and about 25% faster than the other solutions who uses the log function (called the function 20 Mio. times with different parameters)
function formatBytes($bytes, $precision = 2) {
$units = ['Byte', 'Kilobyte', 'Megabyte', 'Gigabyte', 'Terabyte'];
$i = 0;
while($bytes > 1024) {
$bytes /= 1024;
$i++;
}
return round($bytes, $precision) . ' ' . $units[$i];
}
Here is an option using log10:
<?php
function format_number(float $d): string {
$e = (int)(log10($d) / 3);
return sprintf('%.3f', $d / 1e3 ** $e) . ['', ' k', ' M', ' G'][$e];
}
$s = format_number(9012345678);
var_dump($s == '9.012 G');
https://php.net/function.log10
My own implementation for getting formatted file size from integer size. Simple to understand and easy to extend to accommodate larger files - Just follow the pattern.
<?php
function getFormattedFileSize($size, $precision)
{
switch (true)
{
case ($size/1024 < 1):
return $size.'B';
case ($size/pow(1024, 2) < 1):
return round($size/1024, $precision).'KB';
case ($size/pow(1024, 3) < 1):
return round($size/pow(1024, 2), $precision).'MB';
case ($size/pow(1024, 4) < 1):
return round($size/pow(1024, 3), $precision).'GB';
case ($size/pow(1024, 5) < 1):
return round($size/pow(1024, 4), $precision).'TB';
default:
return 'Error: invalid input or file is too large.';
}
}
I succeeded with following function,
function format_size($size) {
$mod = 1024;
$units = explode(' ','B KB MB GB TB PB');
for ($i = 0; $size > $mod; $i++) {
$size /= $mod;
}
return round($size, 2) . ' ' . $units[$i];
}
try this ;)
function bytesToSize($bytes) {
$sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if ($bytes == 0) return 'n/a';
$i = intval(floor(log($bytes) / log(1024)));
if ($i == 0) return $bytes . ' ' . $sizes[$i];
return round(($bytes / pow(1024, $i)),1,PHP_ROUND_HALF_UP). ' ' . $sizes[$i];
}
echo bytesToSize(10000050300);
function changeType($size, $type, $end){
$arr = ['B', 'KB', 'MB', 'GB', 'TB'];
$tSayi = array_search($type, $arr);
$eSayi = array_search($end, $arr);
$pow = $eSayi - $tSayi;
return $size * pow(1024 * $pow) . ' ' . $end;
}
echo changeType(500, 'B', 'KB');
Albeit a bit stale, this library offers a tested and robust conversion API:
https://github.com/gabrielelana/byte-units
Once installed:
\ByteUnits\Binary::bytes(1024)->format();
// Output: "1.00KiB"
And to convert in the other direction:
\ByteUnits\Binary::parse('1KiB')->numberOfBytes();
// Output: "1024"
Beyond basic conversion, it offers methods for addition, subtraction, comparison, etc.
I am no way affiliated with this library.
I did this converting all input to byte and so converting to any output needed. Also, I used a auxiliar function to get base 1000 or 1024, but left it flex to decide use 1024 on popular type (without 'i', like MB instead of MiB).
public function converte_binario($size=0,$format_in='B',$format_out='MB',$force_in_1024=false,$force_out_1024=false,$precisao=5,$return_format=true,$decimal=',',$centena=''){
$out = false;
if( (is_numeric($size)) && ($size>0)){
$in_data = $this->converte_binario_aux($format_in,$force_in_1024);
$out_data = $this->converte_binario_aux($format_out,$force_out_1024);
// se formato de entrada e saĆda foram encontrados
if( ((isset($in_data['sucesso'])) && ($in_data['sucesso']==true)) && ((isset($out_data['sucesso'])) && ($out_data['sucesso']==true))){
// converte formato de entrada para bytes.
$size_bytes_in = $size * (pow($in_data['base'], $in_data['pot']));
$size_byte_out = (pow($out_data['base'], $out_data['pot']));
// transforma bytes na unidade de destino
$out = number_format($size_bytes_in / $size_byte_out,$precisao,$decimal,$centena);
if($return_format){
$out .= $format_out;
}
}
}
return $out;
}
public function converte_binario_aux($format=false,$force_1024=false){
$out = [];
$out['sucesso'] = false;
$out['base'] = 0;
$out['pot'] = 0;
if((is_string($format) && (strlen($format)>0))){
$format = trim(strtolower($format));
$units_1000 = ['b','kb' ,'mb' ,'gb' ,'tb' ,'pb' ,'eb' ,'zb' ,'yb' ];
$units_1024 = ['b','kib','mib','gib','tib','pib','eib','zib','yib'];
$pot = array_search($format,$units_1000);
if( (is_numeric($pot)) && ($pot>=0)){
$out['pot'] = $pot;
$out['base'] = 1000;
$out['sucesso'] = true;
}
else{
$pot = array_search($format,$units_1024);
if( (is_numeric($pot)) && ($pot>=0)){
$out['pot'] = $pot;
$out['base'] = 1024;
$out['sucesso'] = true;
}
}
if($force_1024){
$out['base'] = 1024;
}
}
return $out;
}
function byte_format($size) {
$bytes = array( ' KB', ' MB', ' GB', ' TB' );
foreach ($bytes as $val) {
if (1024 <= $size) {
$size = $size / 1024;
continue;
}
break;
}
return round( $size, 1 ) . $val;
}
Here is simplified implementation of the Drupal format_size function:
/**
* Generates a string representation for the given byte count.
*
* #param $size
* A size in bytes.
*
* #return
* A string representation of the size.
*/
function format_size($size) {
if ($size < 1024) {
return $size . ' B';
}
else {
$size = $size / 1024;
$units = ['KB', 'MB', 'GB', 'TB'];
foreach ($units as $unit) {
if (round($size, 2) >= 1024) {
$size = $size / 1024;
}
else {
break;
}
}
return round($size, 2) . ' ' . $unit;
}
}
Base on Leo's answer, add
Support for negative
Support 0 < value < 1 ( Ex: 0.2, will cause log(value) = negative number )
If you want max unit to Mega, change to $units = explode(' ', ' K M');
function formatUnit($value, $precision = 2) {
$units = explode(' ', ' K M G T P E Z Y');
if ($value < 0) {
return '-' . formatUnit(abs($value));
}
if ($value < 1) {
return $value . $units[0];
}
$power = min(
floor(log($value, 1024)),
count($units) - 1
);
return round($value / pow(1024, $power), $precision) . $units[$power];
}
It's a little late but a slightly faster version of the accepted answer is below:
function formatBytes($bytes, $precision)
{
$unit_list = array
(
'B',
'KB',
'MB',
'GB',
'TB',
);
$bytes = max($bytes, 0);
$index = floor(log($bytes, 2) / 10);
$index = min($index, count($unit_list) - 1);
$bytes /= pow(1024, $index);
return round($bytes, $precision) . ' ' . $unit_list[$index];
}
It's more efficient, due to performing a single log-2 operation instead of two log-e operations.
It's actually faster to do the more obvious solution below, however:
function formatBytes($bytes, $precision)
{
$unit_list = array
(
'B',
'KB',
'MB',
'GB',
'TB',
);
$index_max = count($unit_list) - 1;
$bytes = max($bytes, 0);
for ($index = 0; $bytes >= 1024 && $index < $index_max; $index++)
{
$bytes /= 1024;
}
return round($bytes, $precision) . ' ' . $unit_list[$index];
}
This is because as the index is calculated at the same time as the value of the number of bytes in the appropriate unit. This cut the execution time by about 35% (a 55% speed increase).
Another condensed implementation which can translate to the base 1024 (binary) or base 1000 (decimal) and also works with incredibly large numbers hence of the use of the bc library:
function renderSize($byte,$precision=2,$mibi=true)
{
$base = (string)($mibi?1024:1000);
$labels = array('K','M','G','T','P','E','Z','Y');
for($i=8;$i>=1;$i--)
if(bccomp($byte,bcpow($base, $i))>=0)
return bcdiv($byte,bcpow($base, $i), $precision).' '.$labels[$i-1].($mibi?'iB':'B');
return $byte.' Byte';
}
I figured I would add a meshing of two submitters code (Using John Himmelman's code, which is in this thread, and using Eugene Kuzmenko's code) that I'm using.
function swissConverter($value, $format = true, $precision = 2) {
//Below converts value into bytes depending on input (specify mb, for
//example)
$bytes = preg_replace_callback('/^\s*(\d+)\s*(?:([kmgt]?)b?)?\s*$/i',
function ($m) {
switch (strtolower($m[2])) {
case 't': $m[1] *= 1024;
case 'g': $m[1] *= 1024;
case 'm': $m[1] *= 1024;
case 'k': $m[1] *= 1024;
}
return $m[1];
}, $value);
if(is_numeric($bytes)) {
if($format === true) {
//Below converts bytes into proper formatting (human readable
//basically)
$base = log($bytes, 1024);
$suffixes = array('', 'KB', 'MB', 'GB', 'TB');
return round(pow(1024, $base - floor($base)), $precision) .' '.
$suffixes[floor($base)];
} else {
return $bytes;
}
} else {
return NULL; //Change to prefered response
}
}
This uses Eugene's code to format the $value into bytes (I keep my data in MB, so it converts my data: 10485760 MB into 10995116277760) - it then uses John's code to convert it into the proper display value (10995116277760 into 10 TB).
I've found this really helpful - so my thanks to the two submitters!
I developed my own function that convert human readable memory size to different sizes.
function convertMemorySize($strval, string $to_unit = 'b')
{
$strval = strtolower(str_replace(' ', '', $strval));
$val = floatval($strval);
$to_unit = strtolower(trim($to_unit))[0];
$from_unit = str_replace($val, '', $strval);
$from_unit = empty($from_unit) ? 'b' : trim($from_unit)[0];
$units = 'kmgtph'; // (k)ilobyte, (m)egabyte, (g)igabyte and so on...
// Convert to bytes
if ($from_unit !== 'b')
$val *= 1024 ** (strpos($units, $from_unit) + 1);
// Convert to unit
if ($to_unit !== 'b')
$val /= 1024 ** (strpos($units, $to_unit) + 1);
return $val;
}
convertMemorySize('1024Kb', 'Mb'); // 1
convertMemorySize('1024', 'k') // 1
convertMemorySize('5.2Mb', 'b') // 5452595.2
convertMemorySize('10 kilobytes', 'bytes') // 10240
convertMemorySize(2048, 'k') // By default convert from bytes, result is 2
This function accepts any memory size abbreviation like "Megabyte, MB, Mb, mb, m, kilobyte, K, KB, b, Terabyte, T...." so it is typo safe.
Ok I write my own JS code for this bug I'm sure there's something more comprehensive out there I can use. My Google mojo isn't working though - any help finding open source code that'll help me represent numbers like how SO does for high numbers (102500 => 102.5K, 18601 => 18.6K, etc)?
JS or PHP would be awesome, otherwise I can translate.
Thanks!
Or directly check
Human readable file sizes
Codepaste
/**
* Return human readable sizes
*
* #author Aidan Lister <aidan#php.net>
* #version 1.3.0
* #link http://aidanlister.com/repos/v/function.size_readable.php
* #param int $size size in bytes
* #param string $max maximum unit
* #param string $system 'si' for SI, 'bi' for binary prefixes
* #param string $retstring return string format
*/
function size_readable($size, $max = null, $system = 'si', $retstring = '%01.2f %s')
{
// Pick units
$systems['si']['prefix'] = array('B', 'K', 'MB', 'GB', 'TB', 'PB');
$systems['si']['size'] = 1000;
$systems['bi']['prefix'] = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
$systems['bi']['size'] = 1024;
$sys = isset($systems[$system]) ? $systems[$system] : $systems['si'];
// Max unit to display
$depth = count($sys['prefix']) - 1;
if ($max && false !== $d = array_search($max, $sys['prefix'])) {
$depth = $d;
}
// Loop
$i = 0;
while ($size >= $sys['size'] && $i < $depth) {
$size /= $sys['size'];
$i++;
}
return sprintf($retstring, $size, $sys['prefix'][$i]);
}
This will give you a really good example of how to do exactly that: http://www.jonasjohn.de/snippets/php/readable-filesize.htm
The link is for megabytes but if you want it for thousands just change the $mod variable and change the names that are given. Then it will fit your purposes perfectly.