You are here

safe_unserialize.inc in Webform Multiple File Upload 6

Same filename and directory in other branches
  1. 7 safe_unserialize.inc

Contains helper functions for webform_multifile_update_7001().

File

safe_unserialize.inc
View source
<?php

/**
 * @file
 * Contains helper functions for webform_multifile_update_7001().
 */

/**
 * Safe unserialize() replacement
 * - accepts a strict subset of PHP's native serialized representation
 * - does not unserialize objects
 *
 * @param string $str
 * @return mixed
 * @throw Exception if $str is malformed or contains unsupported types (e.g., resources, objects)
 */
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;
}

/**
 * Wrapper for _safe_unserialize() that handles exceptions and multibyte encoding issue
 *
 * @param string $str
 * @return mixed
 */
function safe_unserialize($str) {

  // ensure we use the byte count for strings even when strlen() is overloaded by mb_strlen()
  if (function_exists('mb_internal_encoding') && (int) ini_get('mbstring.func_overload') & 2) {
    $mbIntEnc = mb_internal_encoding();
    mb_internal_encoding('ASCII');
  }
  $out = _safe_unserialize($str);
  if (isset($mbIntEnc)) {
    mb_internal_encoding($mbIntEnc);
  }
  return $out;
}

Functions

Namesort descending Description
safe_unserialize Wrapper for _safe_unserialize() that handles exceptions and multibyte encoding issue
_safe_unserialize Safe unserialize() replacement