Format bytes to kilobytes, megabytes, gigabytes

Php

Php Problem Overview


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?

Php Solutions


Solution 1 - Php

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 :-)

Solution 2 - Php

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

Solution 3 - Php

Pseudocode:

$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;

Solution 4 - Php

Just divide it by 1024 for kb, 1024^2 for mb and 1024^3 for GB. As simple as that.

Solution 5 - Php

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]);
}

Solution 6 - Php

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";
}

Solution 7 - Php

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

Solution 8 - Php

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';
}

Solution 9 - Php

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

Solution 10 - Php

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'

Solution 11 - Php

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];
  }
}

Solution 12 - Php

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];
}

Solution 13 - Php

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];
}
?>

Solution 14 - Php

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"

Solution 15 - Php

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

Solution 16 - Php

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];
	}

Solution 17 - Php

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);

Solution 18 - Php

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');

Solution 19 - Php

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.

Solution 20 - Php

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;
}

Solution 21 - Php

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.';
    }
}

Solution 22 - Php

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;
}

Solution 23 - Php

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;
  }
}

Solution 24 - Php

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).

Solution 25 - Php

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';
}

Solution 26 - Php

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!

Solution 27 - Php

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.

Solution 28 - Php

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];
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionleepowersView Question on Stackoverflow
Solution 1 - PhpLeoView Answer on Stackoverflow
Solution 2 - PhpJohn HimmelmanView Answer on Stackoverflow
Solution 3 - PhpChris Jester-YoungView Answer on Stackoverflow
Solution 4 - PhpVonderView Answer on Stackoverflow
Solution 5 - PhpryeguyView Answer on Stackoverflow
Solution 6 - PhpguariView Answer on Stackoverflow
Solution 7 - PhpYanniView Answer on Stackoverflow
Solution 8 - PhpDavid BélangerView Answer on Stackoverflow
Solution 9 - PhpSebHallinView Answer on Stackoverflow
Solution 10 - PhpMadushanka SampathView Answer on Stackoverflow
Solution 11 - Phpuser24087View Answer on Stackoverflow
Solution 12 - PhpZettiCalettiView Answer on Stackoverflow
Solution 13 - PhpJohn ErckView Answer on Stackoverflow
Solution 14 - PhpPavel TzonkovView Answer on Stackoverflow
Solution 15 - PhpZomboView Answer on Stackoverflow
Solution 16 - PhpJanith ChinthanaView Answer on Stackoverflow
Solution 17 - PhpYahia MgarrechView Answer on Stackoverflow
Solution 18 - PhpKerem ÇakırView Answer on Stackoverflow
Solution 19 - PhpBen JohnsonView Answer on Stackoverflow
Solution 20 - PhpGabriel BarcellosView Answer on Stackoverflow
Solution 21 - PhpUdo E.View Answer on Stackoverflow
Solution 22 - PhpmookyView Answer on Stackoverflow
Solution 23 - Phpya.teckView Answer on Stackoverflow
Solution 24 - Phpuser3690595View Answer on Stackoverflow
Solution 25 - PhpChristianView Answer on Stackoverflow
Solution 26 - PhpEMLView Answer on Stackoverflow
Solution 27 - PhpJuan LagoView Answer on Stackoverflow
Solution 28 - PhpSteely WingView Answer on Stackoverflow