【问题标题】:PHP convert KB MB GB TB etc to BytesPHP 将 KB MB GB TB 等转换为字节
【发布时间】:2012-08-02 04:11:34
【问题描述】:


我在问如何转换 KB MB GB TB & co。成字节。
例如:

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

等等……

编辑:哇。 4年前我问过这个问题。这种事情真的可以告诉你随着时间的推移你进步了多少!

【问题讨论】:

  • 将参数的数值乘以1024多次。
  • What have you tried? 另外,我确信 Google 搜索结果的第一页有一百个可用的函数。
  • @AlexLunix 什么都没有,我什至不知道如何开始,也没有在 google 中找到任何东西

标签: php byte type-conversion


【解决方案1】:

这是实现此目的的函数:

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));

输出:

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

【讨论】:

  • 对于 110GB 出现 Float returned 错误是不正确的。改用答案https://stackoverflow.com/questions/11807115/php-convert-kb-mb-gb-tb-etc-to-bytes/17364338#17364338
  • @MR_AMDEV 110GB 对我来说很好用,“110GB”真的是你在不工作时传入的吗?
  • 我似乎无法重现该结果,您能提供一个代码示例吗? 3v4l.org/6SNq9
  • 一种想法是,您正在运行的系统可能是 32 位的,并且将数字表示为浮点数,因为没有足够的空间容纳 int。如果是这种情况,您可以将返回类型更改为在您的系统上浮动,但请注意,大型浮动计算可能会出现意外结果。
  • 如果传递的大小像“20M”那么这个函数不能正常工作并返回20而不是正确的大小。
【解决方案2】:
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]);
}

【讨论】:

【解决方案3】:

这是我迄今为止提出的,我认为这是一个更优雅的解决方案:

/**
 * 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);
}

【讨论】:

  • 非常有趣的方法,我建议将正则表达式更改为 /^\s*([\d.]+)\s*(?:([kmgt]?)b?)?\s*$/i
【解决方案4】:

我使用一个函数来确定在一些 cron 脚本中为 PHP 设置的内存限制,如下所示:

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

类似的方法可以更好地处理浮点数并接受两个字母的缩写,如下所示:

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'))));
}

【讨论】:

    【解决方案5】:
    <?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";
    ?>
    

    【讨论】:

    • 这个版本看起来更好(我喜欢正则表达式:))
    • @user1494162 更慢更冗长。
    【解决方案6】:

    想要类似的东西并且由于各种原因不太喜欢这里发布的其他解决方案,我决定编写自己的函数:

    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;
    }
    

    它采用了 Al Jey(空白处理)和 John V(switch-case)在此提出的一些想法,但没有正则表达式,不调用 pow(),让 switch-case 在有不会中断,并且可以处理一些奇怪的用户输入(例如,“123 wonderful KB”会导致 125952)。我确信有一个更优化的解决方案,它涉及更少的指令,但代码会不太干净/可读。

    【讨论】:

      【解决方案7】:

      基于https://stackoverflow.com/a/17364338/1041470

      改进:

      • 修复了字节后缀长度的错误,
      • 允许使用双精度(浮点)值,但只能使用整数,
      • 包含单位的还原数组,
      • 重命名变量,
      • 添加了 cmets。
      /**
       * 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(check_plain($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]));
      }
      

      【讨论】:

        【解决方案8】:

        我只是在寻找这个函数,并接受了挑战,试图改进它,并把它变成了两行 :) 使用与 Eugene 类似的正则表达式来验证/提取值,但避免了 switch 语句。可以接受长 '10MB'、'10mb' 和短 '10M'、'10m' 值、十进制值并始终返回整数。无效字符串返回 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 ));
        }
        

        【讨论】:

          【解决方案9】:

          另一种解决方案 (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;
              }
          
              // ...
          }
          

          来源:

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

          【讨论】:

            【解决方案10】:

            我知道这是一个比较老的话题,但是当我需要这种东西时,我有时不得不使用这个功能;如果功能不起作用,您可以原谅,我是在手机上写的:

            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;
            }
            

            而且紧凑

            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;}
            

            保重!

            布罗德85 ;)

            【讨论】:

              【解决方案11】:

              根据标准,这是一个更干净的版本(使用上面的答案):

              /**
               * 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]);
              }
              

              【讨论】:

              • 此代码不能以 'bytes' 后缀正常工作 - 它会截断最后 N 位数字并且不允许浮点数/双精度数。查看我的版本:stackoverflow.com/a/65726567/1041470
              • @VladSavitsky 太棒了
              猜你喜欢
              • 2012-11-12
              • 1970-01-01
              • 2015-05-18
              • 2015-06-29
              • 1970-01-01
              • 1970-01-01
              • 2023-02-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多