13


I'm asking how to convert KB MB GB TB & co. into bytes.
For example:

byteconvert("10KB") // => 10240
byteconvert("10.5KB") // => 10752
byteconvert("1GB") // => 1073741824
byteconvert("1TB") // => 1099511627776

and so on...

EDIT: wow. I've asked this question over 4 years ago. Thise kind of things really show you how much you've improved over time!

user1494162
  • 316
  • 1
  • 3
  • 10
  • 1
    Multiply the numeric value of the argument by 1024 multiple times. – DCoder Aug 04 '12 at 08:29
  • 2
    [What have you tried?](http://whathaveyoutried.com/) Also, I'm sure there are a hundred functions for this available from the first page of Google's search results. – John V. Aug 04 '12 at 08:30
  • 1
    @AlexLunix nothing i don't even know how to start and I didn't found anything in google – user1494162 Aug 04 '12 at 08:33

11 Answers11

45

Here's a function to achieve this:

function convertToBytes(string $from): ?int {
    $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    $number = substr($from, 0, -2);
    $suffix = strtoupper(substr($from,-2));

    //B or no suffix
    if(is_numeric(substr($suffix, 0, 1))) {
        return preg_replace('/[^\d]/', '', $from);
    }

    $exponent = array_flip($units)[$suffix] ?? null;
    if($exponent === null) {
        return null;
    }

    return $number * (1024 ** $exponent);
}

$testCases = ["13", "13B", "13KB", "10.5KB", "123Mi"];
var_dump(array_map('convertToBytes', $testCases));

Output:

array(5) { [0]=> int(13) [1]=> int(13) [2]=> int(13312) [3]=> int(10752) [4]=> NULL } int(1)

John V.
  • 4,652
  • 4
  • 26
  • 26
  • This is not correct getting `Float returned` error for 110GB. Use the answer instead `https://stackoverflow.com/questions/11807115/php-convert-kb-mb-gb-tb-etc-to-bytes/17364338#17364338` – MR_AMDEV Apr 19 '19 at 17:09
  • @MR_AMDEV 110GB works fine for me, is "110GB" literally what you are passing in when it is not working? – John V. Apr 19 '19 at 19:44
  • I can't seem to reproduce that result, can you provide a code example? https://3v4l.org/6SNq9 – John V. Apr 20 '19 at 03:37
  • One thought is that it's possible that your system you are running on is 32 bit and is representing the number as a float because there is not enough room for an int. If that's the case you could change the return type to float on your system, but be warned there is room for unexpected results with large float calculations. – John V. Apr 20 '19 at 03:40
  • If the size passed like "20M" then this function does not work properly and returns 20 instead of the correct size. – Munshi Azhar Mar 12 '21 at 01:06
10
function toByteSize($p_sFormatted) {
    $aUnits = array('B'=>0, 'KB'=>1, 'MB'=>2, 'GB'=>3, 'TB'=>4, 'PB'=>5, 'EB'=>6, 'ZB'=>7, 'YB'=>8);
    $sUnit = strtoupper(trim(substr($p_sFormatted, -2)));
    if (intval($sUnit) !== 0) {
        $sUnit = 'B';
    }
    if (!in_array($sUnit, array_keys($aUnits))) {
        return false;
    }
    $iUnits = trim(substr($p_sFormatted, 0, strlen($p_sFormatted) - 2));
    if (!intval($iUnits) == $iUnits) {
        return false;
    }
    return $iUnits * pow(1024, $aUnits[$sUnit]);
}
Kristian Williams
  • 2,275
  • 22
  • 25
  • This code don't work correctly with 'B' suffix - it cuts off last digit and don't allows float/double. See my version: https://stackoverflow.com/a/65726567/1041470 – VladSavitsky Mar 29 '21 at 14:07
8

Here's what I've come up with so far, that I think is a much more elegant solution:

/**
 * Converts a human readable file size value to a number of bytes that it
 * represents. Supports the following modifiers: K, M, G and T.
 * Invalid input is returned unchanged.
 *
 * Example:
 * <code>
 * $config->human2byte(10);          // 10
 * $config->human2byte('10b');       // 10
 * $config->human2byte('10k');       // 10240
 * $config->human2byte('10K');       // 10240
 * $config->human2byte('10kb');      // 10240
 * $config->human2byte('10Kb');      // 10240
 * // and even
 * $config->human2byte('   10 KB '); // 10240
 * </code>
 *
 * @param number|string $value
 * @return number
 */
public function human2byte($value) {
  return 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);
}
Eugene Kuzmenko
  • 947
  • 9
  • 11
  • 1
    Very interesting approach, I would suggest to make it decimal friendly by changing regex to `/^\s*([\d.]+)\s*(?:([kmgt]?)b?)?\s*$/i` – Nazariy Oct 31 '18 at 16:47
4

I use a function to determine the memory limit set for PHP in some cron scripts that looks like:

$memoryInBytes = function ($value) {
    $unit = strtolower(substr($value, -1, 1));
    return (int) $value * pow(1024, array_search($unit, array(1 =>'k','m','g')));
}

A similar approach that will work better with floats and accept the two letter abbreviation would be something like:

function byteconvert($value) {
    preg_match('/(.+)(.{2})$/', $value, $matches);
    list($_,$value,$unit) = $matches;
    return (int) ($value * pow(1024, array_search(strtolower($unit), array(1 => 'kb','mb','gb','tb'))));
}
Steve Buzonas
  • 5,300
  • 1
  • 33
  • 55
4

Wanting something similar to this and not quite liking the other solutions posted here for various reasons, I decided to write my own function:

function ConvertUserStrToBytes($str)
{
    $str = trim($str);
    $num = (double)$str;
    if (strtoupper(substr($str, -1)) == "B")  $str = substr($str, 0, -1);
    switch (strtoupper(substr($str, -1)))
    {
        case "P":  $num *= 1024;
        case "T":  $num *= 1024;
        case "G":  $num *= 1024;
        case "M":  $num *= 1024;
        case "K":  $num *= 1024;
    }

    return $num;
}

It adapts a few of the ideas presented here by Al Jey (whitespace handling) and John V (switch-case) but without the regex, doesn't call pow(), lets switch-case do its thing when there aren't breaks, and can handle some weird user inputs (e.g. " 123 wonderful KB " results in 125952). I'm sure there is a more optimal solution that involves fewer instructions but the code would be less clean/readable.

CubicleSoft
  • 2,274
  • 24
  • 20
  • The only thing I changed was `return round($num);` because eg 1.2MB isn't a round number of bytes. – MSpreij Apr 14 '22 at 14:23
3
<?php
function byteconvert($input)
{
    preg_match('/(\d+)(\w+)/', $input, $matches);
    $type = strtolower($matches[2]);
    switch ($type) {
    case "b":
        $output = $matches[1];
        break;
    case "kb":
        $output = $matches[1]*1024;
        break;
    case "mb":
        $output = $matches[1]*1024*1024;
        break;
    case "gb":
        $output = $matches[1]*1024*1024*1024;
        break;
    case "tb":
        $output = $matches[1]*1024*1024*1024;
        break;
    }
    return $output;
}
$foo = "10mb";
echo "$foo = ".byteconvert($foo)." byte";
?>
Hiendv
  • 39
  • 1
3

Based on https://stackoverflow.com/a/17364338/1041470

Improvements:

  • Fixed bug with bytes suffix length,
  • Allowed to use double (float) values but only integers,
  • Reverted array which holds units,
  • Renamed variables,
  • Added comments.
/**
 * Converts human readable file size into bytes.
 *
 * Note: This is 1024 based version which assumes that a 1 KB has 1024 bytes.
 * Based on https://stackoverflow.com/a/17364338/1041470
 *
 * @param string $from
 *   Required. Human readable size (file, memory or traffic).
 *   For example: '5Gb', '533Mb' and etc.
 *   Allowed integer and float values. Eg., 10.64GB.
 *
 * @return int
 *   Returns given size in bytes.
 */
function cm_common_convert_to_bytes(string $from): ?int {
  static $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  $from = trim($from);
  // Get suffix.
  $suffix = strtoupper(trim(substr($from, -2)));
  // Check one char suffix 'B'.
  if (intval($suffix) !== 0) {
    $suffix = 'B';
  }
  if (!in_array($suffix, $units)) {
    return FALSE;
  }
  $number = trim(substr($from, 0, strlen($from) - strlen($suffix)));
  if (!is_numeric($number)) {
    // Allow only float and integer. Strings produces '0' which is not corect.
    return FALSE;
  }
  return (int) ($number * pow(1024, array_flip($units)[$suffix]));
}
VladSavitsky
  • 523
  • 5
  • 13
1

I was just looking for this function and took on the challenge to try to improve in it and got it to TWO lines :) Uses a similar regex to Eugene's to validate/extract values, but avoids the switch statement. Can accept long '10MB','10mb' and short '10M','10m' values, decimal values and always returns an integer. Invalid strings return 0

function to_bytes( $str )
{
    if( ! preg_match('/^([\d.]+)([BKMGTPE]?)(B)?$/i', trim($str), $m) ) return 0;
    return (int) floor($m[1] * ( $m[2] ? (1024**strpos('BKMGTPE', strtoupper($m[2]))) : 1 ));
}
ntheorist
  • 79
  • 4
0

I know this is a relative old topic, but here's a function that I sometimes have to use when I need this kind of stuff; You may excuse for if the functions dont work, I wrote this for hand in a mobile:

function intobytes($bytes, $stamp = 'b') {
    $indx = array_search($stamp, array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'yb'));
    if ($indx > 0) {
        return $bytes * pow(1024, $indx);
    }
    return $bytes;
}

and as compact

function intobytes($bytes, $stamp='b') {$indx=array_search($stamp,array('b','kb','mb','gb','tb','pb','yb'));if($indx > 0){return $bytes * pow(1024,$indx);} return $bytes;}

Take care!

Brodde85 ;)

dearsina
  • 4,774
  • 2
  • 28
  • 34
Cooper
  • 11
  • 1
  • 2
0

One more solution (IEC):

<?php

class Filesize
{
    const UNIT_PREFIXES_POWERS = [
        'B' => 0,
        ''  => 0,
        'K' => 1,
        'k' => 1,
        'M' => 2,
        'G' => 3,
        'T' => 4,
        'P' => 5,
        'E' => 6,
        'Z' => 7,
        'Y' => 8,
    ];

    public static function humanize($size, int $precision = 2, bool $useBinaryPrefix = false)
    {
        $base = $useBinaryPrefix ? 1024 : 1000;
        $limit = array_values(self::UNIT_PREFIXES_POWERS)[count(self::UNIT_PREFIXES_POWERS) - 1];
        $power = ($_ = floor(log($size, $base))) > $limit ? $limit : $_;
        $prefix = array_flip(self::UNIT_PREFIXES_POWERS)[$power];
        $multiple = ($useBinaryPrefix ? strtoupper($prefix) . 'iB' : $prefix . 'B');
        return round($size / pow($base, $power), $precision) . $multiple;
    }

    // ...
}

Source:

https://github.com/mingalevme/utils/blob/master/src/Filesize.php https://github.com/mingalevme/utils/blob/master/tests/FilesizeTest.php

MingalevME
  • 1,827
  • 1
  • 22
  • 19
0

Here is a little more cleaned version according to the standards (Using answer above):

/**
 * Format kb, mb, gb, tb to bytes
 *
 * @param integer $size
 * @return integer
 */
function formatToBytes ($size)
{
    $aUnits = array('bytes' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4);
    $sUnit = strtoupper(trim(substr($size, -2)));
    if (intval($sUnit) !== 0) {
        $sUnit = 'bytes';
    }
    if (!in_array($sUnit, array_keys($aUnits))) {
        return false;
    }
    $iUnits = trim(substr($size, 0, strlen($size) - 2));
    if (!intval($iUnits) == $iUnits) {
        return false;
    }
    return $iUnits * pow(1024, $aUnits[$sUnit]);
}
MR_AMDEV
  • 1,712
  • 2
  • 21
  • 38