Advertisement
jtl999

SMF 2.0.12 safe_unserialize

Oct 2nd, 2016
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 3.91 KB | None | 0 0
  1. /**
  2.  * Safe unserialize() replacement
  3.  * - accepts a strict subset of PHP's native serialized representation
  4.  * - does not unserialize objects
  5.  *
  6.  * @param string $str
  7.  * @return mixed
  8.  * @throw Exception if $str is malformed or contains unsupported types (e.g., resources, objects)
  9.  */
  10. function _safe_unserialize($str)
  11. {
  12.     // Input  is not a string.
  13.     if(empty($str) || !is_string($str))
  14.         return false;
  15.  
  16.     $stack = array();
  17.     $expected = array();
  18.  
  19.     /*
  20.      * states:
  21.      *   0 - initial state, expecting a single value or array
  22.      *   1 - terminal state
  23.      *   2 - in array, expecting end of array or a key
  24.      *   3 - in array, expecting value or another array
  25.      */
  26.     $state = 0;
  27.     while($state != 1)
  28.     {
  29.         $type = isset($str[0]) ? $str[0] : '';
  30.         if($type == '}')
  31.             $str = substr($str, 1);
  32.  
  33.         else if($type == 'N' && $str[1] == ';')
  34.         {
  35.             $value = null;
  36.             $str = substr($str, 2);
  37.         }
  38.         else if($type == 'b' && preg_match('/^b:([01]);/', $str, $matches))
  39.         {
  40.             $value = $matches[1] == '1' ? true : false;
  41.             $str = substr($str, 4);
  42.         }
  43.         else if($type == 'i' && preg_match('/^i:(-?[0-9]+);(.*)/s', $str, $matches))
  44.         {
  45.             $value = (int)$matches[1];
  46.             $str = $matches[2];
  47.         }
  48.         else if($type == 'd' && preg_match('/^d:(-?[0-9]+\.?[0-9]*(E[+-][0-9]+)?);(.*)/s', $str, $matches))
  49.         {
  50.             $value = (float)$matches[1];
  51.             $str = $matches[3];
  52.         }
  53.         else if($type == 's' && preg_match('/^s:([0-9]+):"(.*)/s', $str, $matches) && substr($matches[2], (int)$matches[1], 2) == '";')
  54.         {
  55.             $value = substr($matches[2], 0, (int)$matches[1]);
  56.             $str = substr($matches[2], (int)$matches[1] + 2);
  57.         }
  58.         else if($type == 'a' && preg_match('/^a:([0-9]+):{(.*)/s', $str, $matches))
  59.         {
  60.             $expectedLength = (int)$matches[1];
  61.             $str = $matches[2];
  62.         }
  63.  
  64.         // Object or unknown/malformed type.
  65.         else
  66.             return false;
  67.  
  68.         switch($state)
  69.         {
  70.             case 3: // In array, expecting value or another array.
  71.                 if($type == 'a')
  72.                 {
  73.                     $stack[] = &$list;
  74.                     $list[$key] = array();
  75.                     $list = &$list[$key];
  76.                     $expected[] = $expectedLength;
  77.                     $state = 2;
  78.                     break;
  79.                 }
  80.                 if($type != '}')
  81.                 {
  82.                     $list[$key] = $value;
  83.                     $state = 2;
  84.                     break;
  85.                 }
  86.  
  87.                 // Missing array value.
  88.                 return false;
  89.  
  90.             case 2: // in array, expecting end of array or a key
  91.                 if($type == '}')
  92.                 {
  93.                     // Array size is less than expected.
  94.                     if(count($list) < end($expected))
  95.                         return false;
  96.  
  97.                     unset($list);
  98.                     $list = &$stack[count($stack)-1];
  99.                     array_pop($stack);
  100.  
  101.                     // Go to terminal state if we're at the end of the root array.
  102.                     array_pop($expected);
  103.  
  104.                     if(count($expected) == 0)
  105.                         $state = 1;
  106.  
  107.                     break;
  108.                 }
  109.  
  110.                 if($type == 'i' || $type == 's')
  111.                 {
  112.                     // Array size exceeds expected length.
  113.                     if(count($list) >= end($expected))
  114.                         return false;
  115.  
  116.                     $key = $value;
  117.                     $state = 3;
  118.                     break;
  119.                 }
  120.  
  121.                 // Illegal array index type.
  122.                 return false;
  123.  
  124.             // Expecting array or value.
  125.             case 0:
  126.                 if($type == 'a')
  127.                 {
  128.                     $data = array();
  129.                     $list = &$data;
  130.                     $expected[] = $expectedLength;
  131.                     $state = 2;
  132.                     break;
  133.                 }
  134.  
  135.                 if($type != '}')
  136.                 {
  137.                     $data = $value;
  138.                     $state = 1;
  139.                     break;
  140.                 }
  141.  
  142.                 // Not in array.
  143.                 return false;
  144.         }
  145.     }
  146.  
  147.     // Trailing data in input.
  148.     if(!empty($str))
  149.         return false;
  150.  
  151.     return $data;
  152. }
  153.  
  154. /**
  155.  * Wrapper for _safe_unserialize() that handles exceptions and multibyte encoding issue
  156.  *
  157.  * @param string $str
  158.  * @return mixed
  159.  */
  160. function safe_unserialize($str)
  161. {
  162.     // Make sure we use the byte count for strings even when strlen() is overloaded by mb_strlen()
  163.     if (function_exists('mb_internal_encoding') &&
  164.         (((int) ini_get('mbstring.func_overload')) & 0x02))
  165.     {
  166.         $mbIntEnc = mb_internal_encoding();
  167.         mb_internal_encoding('ASCII');
  168.     }
  169.  
  170.     $out = _safe_unserialize($str);
  171.  
  172.     if (isset($mbIntEnc))
  173.         mb_internal_encoding($mbIntEnc);
  174.  
  175.     return $out;
  176. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement