143

How can I convert the output of PHP's filesize() function to a nice format with MegaBytes, KiloBytes etc?

like:

  • if the size is less than 1 MB, show the size in KB
  • if it's between 1 MB - 1 GB show it in MB
  • if it's larger - in GB
YakovL
  • 7,557
  • 12
  • 62
  • 102
Alex
  • 66,732
  • 177
  • 439
  • 641
  • 1
    [check this also](http://stackoverflow.com/questions/2510434/php-format-bytes-to-kilobytes-megabytes-gigabytes) – Code Mar 06 '13 at 10:07
  • if you are working with WordPress, you can use the shared function `size_format()`. – Earlee Dec 04 '22 at 10:52

11 Answers11

331

Here is a sample:

<?php
// Snippet from PHP Share: http://www.phpshare.org

    function formatSizeUnits($bytes)
    {
        if ($bytes >= 1073741824)
        {
            $bytes = number_format($bytes / 1073741824, 2) . ' GB';
        }
        elseif ($bytes >= 1048576)
        {
            $bytes = number_format($bytes / 1048576, 2) . ' MB';
        }
        elseif ($bytes >= 1024)
        {
            $bytes = number_format($bytes / 1024, 2) . ' KB';
        }
        elseif ($bytes > 1)
        {
            $bytes = $bytes . ' bytes';
        }
        elseif ($bytes == 1)
        {
            $bytes = $bytes . ' byte';
        }
        else
        {
            $bytes = '0 bytes';
        }

        return $bytes;
}
?>
Kelderic
  • 6,502
  • 8
  • 46
  • 85
Adnan
  • 25,882
  • 18
  • 81
  • 110
  • 6
    This answer is more efficient than the others below. It avoids using the log function or successive division statements to identify the unit. – Ali Gangji May 25 '13 at 02:34
  • 1
    That is a brilliant solution, thank you for this awesome function - exactly what I was looking for. – justinhartman Dec 24 '13 at 10:18
  • This function is actually not correct. 1KB is 1000Bytes, because Kilo is 1000. – Aidas Dec 21 '20 at 09:24
  • Easy and to the point. Just make sure that the bytes value you are inputting into the function isn't already formatting using number_format. Lol. Couldn't figure out why it wouldn't work, and realized the commas were messing things up for me. – Michael Oct 27 '21 at 17:47
75

Even nicer is this version I created from a plugin I found:

function filesize_formatted($path)
{
    $size = filesize($path);
    $units = array( 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
    $power = $size > 0 ? floor(log($size, 1024)) : 0;
    return number_format($size / pow(1024, $power), 2, '.', ',') . ' ' . $units[$power];
}

Note from filesize() doc

Because PHP's integer type is signed and many platforms use 32bit integers, some filesystem functions may return unexpected results for files which are larger than 2GB

Community
  • 1
  • 1
PiTheNumber
  • 22,828
  • 17
  • 107
  • 180
  • 1
    Why is it "nicer" tho? It does almost the same thing as my version, except that it'll return the wrong size for files over 2GB (plus the OP never asked for the remaining units of power). – Alix Axel Nov 19 '12 at 13:35
  • 6
    @AlixAxel It is nicer, because it is half the size and still easy to read. Also I bet it is faster. But hey, it's not personal. I didn't think of it myself. Your version is cool too! Upvoted it ;) – PiTheNumber Nov 19 '12 at 16:16
  • 1
    Adnan posted the most verbose, but also the most efficient answer. Using the log function to identify the units is much slower than using simple inequalities. Even using successive division statements in a loop is much faster than using log – Ali Gangji May 25 '13 at 02:41
  • 1
    @PiTheNumber Consider note at [`filesize()` doc](http://php.net/manual/en/function.filesize.php): "Because PHP's integer type is signed and many platforms use 32bit integers, some filesystem functions may return unexpected results for files which are larger than 2GB". For this and for many more reasons I don't quite believe that someone would ever use PHP to operate on files, which size is counted in `TB`, not mentioning higher scales. Plus, I doubt your function is faster than Alix Axel's as you're using `pow` function, similar in resources consumption to `log` used by Alix. – trejder Sep 17 '13 at 09:33
  • I didn't say it is faster or something. Only that it looks nicer. But just for fun I tried to make a benchmark but I don't got any usable results. I should not run it on codepad: http://codepad.org/o6cWsjIi – PiTheNumber Sep 17 '13 at 10:48
43

A cleaner approach:

function Size($path)
{
    $bytes = sprintf('%u', filesize($path));

    if ($bytes > 0)
    {
        $unit = intval(log($bytes, 1024));
        $units = array('B', 'KB', 'MB', 'GB');

        if (array_key_exists($unit, $units) === true)
        {
            return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]);
        }
    }

    return $bytes;
}
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • This looks cleaner but using log to identify the units is much more costly than using a few simple inequalities. – Ali Gangji May 25 '13 at 02:38
  • @AliGangji: True, between 0.1% and 42% more costly to be precise (depending on which `if` condition `$bytes` falls into). – Alix Axel May 25 '13 at 03:48
  • @AliGangji: To expand on my last comment, seems like for values <= 1023 bytes the log approach is on average ~40% slower *but* for 1024 and above I get consistent averages on the order of 0.1%. Interesting! – Alix Axel May 25 '13 at 03:55
  • @AlixAxel Wouldn't that be, because PHP parser analyses `if` block bottom-top, i.e. starting from single (last) `else` and going up through all `elseif` until finally reaching first (in order) `if`? Just wandering, why you're getting such results? – trejder Sep 17 '13 at 09:29
  • @trejder: I only have one `if` statement in my code. And for values 1..1023 it is much slower than for any given value above that. I assume it has something to do with the `log` implementation of PHP (after all, I'm using a 1024 base). – Alix Axel Sep 17 '13 at 10:31
  • 5
    I can't freaking believe you guys are aruging about the 'cost' of a logarithmic equasion in this much cleaner and more elegant answer. How did you even benchmark that difference? And, why not begin the function with a comparisson to >= 1024 before applying a unit appendix if the log ist so costly? – j4k3 Jun 22 '15 at 11:26
  • I too would be interested to see how you implemented the comparison tests. – Jeff Puckett Jul 20 '16 at 18:55
  • This didn't work as well for me. It reported a 2.85gb file as 2G, whereas Adnan's solution reports 2.66GB (still not accurate, but closer).. I'd take accuracy over a few less milliseconds of processing time. – BSUK Nov 21 '17 at 01:32
18

I think this is a better approach. Simple and straight forward.

public function sizeFilter( $bytes )
{
    $label = array( 'B', 'KB', 'MB', 'GB', 'TB', 'PB' );
    for( $i = 0; $bytes >= 1024 && $i < ( count( $label ) -1 ); $bytes /= 1024, $i++ );
    return( round( $bytes, 2 ) . " " . $label[$i] );
}
PiTheNumber
  • 22,828
  • 17
  • 107
  • 180
Teffi
  • 2,498
  • 4
  • 21
  • 40
10

This is based on @adnan's great answer.

Changes:

  • added internal filesize() call
  • return early style
  • saving one concatentation on 1 byte

And you can still pull the filesize() call out of the function, in order to get a pure bytes formatting function. But this works on a file.


/**
 * Formats filesize in human readable way.
 *
 * @param file $file
 * @return string Formatted Filesize, e.g. "113.24 MB".
 */
function filesize_formatted($file)
{
    $bytes = filesize($file);

    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } elseif ($bytes > 1) {
        return $bytes . ' bytes';
    } elseif ($bytes == 1) {
        return '1 byte';
    } else {
        return '0 bytes';
    }
}
Jens A. Koch
  • 39,862
  • 13
  • 113
  • 141
8

All the answers to the question uses that 1 kilobyte = 1024 bytes which is wrong! (1 kibibyte = 1024 bytes)

since the question asks to convert file sizes, it should use that 1 kilobyte = 1000 bytes (see https://wiki.ubuntu.com/UnitsPolicy)

function format_bytes($bytes, $precision = 2) {
    $units = array('B', 'KB', 'MB', 'GB');

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1000));
    $pow = min($pow, count($units) - 1);

    $bytes /= pow(1000, $pow);

    return round($bytes, $precision) . ' ' . $units[$pow];
}
miyuru
  • 1,141
  • 11
  • 19
  • This answer is the only one that is technically correct based on SI standards (except KB should be kB) If you use 1024 as your divisor, then the units should be expressed as KiB, MiB, GiB, TiB, etc. – MortimerCat Jan 11 '20 at 12:25
6

This would be a cleaner implementation:

function size2Byte($size) {
    $units = array('KB', 'MB', 'GB', 'TB');
    $currUnit = '';
    while (count($units) > 0  &&  $size > 1024) {
        $currUnit = array_shift($units);
        $size /= 1024;
    }
    return ($size | 0) . $currUnit;
}
Bat Fung
  • 61
  • 1
  • 2
3
function calcSize($size,$accuracy=2) {
    $units = array('b','Kb','Mb','Gb');
    foreach($units as $n=>$u) {
        $div = pow(1024,$n);
        if($size > $div) $output = number_format($size/$div,$accuracy).$u;
    }
    return $output;
}
barns
  • 352
  • 2
  • 13
3

A complete example.

<?php
    $units = explode(' ','B KB MB GB TB PB');
    echo("<html><body>");
    echo('file size: ' . format_size(filesize("example.txt")));
    echo("</body></html>");


    function format_size($size) {

        $mod = 1024;

        for ($i = 0; $size > $mod; $i++) {
            $size /= $mod;
        }

        $endIndex = strpos($size, ".")+3;

        return substr( $size, 0, $endIndex).' '.$units[$i];
    }
?>
vdbuilder
  • 12,254
  • 2
  • 25
  • 29
2
function getNiceFileSize($file, $digits = 2){
    if (is_file($file)) {
        $filePath = $file;
        if (!realpath($filePath)) {
            $filePath = $_SERVER["DOCUMENT_ROOT"] . $filePath;
        }
        $fileSize = filesize($filePath);
        $sizes = array("TB", "GB", "MB", "KB", "B");
        $total = count($sizes);
        while ($total-- && $fileSize > 1024) {
            $fileSize /= 1024;
        }
        return round($fileSize, $digits) . " " . $sizes[$total];
    }
    return false;
}
Hamed
  • 51
  • 1
  • 5
2
//Get the size in bytes
function calculateFileSize($size)
{
   $sizes = ['B', 'KB', 'MB', 'GB'];
   $count=0;
   if ($size < 1024) {
    return $size . " " . $sizes[$count];
    } else{
     while ($size>1024){
        $size=round($size/1024,2);
        $count++;
    }
     return $size . " " . $sizes[$count];
   }
}
Tohid Dadashnezhad
  • 1,808
  • 1
  • 17
  • 27