tags:

views:

102

answers:

3

I need to test the value returned by ini_get('memory_limit') and increase the memory limit if it is below a certain threshold, however this ini_get('memory_limit') call returns string values like '128M' rather than integers.

I know I can write a function to parse these strings (taking case and trailing 'B's into account) as I have written them numerous times:

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

However, this gets tedious and this seems like one of those random things that would already exist in PHP, though I've never found it. Does anyone know of some built-in way to parse these byte-amount strings?

+2  A: 

From the PHP website for 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;
}
John Rasch
That doesn't actually handle the optional B on the end.
cletus
When does it have a B on the end? Is that platform specific?
John Rasch
Look at the OP's regex. There's an optional B at the end.
cletus
I added the 'B' and the white-space matches to the regular expression to make the function more generally useful than just being able to parse the values returned by `ini_get()`. The more general version will also handle decimal sizes as well, i.e.: 2.25MB
Adam Franco
+2  A: 

I think you're out of luck. The PHP manual for ini_get() actually addresses this specific problem in a warning about how ini_get() returns the ini values.

They provide a function in one of the examples to do exactly this, so I'm guessing it's the way to go:

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

They have this to say about the above function: "The example above shows one way to convert shorthand notation into bytes, much like how the PHP source does it."

zombat
Same problem as John's answer: doesn't handle the optional trailing B.
cletus
Yes, that's true. I was providing it mostly to illustrate how the PHP manual claims it's done. This would work if you wanted to only analyze results of `ini_get()`, otherwise you'd have to modify it yourself. The short answer to the posters question is really "No, there isn't a built-in method."
zombat
I was looking for this info in the description of the ini values and just about everywhere else other than the docs for the `ini_get()` function itself. Thanks for finding that.
Adam Franco
+2  A: 

I can only think of a slight variation on what you're doing:

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);
}
cletus
I actually like the original version even more then yours: no loops. At least no explicit loops :)
elcuco