You are here

function _safe_unserialize in Webform Multiple File Upload 6

Same name and namespace in other branches
  1. 7 safe_unserialize.inc \_safe_unserialize()

Safe unserialize() replacement

  • accepts a strict subset of PHP's native serialized representation
  • does not unserialize objects

@throw Exception if $str is malformed or contains unsupported types (e.g., resources, objects)

Parameters

string $str:

Return value

mixed

1 call to _safe_unserialize()
safe_unserialize in ./safe_unserialize.inc
Wrapper for _safe_unserialize() that handles exceptions and multibyte encoding issue

File

./safe_unserialize.inc, line 17
Contains helper functions for webform_multifile_update_7001().

Code

function _safe_unserialize($str) {
  if (empty($str) || !is_string($str)) {
    return false;
  }
  $stack = array();
  $expected = array();

  /*
   * states:
   *   0 - initial state, expecting a single value or array
   *   1 - terminal state
   *   2 - in array, expecting end of array or a key
   *   3 - in array, expecting value or another array
   */
  $state = 0;
  while ($state != 1) {
    $type = isset($str[0]) ? $str[0] : '';
    if ($type == '}') {
      $str = substr($str, 1);
    }
    else {
      if ($type == 'N' && $str[1] == ';') {
        $value = null;
        $str = substr($str, 2);
      }
      else {
        if ($type == 'b' && preg_match('/^b:([01]);/', $str, $matches)) {
          $value = $matches[1] == '1' ? true : false;
          $str = substr($str, 4);
        }
        else {
          if ($type == 'i' && preg_match('/^i:(-?[0-9]+);(.*)/s', $str, $matches)) {
            $value = (int) $matches[1];
            $str = $matches[2];
          }
          else {
            if ($type == 'd' && preg_match('/^d:(-?[0-9]+\\.?[0-9]*(E[+-][0-9]+)?);(.*)/s', $str, $matches)) {
              $value = (double) $matches[1];
              $str = $matches[3];
            }
            else {
              if ($type == 's' && preg_match('/^s:([0-9]+):"(.*)/s', $str, $matches) && substr($matches[2], (int) $matches[1], 2) == '";') {
                $value = substr($matches[2], 0, (int) $matches[1]);
                $str = substr($matches[2], (int) $matches[1] + 2);
              }
              else {
                if ($type == 'a' && preg_match('/^a:([0-9]+):{(.*)/s', $str, $matches)) {
                  $expectedLength = (int) $matches[1];
                  $str = $matches[2];
                }
                else {

                  // object or unknown/malformed type
                  return false;
                }
              }
            }
          }
        }
      }
    }
    switch ($state) {
      case 3:

        // in array, expecting value or another array
        if ($type == 'a') {
          $stack[] =& $list;
          $list[$key] = array();
          $list =& $list[$key];
          $expected[] = $expectedLength;
          $state = 2;
          break;
        }
        if ($type != '}') {
          $list[$key] = $value;
          $state = 2;
          break;
        }

        // missing array value
        return false;
      case 2:

        // in array, expecting end of array or a key
        if ($type == '}') {
          if (count($list) < end($expected)) {

            // array size less than expected
            return false;
          }
          unset($list);
          $list =& $stack[count($stack) - 1];
          array_pop($stack);

          // go to terminal state if we're at the end of the root array
          array_pop($expected);
          if (count($expected) == 0) {
            $state = 1;
          }
          break;
        }
        if ($type == 'i' || $type == 's') {
          if (count($list) >= end($expected)) {

            // array size exceeds expected length
            return false;
          }
          $key = $value;
          $state = 3;
          break;
        }

        // illegal array index type
        return false;
      case 0:

        // expecting array or value
        if ($type == 'a') {
          $data = array();
          $list =& $data;
          $expected[] = $expectedLength;
          $state = 2;
          break;
        }
        if ($type != '}') {
          $data = $value;
          $state = 1;
          break;
        }

        // not in array
        return false;
    }
  }
  if (!empty($str)) {

    // trailing data in input
    return false;
  }
  return $data;
}