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?
28 Answers
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 :-)
-
I almost upvoted your answer (it's very similar to mine), but I don't like this "division by 1024^$pow" business. You should just do 1024^fraction($pow) and be done. :-) – C. K. Young Mar 24 '10 at 18:40
-
8If you used `$bytes /= (1 << (10 * $pow))` or the like, I could like it better. :-P – C. K. Young Mar 24 '10 at 18:46
-
5There you go :D (personally, I don't like bitwise arithmetic, because it is hard to understand if you aren't used to it...) – Leo Mar 24 '10 at 18:50
-
`9287695` returns `8.86 MB` with a precision of 2. That doesn't seem right. – Justin Sep 01 '12 at 09:02
-
3
-
45Actually, it's `KiB`, `MiB`, `GiB` and `TiB` since you are dividing by `1024`. If you divided by `1000` it would be without the `i`. – Devator May 16 '13 at 19:41
-
1`$bytes /= (1 << (10 * $pow))` does not work well but number above 1 TB – David Bélanger Aug 05 '13 at 16:40
-
1Just FYI, the second alternative above calculates TB wrong as David Belanger also pointed out. Use the first alternative instead ($bytes /= pow(1024, $pow);) – fred Jun 03 '14 at 15:59
-
1use return round($bytes, $precision) . ' ' . $units[$pow]; if you never want the unit being pushed onto the next line in HTML output. – Rid Iculous Jun 07 '16 at 01:44
-
12`Uncomment one of the following alternatives` was something I did not notice for 5 minutes ... – Arnis Juraga Aug 08 '17 at 16:04
-
-
2@yogur, it is so that if $bytes is a negative value, it will set it to 0 instead. – kojow7 Nov 19 '17 at 21:15
-
1Do not forget to uncomment one of the two lines stated in the code. – TheTechGuy Oct 01 '19 at 17:07
-
`return round($bytes, $precision) . ' ' . $units[$pow]; ` needs to be `return round($pow, $precision) . ' ' . $units[$pow]; `. Isn't it? check:- https://3v4l.org/3GEig AND https://3v4l.org/gqE3D – Alive to die - Anant Mar 18 '20 at 07:10
-
if you are working with WordPress, you can use the shared function `size_format()`. – Earlee Dec 04 '22 at 10:52
-
Does not work out of the box (just tried copy-pasting without checking comments). I would ask the author to adapt the code so that it does (uncomment one of the two options). Until then I recommend this answer: https://stackoverflow.com/a/2510540/1240678 – Tyreal Apr 24 '23 at 14:24
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

- 6,987
- 24
- 106
- 158

- 21,504
- 22
- 65
- 80
-
8it has 2 errors - add 1 to (at least small) files size - not working with 0 (return NAN) – maazza Aug 31 '12 at 10:35
-
-
3*a lil dreaming* **:** `$suffixes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');` I wants a Yottabyte hard drive! ***:-P*** – SpYk3HH Dec 17 '13 at 16:49
-
1i had to cast the $size to a double to get it to work. heres what worked for me: function formatBytes($size, $precision = 2){ $base = log(floatval($size)) / log(1024); $suffixes = array('', 'k', 'M', 'G', 'T'); return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; } – CGray Mar 19 '14 at 17:02
-
-
For the pedants amongst us (isn't that all of us?): 'K' should be 'k'. See: https://en.wikipedia.org/wiki/Metric_prefix. – darrenp Oct 12 '16 at 20:07
-
1I like this too, and think it's clean, but a little more explaination about what this function is _doing_ in steps would be appreciated, for us noobs :). For example: why hard code `1024` instead of [using diff converters](http://www.eagle-web-designs.com/cool_stuff/ByteConversion.html) like `$unitInBytes = 1 * pow(2, 10)` then doing a `return ($size / $unitInBytes)` or some combination thereof, why does this method produce better results? Any clarification is appreciated for understanding it, rather than just copy/pasting and never thinking about it again. – mrClean Feb 20 '17 at 21:17
-
It calculates bits $suffixes = array('', 'K', 'M', 'G', 'T'); but if you want to show only minimum in Megabytes remove first 2 values $suffixes = array('M', 'G', 'T'); now calculate echo formatBytes(1024, 0); it will come up with 1GB – shaz3e Jun 23 '17 at 22:25
-
IDE looks nicer when added (int) here: return .......$suffixes[(int)floor($base)]; – Vit Aug 23 '21 at 09:50
Pseudocode:
$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;

- 219,335
- 46
- 382
- 435
-
-
This doesn't look like pseudocode; or do you just mean that it is "untested code"? This answer is missing its educational explanation. – mickmackusa Apr 06 '21 at 07:40
Just divide it by 1024 for kb, 1024^2 for mb and 1024^3 for GB. As simple as that.

- 4,033
- 15
- 44
- 61
-
1Downvoted, because a) it's factually wrong (see ISO 80000-13), b) doesn't provide any real solution in the form of a piece of code. – ericek111 Sep 20 '22 at 08:29
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]);
}

- 65,519
- 58
- 198
- 260
-
Their idea of having an option between 1024 and 1000 power is good. But this implementation is really weird. `$force_unit` and `$si` seem to do the same thing. You can also pass any string with an "i" in it to `$force_unit`, because they test for position. The decimal formatting is also overkill. – Gus Neves Dec 01 '16 at 00:43
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";
}

- 3,715
- 3
- 28
- 25
use this function if you want a short code
$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
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';
}

- 7,400
- 4
- 37
- 55
-
1You get a double B (BB) for small values of $B, as a work around you could make "$S = 'kMGTPEZY'", and instead of "@$S[$F]" do "@$S[$F-1]". – camomileCase Jun 16 '14 at 16:29
-
1@camomileCase Two years and half later - I updated my answer. Thanks. – David Bélanger Dec 14 '16 at 14:05
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

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

- 9,478
- 8
- 61
- 71
-
This is a nice one, which I used. Simple enough if you understand some math, which probably is a valid assumption for programmers. But: The factor should be 1000 to be correct, and this returns the quite uncommon PHP shorthand “42M”, not something one would use in UI like “42 MB“. – Andy Apr 23 '22 at 14:54
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'

- 169
- 2
- 13
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"

- 732,580
- 175
- 1,330
- 1,459

- 264
- 3
- 9
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];
}
}

- 29
- 2
-
This answer is missing its educational explanation. I have concerns regarding `KB` and `KiB`. https://3v4l.org/s9AXo Please see https://cseducators.stackexchange.com/q/4425 – mickmackusa Apr 06 '21 at 07:15
-
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];
}

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

- 1
- 62
- 391
- 407
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.';
}
}

- 2,665
- 2
- 21
- 33
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];
}

- 3,792
- 2
- 27
- 54
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);

- 682
- 9
- 14
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');

- 401
- 2
- 7
- 19
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.

- 2,507
- 3
- 29
- 29
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;
}

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

- 2,060
- 28
- 34
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];
}

- 16,239
- 8
- 58
- 54
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).

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

- 582
- 9
- 21
-
Just a little side note; `bcpow()` will throw TypeError exception if `$base` and `$i` are not string values. Tested on PHP version 7.0.11. – David Cery Jan 06 '17 at 18:34
-
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!

- 1
- 4
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.

- 960
- 1
- 10
- 20