diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 495dd0bbb34..a08bff5ef9b 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -161,6 +161,14 @@ define('DRUPAL_ANONYMOUS_RID', 1); */ define('DRUPAL_AUTHENTICATED_RID', 2); +/** + * The number of bytes in a kilobyte. The scientific standard for kilo is 1000, + * but used commonly in the field of computers to represent 1024 bits. For more + * information on the different standards please visit: + * http://en.wikipedia.org/wiki/Kilobyte. + */ +define('DRUPAL_KILOBYTE', 1024); + /** * No language negotiation. The default language is used. */ diff --git a/includes/common.inc b/includes/common.inc index 8e78606190f..0b6faa35a02 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1210,20 +1210,20 @@ function format_plural($count, $singular, $plural, $args = array(), $langcode = * Parse a given byte count. * * @param $size - * A size expressed as a number of bytes with optional SI size and unit - * suffix (e.g. 2, 3K, 5MB, 10G). + * A size expressed as a number of bytes with optional SI or IEC binary unit + * prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8 bytes, 9mbytes). * @return - * An integer representation of the size. + * An integer representation of the size in bytes. */ function parse_size($size) { - $suffixes = array( - '' => 1, - 'k' => 1024, - 'm' => 1048576, // 1024 * 1024 - 'g' => 1073741824, // 1024 * 1024 * 1024 - ); - if (preg_match('/([0-9]+)\s*(k|m|g)?(b?(ytes?)?)/i', $size, $match)) { - return $match[1] * $suffixes[drupal_strtolower($match[2])]; + $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size. + $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size. + if ($unit) { + // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by. + return round($size * pow(DRUPAL_KILOBYTE, stripos('bkmgtpezy', $unit[0]))); + } + else { + return round($size); } } @@ -1239,11 +1239,11 @@ function parse_size($size) { * A translated string representation of the size. */ function format_size($size, $langcode = NULL) { - if ($size < 1000) { + if ($size < DRUPAL_KILOBYTE) { return format_plural($size, '1 byte', '@count bytes', array(), $langcode); } else { - $size = $size / 1000; // convert bytes to kilobytes (1000 bytes) + $size = $size / DRUPAL_KILOBYTE; // Convert bytes to kilobytes. $units = array( t('@size KB', array(), $langcode), t('@size MB', array(), $langcode), @@ -1255,8 +1255,8 @@ function format_size($size, $langcode = NULL) { t('@size YB', array(), $langcode), ); foreach ($units as $unit) { - if (round($size, 2) >= 1000) { - $size = $size / 1000; + if (round($size, 2) >= DRUPAL_KILOBYTE) { + $size = $size / DRUPAL_KILOBYTE; } else { break; diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index 62cfdb108c3..01fe73546fe 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -1,14 +1,16 @@ t('Format size test'), + 'name' => t('Size parsing test'), 'description' => t('Parse a predefined amount of bytes and compare the output with the expected value.'), 'group' => t('System') ); @@ -18,40 +20,88 @@ class CommonFormatSizeTestCase extends DrupalWebTestCase { * Implementation of setUp(). */ function setUp() { + $kb = DRUPAL_KILOBYTE; $this->exact_test_cases = array( - '1 byte' => 1, // byte - '1 KB' => 1000, // kilobyte - '1 MB' => 1000000, // megabyte - '1 GB' => 1000000000, // gigabyte - '1 TB' => 1000000000000, // terabyte - '1 PB' => 1000000000000000, // petabyte - '1 EB' => 1000000000000000000, // exabyte - '1 ZB' => 1000000000000000000000, // zettabyte - '1 YB' => 1000000000000000000000000, // yottabyte + '1 byte' => 1, + '1 KB' => $kb, + '1 MB' => $kb * $kb, + '1 GB' => $kb * $kb * $kb, + '1 TB' => $kb * $kb * $kb * $kb, + '1 PB' => $kb * $kb * $kb * $kb * $kb, + '1 EB' => $kb * $kb * $kb * $kb * $kb * $kb, + '1 ZB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb, + '1 YB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb * $kb, ); $this->rounded_test_cases = array( - '2 bytes' => 2, // bytes - '1 MB' => 999999, // 1 MB (not 1000 kilobyte!) - '3.62 MB' => 3623651, // megabytes - '67.23 PB' => 67234178751368124, // petabytes - '235.35 YB' => 235346823821125814962843827, // yottabytes + '2 bytes' => 2, + '1 MB' => ($kb * $kb) - 1, // rounded to 1 MB (not 1000 or 1024 kilobyte!) + round(3623651 / ($this->exact_test_cases['1 MB']), 2) . ' MB' => 3623651, // megabytes + round(67234178751368124 / ($this->exact_test_cases['1 PB']), 2) . ' PB' => 67234178751368124, // petabytes + round(235346823821125814962843827 / ($this->exact_test_cases['1 YB']), 2) . ' YB' => 235346823821125814962843827, // yottabytes ); parent::setUp(); } /** - * testCommonFormatSize + * Check that format_size() returns the expected string. */ function testCommonFormatSize() { foreach (array($this->exact_test_cases, $this->rounded_test_cases) as $test_cases) { - foreach ($test_cases as $expected => $size) { - $this->assertTrue( - ($result = format_size($size, NULL)) == $expected, - $expected . " == " . $result . " (" . $size . " bytes) %s" + foreach ($test_cases as $expected => $input) { + $this->assertEqual( + ($result = format_size($input, NULL)), + $expected, + $expected . ' == ' . $result . ' (' . $input . ' bytes)' ); } } } + + /** + * Check that parse_size() returns the proper byte sizes. + */ + function testCommonParseSize() { + foreach ($this->exact_test_cases as $string => $size) { + $this->assertEqual( + $parsed_size = parse_size($string), + $size, + $size . ' == ' . $parsed_size . ' (' . $string . ')' + ); + } + + // Some custom parsing tests + $string = '23476892 bytes'; + $this->assertEqual( + ($parsed_size = parse_size($string)), + $size = 23476892, + $string . ' == ' . $parsed_size . ' bytes' + ); + $string = '76MRandomStringThatShouldBeIgnoredByParseSize.'; // 76 MB + $this->assertEqual( + $parsed_size = parse_size($string), + $size = 79691776, + $string . ' == ' . $parsed_size . ' bytes' + ); + $string = '76.24 Giggabyte'; // Misspeld text -> 76.24 GB + $this->assertEqual( + $parsed_size = parse_size($string), + $size = 81862076662, + $string . ' == ' . $parsed_size . ' bytes' + ); + } + + /** + * Cross-test parse_size() and format_size(). + */ + function testCommonParseSizeFormatSize() { + foreach ($this->exact_test_cases as $size) { + $this->assertEqual( + $size, + ($parsed_size = parse_size($string = format_size($size, NULL))), + $size . ' == ' . $parsed_size . ' (' . $string . ')' + ); + } + } } /**