PHP filesize MB/KB conversion [duplicate]
Asked Answered
B

11

146

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
Bunnie answered 31/3, 2011 at 14:26 Comment(3)
check this alsoDobbin
if you are working with WordPress, you can use the shared function size_format().Exodontics
And if you're not working with WordPress (I am!), you can always take a peek at developer.wordpress.org/reference/functions/size_format and copy the source code. It defines a few constants, but everything should be easy to understand; also, the WordPress code tries to deal with internationalisation/localisation, which may be overkill (and number_format() will do the job of pretty-formatting things at the end, instead of WP's own function).Horta
U
334

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;
}
?>
Ule answered 31/3, 2011 at 14:28 Comment(5)
This answer is more efficient than the others below. It avoids using the log function or successive division statements to identify the unit.Sinhalese
That is a brilliant solution, thank you for this awesome function - exactly what I was looking for.Sanguine
This function is actually not correct. 1KB is 1000Bytes, because Kilo is 1000.Beefburger
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.Twitch
At last someone who writes fast PHP code, avoiding all the pitfalls of calling the expensive math function! And, of course, it's trivial to understand. Simple code sometimes is efficient code. And a nice touch using number_format(). In fact, it seems that WordPress itself uses a variant of your simple function: developer.wordpress.org/reference/functions/size_formatHorta
M
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

Midterm answered 8/8, 2012 at 8:32 Comment(5)
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).Emulsoid
@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 ;)Midterm
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 logSinhalese
@Midterm Consider note at 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". 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.Niblick
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: codepad.org/o6cWsjIiMidterm
E
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;
}
Emulsoid answered 31/3, 2011 at 15:10 Comment(8)
This looks cleaner but using log to identify the units is much more costly than using a few simple inequalities.Sinhalese
@AliGangji: True, between 0.1% and 42% more costly to be precise (depending on which if condition $bytes falls into).Emulsoid
@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!Emulsoid
@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?Niblick
@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).Emulsoid
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?Coray
I too would be interested to see how you implemented the comparison tests.Upbow
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.Hirsute
H
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] );
}
Hammon answered 21/5, 2013 at 7:42 Comment(1)
Perfect i can use that in my helper class, thx alot.Jarad
G
11

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';
    }
}
Gegenschein answered 20/9, 2014 at 22:52 Comment(0)
B
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];
}
Bundelkhand answered 17/10, 2018 at 8:36 Comment(1)
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.Cuman
G
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;
}
Girlish answered 1/4, 2015 at 20:59 Comment(0)
C
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];
    }
?>
Camlet answered 1/12, 2011 at 22:56 Comment(0)
T
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;
}
Tactical answered 13/7, 2015 at 12:11 Comment(0)
D
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;
}
Dandy answered 25/3, 2016 at 11:14 Comment(0)
S
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];
   }
}
Salba answered 24/12, 2016 at 10:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.