Drupal provides the format_size function to format a file size. But it is not enough flexible to meet all requirements. It cannot handle suffixes larger than megabytes, don't let choose the precision, and the format used to render it.
The following code is able to take the three most common file size formats up to the yottabyte. It is feature complete and could be considered in future versions of Drupal.
function format_filesize($filesize, $precision = 2, $format = "byte") {
switch ($format) {
case "byte":
$suffixes = array("B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
$power_div = 1024;
break;
case "byte-si":
$suffixes = array("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB");
$power_div = 1000;
break;
case "bits":
$suffixes = array("b", "kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb");
$filesize *= 8;
$power_div = 1000;
break;
default:
die(t("No valid file size format specified."));
}
$power = floor(log($filesize, $power_div));
$suffix = t($suffixes[$power]);
if ($power > 0) {
$filesize = number_format($filesize / pow($power_div, $power), $precision);
}
return t(
"@filesize @suffix",
array(
'@filesize' => $filesize,
'@suffix' => $suffix
)
);
}
| Comment | File | Size | Author |
|---|---|---|---|
| #22 | format_size.patch | 3.02 KB | mrharolda |
| #19 | common.test.patch | 1.62 KB | mrharolda |
| #5 | format_size.patch | 1.25 KB | mrharolda |
| #3 | format_size.patch | 1.12 KB | mrharolda |
Comments
Comment #1
bdragon commentedPlease attach a patch in -up format before setting cnr.. Thanks.
Comment #2
ntiostle commentedThe case for SI is wrong. The SI defines k=kilo=1000 (see http://en.wikipedia.org/wiki/SI_prefix#List_of_SI_prefixes). The KiB, MiB units are defined in IEC 60027-2 (http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes) and define 1KiB=1024 Byte.
Comment #3
mrharolda commentedI've attached a patch without the bits and SI code, but as close to the existing code as possible.
It adds support for 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB' and 'YiB' using the correct naming schema as defined in http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes
Edit: removed 'B' from the list, as it is handled by the first if statement...
Comment #4
dries commentedI know that technically, one has to use KiB and MiB but in practice, people don't know what these stand for (unless you have a CS degree). I'd prefer to stick with MB instead of MiB.
Comment #5
mrharolda commentedHow about using units of 1000 bytes as a kilobyte (KB) then? That would be complient to the SI prefixes: http://en.wikipedia.org/wiki/SI_prefixes#List_of_SI_prefixes and thus not a 'lie'... ;)
Comment #6
mrharolda commentedreset patch to 'code needs review'...
Comment #7
dries commentedI'm OK with the patch in #5 but it could use a SimpleTest ...
Comment #8
mrharolda commentedAfter running the following test, I found 2 issues with my patch...
1: yottabytes don't fit in a 32-bit integer ;)
2: there is a bug in locale_get_plural() wich uses
$langcode = NULLas index in line 422:$locale_formula[$langcode] = $language_list[$langcode]->formula;The test:
Edit: removed attached patch to prevent confusion
Comment #9
mrharolda commentedI've just created a separate issue for issue 2 in comment #8: http://drupal.org/node/263259
Comment #10
damien tournoud commentedHum. The handling of file sizes as strings is ugly. Do we really need to support sizes up to yottabytes?
Comment #11
mrharolda commentedThe maximum value of a signed 32-bit integer is 2147483647, which is equal to 2.15 GB.
Support up to yottabyte is probably a bit too much, but it comes for free with this function. I'd guess support of terabyte is quite reasonable these days...
We @ madcap are working on a video platform capable of handling multiple terabytes of data, hence this function enhancement. Filesize is retrieved from a SUM() function in mysql and fetched as a string, because of the limit of 32-bit integers as mentioned above.
Comment #12
damien tournoud commentedWhy not treating everything as a float instead? We just don't need arbitrary precision here.
Comment #13
mrharolda commentedYou're absolutely right! ;)
I've just run the test code below both a 32-bit and a 64-bit platform and it passed without any problems using the non-string code as posted in comment #5. Integers larger than 2147483647 are automatically casted into a float on a 32-bit platform and the code in comment #5 does not have a problem with that...
Comment #14
mrharolda commentedIf no-one has any other objections, can this be committed to D7?
Patch @ comment #5: http://drupal.org/node/151902#comment-858506
-tnx!-
Harold.
Comment #15
mrharolda commentedDries: I'm OK with the patch in #5 but it could use a SimpleTest ...
Simpletest code in comment #13...
Comment #16
dries commentedThe way we use strings to do this is, in fact, ugly. I'd like to see us brainstorm some more about something that is a bit more elegant.
Comment #17
dries commentedAlso, please add the simpletest code as a patch. We commit these to core as well nowadays.
Comment #18
damien tournoud commented@Dries: The brainstorming is already done. The patch in #5 does not use strings at all, but floats.
Comment #19
mrharolda commentedPlease review the attached patch wich will create a 'common.test' file in which the test for
format_size()resides...The patch for the
format_size()function can be found at comment #5.Comment #20
mrharolda commentedOff topic: I've changed my username from Harold@Madcap to MadHarold, since IRC doesn't allow '@' in a username...
Comment #21
mrharolda commentedI've updated format_size() to never show 1000 'whatevers'. I've also added the following test to prove it! ;)
Edit:
Removed the 2 patches in favor of the single patch attached below...
Comment #22
mrharolda commentedReplaced the above patches with a single one, diffed from the root of the Drupal install...
This single patch includes the creation of the
common.testfile.Comment #23
coupet commentedCalculations should be in Binary or Decimal (SI)?
Byte
http://en.wikipedia.org/wiki/Byte
Comment #24
mrharolda commented@coupet: Dries said that using decimal(1000) calculations would be best. Using binary(1024) calculations would force the output to use KiB, MiB, etc and users would be confused by that...
Using a mix of binary(1024) and KB, MB etc would be 'lying'... :)
Comment #25
catchTest passes fine and I think it addresses Dries' questions, bumping this to critical as well since it introduces common.test - and a lack of common.test is blocking at least 3-4 patches elsewhere in the queue.
Comment #26
dries commentedCommitted to CVS HEAD. Thanks folks. :-)
Comment #27
kkaefer commentedPleae make sure that "KB", "MB", ... are translatable. While they are identical to the English version in most cases, Germans usually use "kB" instead of "KB".
Comment #28
mrharolda commented@kkaefer: good catch! I've created a separate issue (+patch) for the missing
t()call in http://drupal.org/node/268477Comment #29
Anonymous (not verified) commentedAutomatically closed -- issue fixed for two weeks with no activity.
Comment #30
mrharolda commentedI'll leave this one closed, but I want to add that I've created a new patch for
format_size()which can be found here: http://drupal.org/node/267883#comment-1095221