Есть ли в PHP простой способ конвертировать строки типа «256M», «180K», «4G» в их целочисленные эквиваленты? - PullRequest
13 голосов
/ 26 августа 2009

Мне нужно проверить значение, возвращаемое ini_get('memory_limit'), и увеличить предел памяти, если он ниже определенного порога, однако этот вызов ini_get('memory_limit') возвращает строковые значения, такие как '128M', а не целые числа.

Я знаю, что могу написать функцию для анализа этих строк (с учетом регистра и конечных 'B'), поскольку я писал их много раз:

function int_from_bytestring ($byteString) {
  preg_match('/^\s*([0-9.]+)\s*([KMGTPE])B?\s*$/i', $byteString, $matches);
  $num = (float)$matches[1];
  switch (strtoupper($matches[2])) {
    case 'E':
      $num = $num * 1024;
    case 'P':
      $num = $num * 1024;
    case 'T':
      $num = $num * 1024;
    case 'G':
      $num = $num * 1024;
    case 'M':
      $num = $num * 1024;
    case 'K':
      $num = $num * 1024;
  }

  return intval($num);
}

Однако, это становится утомительным, и это похоже на одну из тех случайных вещей, которые уже существуют в PHP, хотя я никогда не находил это. Кто-нибудь знает какой-нибудь встроенный способ разбора этих строк в байтах?

Ответы [ 6 ]

5 голосов
/ 06 января 2011

Или, если хотите, более короткая версия

function toInteger ($string)
{
    sscanf ($string, '%u%c', $number, $suffix);
    if (isset ($suffix))
    {
        $number = $number * pow (1024, strpos (' KMG', strtoupper($suffix)));
    }
    return $number;
}
5 голосов
/ 26 августа 2009

Я думаю, тебе не повезло. Руководство по PHP для ini_get () фактически решает эту конкретную проблему в предупреждении о том, как ini_get () возвращает значения ini.

Они предоставляют функцию в одном из примеров, чтобы сделать именно это, поэтому я думаю, что это путь:

function return_bytes($val) {
    $val = trim($val);
    $last = strtolower($val[strlen($val)-1]);
    switch($last) {
        // The 'G' modifier is available since PHP 5.1.0
        case 'g':
            $val *= 1024;
        case 'm':
            $val *= 1024;
        case 'k':
            $val *= 1024;
    }

    return $val;
}

У них есть то, что можно сказать о вышеупомянутой функции: «В приведенном выше примере показан один способ преобразования сокращенной записи в байты, очень похожий на то, как это делает исходный код PHP».

2 голосов
/ 26 августа 2009

Я могу думать только о небольшом отклонении от того, что вы делаете:

function int_from_bytestring($byteString) {
  $ret = 0;
  if (preg_match('!^\s*(\d+(?:\.\d+))\s*([KMNGTPE])B?\s*$!', $byteString, $matches)) {
    $suffix = " KMGTPE";
    $index = strpos($suffix, $matches[2]);
    if ($index !== false) {
      $ret = $matches[1];
      while ($index--) {
        $matches *= 1024;
      }
    }
  }
  return intval($ret);
}
2 голосов
/ 26 августа 2009

С веб-сайта PHP для ini_get():

function return_bytes($val) {
    $val = trim($val);
    $last = strtolower($val[strlen($val)-1]);
    switch($last) {
        // The 'G' modifier is available since PHP 5.1.0
        case 'g':
            $val *= 1024;
        case 'm':
            $val *= 1024;
        case 'k':
            $val *= 1024;
    }

    return $val;
}
0 голосов
/ 07 июня 2019

, даже если приведенные выше решения верны, оператор switch без break не очень интуитивен и для улучшения читабельности, чтобы выразить то, что действительно происходит, я бы предпочел сделать это следующим образом:

/**
 * @return int maximum memory limit in [byte]
 */
private static function takeMaximumFootprint()
{
    $memory = ini_get('memory_limit');
    $byte = intval($memory);
    $unit = strtolower($memory[strlen($memory) - 1]);
    switch ($unit) {
        case 'g':
            $byte *= 1024 * 1024 * 1024; break;
        case 'm':
            $byte *= 1024 * 1024; break;
        case 'k':
            $byte *= 1024; break;
    }

    return $byte;
}
0 голосов
/ 13 марта 2018

Поскольку в новых версиях PHP вы получите сообщение об ошибке, если в конце значения указан символ CHAR, вам может потребоваться дополнительное тестирование:

private function toBytes($str){
    $val = trim($str);
    $last = strtolower($str[strlen($str)-1]);
    if (!is_numeric($last)) {
        $val = substr($val,0,strlen($val)-1);
        switch($last) {
            case 'g': $val *= 1024;
            case 'm': $val *= 1024;
            case 'k': $val *= 1024;
        }
    }
    return $val;
}

Это работает без предупреждений

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...