Variable handling 函数
在线手册:中文 英文
PHP手册

unserialize

(PHP 4, PHP 5)

unserialize 从已存储的表示中创建 PHP 的值

说明

mixed unserialize ( string $str [, string $callback ] )

unserialize() 对单一的已序列化的变量进行操作,将其转换回 PHP 的值。返回的是转换之后的值,可为 integerfloatstringarrayobject。如果传递的字符串不可解序列化,则返回 FALSE

Note: unserialize_callback_func 指令

如果在解序列化的时候需要实例化一个未定义类,则可以设置回调函数以供调用(以免得到的是不完整的 object “__PHP_Incomplete_Class”)。可通过 php.iniini_set().htaccess 定义‘unserialize_callback_func’。每次实例化一个未定义类时它都会被调用。若要禁止这个特性,只需置空此设定。还需要注意的是 unserialize_callback_func 指令是从 PHP 4.2.0 开始提供使用的。

Note:

callback 参数是在 PHP 4.2.0 中添加的

若被解序列化的变量是一个对象,在成功地重新构造对象之后,PHP 会自动地试图去调用 __wakeup() 成员函数(如果存在的话)。

Example #1 unserialize_callback_func 示例

<?php
$serialized_object
='O:1:"a":1:{s:5:"value";s:3:"100";}';

// unserialize_callback_func 从 PHP 4.2.0 起可用
ini_set('unserialize_callback_func','mycallback'); // 设置您的回调函数

function mycallback($classname) {
    
// 只需包含含有类定义的文件
    // $classname 指出需要的是哪一个类
}
?>

Note:

在 PHP 3 中,解序列化一个对象时是不保存方法的。而 PHP 4 打破了这个限制,同时保存了属性和方法。请参见类与对象中的序列化对象部分获取更多信息。

Example #2 unserialize() 示例

<?php
// 这里,我们使用 unserialize() 装载来自数据库的 $session_data 数组中的会话数据。
// 此例是描述 serialize() 的那个例子的补充。

$conn odbc_connect ("webdb""php""chicken");
$stmt odbc_prepare ($conn"SELECT data FROM sessions WHERE id = ?");
$sqldata = array ($PHP_AUTH_USER);
if (!
odbc_execute ($stmt, &$sqldata) || !odbc_fetch_into ($stmt, &$tmp)) {
    
// 如果执行出错或返回错误,则初始化为空数组
    
$session_data = array();
} else {
    
// 现在我们需要的是 $tmp[0] 中已序列化的数据。
    
$session_data unserialize ($tmp[0]);
    if (!
is_array ($session_data)) {
        
// 出错,初始化为空数组
        
$session_data = array();
    }
}
?>

参见 serialize()

参数

str

The serialized string.

If the variable being unserialized is an object, after successfully reconstructing the object PHP will automatically attempt to call the __wakeup() member function (if it exists).

Note: unserialize_callback_func directive

It's possible to set a callback-function which will be called, if an undefined class should be instantiated during unserializing. (to prevent getting an incomplete object "__PHP_Incomplete_Class".) Use your php.ini, ini_set() or .htaccess to define 'unserialize_callback_func'. Everytime an undefined class should be instantiated, it'll be called. To disable this feature just empty this setting.

返回值

The converted value is returned, and can be a boolean, integer, float, string, array or object.

In case the passed string is not unserializeable, FALSE is returned and E_NOTICE is issued.

更新日志

版本 说明
4.2.0 The directive unserialize_callback_func became available.

范例

Example #3 unserialize() example

<?php
// Here, we use unserialize() to load session data to the
// $session_data array from the string selected from a database.
// This example complements the one described with serialize().

$conn odbc_connect("webdb""php""chicken");
$stmt odbc_prepare($conn"SELECT data FROM sessions WHERE id = ?");
$sqldata = array($_SERVER['PHP_AUTH_USER']);
if (!
odbc_execute($stmt$sqldata) || !odbc_fetch_into($stmt$tmp)) {
    
// if the execute or fetch fails, initialize to empty array
    
$session_data = array();
} else {
    
// we should now have the serialized data in $tmp[0].
    
$session_data unserialize($tmp[0]);
    if (!
is_array($session_data)) {
        
// something went wrong, initialize to empty array
        
$session_data = array();
    }
}
?>

Example #4 unserialize_callback_func example

<?php
$serialized_object
='O:1:"a":1:{s:5:"value";s:3:"100";}';

// unserialize_callback_func directive available as of PHP 4.2.0
ini_set('unserialize_callback_func''mycallback'); // set your callback_function

function mycallback($classname
{
    
// just include a file containing your classdefinition
    // you get $classname to figure out which classdefinition is required
}
?>

注释

Warning

FALSE is returned both in the case of an error and if unserializing the serialized FALSE value. It is possible to catch this special case by comparing str with serialize(false) or by catching the issued E_NOTICE.

参见


Variable handling 函数
在线手册:中文 英文
PHP手册
PHP手册 - N: 从已存储的表示中创建 PHP 的值

用户评论:

php at deltatech-v2 dot de (26-Mar-2012 07:00)

I used Google-Oauth for authentication, got a &quot;Person-Object&quot; back and saved this in the database (serialized).
After unserializing, i got the PHP_INCOMPLETE-Class, because the Person-Class was not included.

To avoid this i converted the original-class to a PHP stdClass via Json:

&lt;?php
// Before: $me_data == Person()
$me_data = json_encode($me_data);
$me_data = json_decode($me_data);
// After: $me_data == stdClass()
?&gt;

suman dot jis at gmail dot com (13-Mar-2012 05:12)

I was getting unserialize()  Error at offset error.

If you face similar problem  then use the following procedure

$auctionDetails = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $dataArr[$i]['auction_details'] );
$auctionDetails = unserialize($auctionDetails);

dcz at phpbb-seo dot com (08-Nov-2011 02:00)

If you are unserializing content from user input and you don't expect objects to be passed (which should be the most common case), you can use this to prevent any object reviving threat :

<?php
/**
* mixed safe_unserialize(string $serialized)
* Safely unserialize, that is only unserialize string, numbers and arrays, not objects
*
* @license Public Domain
* @author dcz (at) phpbb-seo (dot) com
*/
function safe_unserialize($serialized) {
   
// unserialize will return false for object declared with small cap o
    // as well as if there is any ws between O and :
   
if (is_string($serialized) && strpos($serialized, "\0") === false) {
        if (
strpos($serialized, 'O:') === false) {
           
// the easy case, nothing to worry about
            // let unserialize do the job
           
return @unserialize($serialized);
        } else if (!
preg_match('/(^|;|{|})O:[0-9]+:"/', $serialized)) {
           
// in case we did have a string with O: in it,
            // but it was not a true serialized object
           
return @unserialize($serialized);
        }
    }
    return
false;
}
?>

Will simply return false if the serialized input contains an object or is not valid.

Example of a successful use of the object reviving threat : http://www.suspekt.org/2009/12/09/advisory-032009-piwik-cookie-unserialize-vulnerability/

frank at interactinet dot com (30-Aug-2011 05:32)

When dealing with sessions, try session_decode($data) instead of unserialize($data).

walf (23-Aug-2011 04:22)

a replacement for unserialize that returns whether it worked and populates the unserialized variable by reference:
<?php
function funserialize($serialized, &$into) {
    static
$sfalse;
    if (
$sfalse === null)
       
$sfalse = serialize(false);
   
$into = @unserialize($serialized);
    return
$into !== false || rtrim($serialized) === $sfalse;//whitespace at end of serialized var is ignored by PHP
}

$s_foo = 'b:0;';
var_dump(funserialize($s_foo, $foo), $foo);

$s_bar = 'bar';
var_dump(funserialize($s_bar, $bar), $bar);

$s_foo = 'a:0:{};';
var_dump(funserialize($s_foo, $foo), $foo);

?>
gives:

bool(true)
bool(false)

bool(false)
bool(false)

bool(true)
array(0) {
}

MBa (02-Aug-2011 11:49)

To check if a string is serialized:

$blSerialized=(@unserialize($sText)||$sText=='b:0;');

chris at colourlovers dot com (17-Jun-2011 01:31)

Anyone having trouble serializing data with SimpleXMLElement objects stored within it, check this out:

This will traverse $data looking for any children which are instances of SimpleXMLElement, and will run ->asXML() on them, turning them into a string and making them serializable. Other data will be left alone.

<?php
function exportNestedSimpleXML($data) {
    if (
is_scalar($data) === false) {
        foreach (
$data as $k => $v) {
            if (
$v instanceof SimpleXMLElement) {
               
$v = str_replace("&#13;","\r",$v->asXML());
            } else {
               
$v = exportNestedSimpleXML($v);
            }

            if (
is_array($data)) {
               
$data[$k] = $v;
            } else if (
is_object($data)) {
               
$data->$k = $v;
            }
        }
    }

    return
$data;
}

$data = array (
   
"baz" => array (
       
"foo" => new stdClass(),
       
"int" => 123,
       
"str" => "asdf",
       
"bar" => new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'),
    )
);

var_dump($data);
/*array(1) {
  ["baz"]=>
  array(4) {
    ["foo"]=>
    object(stdClass)#3 (0) {
    }
    ["int"]=>
    int(123)
    ["str"]=>
    string(4) "asdf"
    ["bar"]=>
    object(SimpleXMLElement)#4 (1) {
      [0]=>
      string(3) "bar"
    }
  }
}*/

var_dump(exportNestedSimpleXML($data));
/*array(1) {
  ["baz"]=>
  array(4) {
    ["foo"]=>
    object(stdClass)#3 (0) {
    }
    ["int"]=>
    int(123)
    ["str"]=>
    string(4) "asdf"
    ["bar"]=>
    string(54) "<?xml version="1.0" encoding="UTF-8"?>
<foo>bar</foo>
"
  }
}
*/
?>

martijntje at martijnotto dot nl (09-Jun-2011 09:50)

If you are storing serialized objects that persists between pageviews and you are using an autoloader, things may fall apart.

By default, when unserializing PHP will not call the autoloader when it discovers an unknown class. This can be fixed easily with the following directive in php.ini

unserialize_callback_func = 'spl_autoload_call'

i dot chiriac at yahoo dot com (01-May-2011 06:14)

Hi,

I'm working with serialized objects stored on files and I've found a problem and his fix when you modify the serialized object subclassing. When you serialize a class with a private property, the subclassing of this private property will simply not work because each private property is attached to it's class level.

For example, you start to implement and serialize this class :

<?php
 
class bar {
    private
$var = 'bar value';
    public function
getValue() {
      return
$this->var;
    }
  }
?>

You store an instance of the bar class into a file as a serialized string.

After some code refactoring you prefer to store the value in a subclass like this :

<?php
 
class foo {
    private
$var = 'bar value';
    public function
getValue() {
      return
$this->var;
    }
  }
  class
bar extends foo {
  }
?>

When you retrieve the stored bar instance from the srialized file, you have lose the $var value.

The only solution is to store private vars as protected properties and not private ones.

If you want to migrate/convert serialized private values as protected values you can use the following code :

<?php
   
function setProtected($serialized, $vars) {
      if (
$serialized[0] != 'O') {
        throw new
Exception('The serialized string is not representing a class');
      }
     
$size = '';       
      for(
$i = 2; $i < strlen($serialized); $i++) {
        if (
$serialized[$i] == ':') break;
       
$size .= $serialized[$i];
      }
     
$class = substr($serialized, $i + 2, $size);
     
$find = array();
     
$replace = array();
      foreach(
$vars as $name) {
       
$from = chr(0).$class.chr(0).$name;
       
$to = chr(0).'*'.chr(0).$name;
       
$find[] = 's:'.strlen($from).':"'.$from.'";';   
       
$replace[] = 's:'.strlen($to).':"'.$to.'";';
      }
    return
str_replace($find, $replace, $serialized);
  }
 
// example of use
 
$obj = unserialize(
   
setProtected(
     
file_get_contents('object.ser'),
      array(
'property1', 'propetyN')
    )
  );
?>

Hope this will helps someone,
aKhEnAtHoN

frank at interactinet dot com (28-Feb-2011 10:19)

When using a custom session handler to store sessions in a database,  loss of session data is probably not from unserializing data.

It is common to use regenerate_session_id() when a user logs in to prevent session fixation.

It turns out regenerate_session_id() does not automatically update the database. You need to do this manually:

<?php
$old
= session_id();
regenerate_session_id();
$new = session_id

$sql
= "update session_table set session_id = '$new' where session_id = '$old'";

?>

Hope this saves you some time.

daniel at fourstaples dot com (24-Mar-2010 04:46)

Here's a simple function to get the class of a serialized string (that is, the type of object that will be returned if it's unserialized):

<?php
function get_serial_class($serial) {
   
$types = array('s' => 'string', 'a' => 'array', 'b' => 'bool', 'i' => 'int', 'd' => 'float', 'N;' => 'NULL');
   
   
$parts = explode(':', $serial, 4);
    return isset(
$types[$parts[0]]) ? $types[$parts[0]] : trim($parts[2], '"');
}
?>

I use this when saving a serialized object to a cookie, to make sure it is the right type when I go to unserialize it.

The type names are the same format/case as you would see if you did a var_dump().

Fagzal (09-Mar-2010 06:10)

To all who have problem with quoting and slashes when storing serialized data in MySQL: you are probably doing it wrong.

Use e.g. PDO with placeholders and the blob column type, and it will Just Work.

VladSavitsky (21-Oct-2009 05:57)

To avoid data loss (problem with '\r\n') you can convert string to array and serialize an array.

Example:
<?php
//Store data:
$array = explode('\r\n', $string);
$serialized = serialize($array);

//Restore data:
$array = unserialize($serialized);
$text = implode('\r\n', $array);
?>

matty dot burke75 at gmail dot com (21-Sep-2009 11:18)

I've been having horrendous problems getting my saved to mysql serialized data to unserialize. All I got back was false.

However, one handy tip saved the day.

<?php
//to safely serialize
$safe_string_to_store = base64_encode(serialize($multidimensional_array));

//to unserialize...
$array_restored_from_db = unserialize(base64_decode($encoded_serialized_string));
?>

chaos (18-Sep-2009 03:15)

The methods here for correcting string lengths in UTF-8 encoded serialized data weren't reliable for me; various of the data I had stored broke them.  This is the method that handled all of my cases:

<?php
$serialized
= preg_replace_callback(
   
'!(?<=^|;)s:(\d+)(?=:"(.*?)";(?:}|a:|s:|b:|d:|i:|o:|N;))!s',
   
'serialize_fix_callback',
   
$serialized
);

function
serialize_fix_callback($match) {
    return
's:' . strlen($match[2]);
}
?>

[EDITOR thiago NOTE: This note has fixes from user "w33ble"]

TBag (17-Sep-2009 10:39)

With regard to might_serialize(), might_unserialize()  - which I posted about a week ago on this page. I've found that empy arrays will be serialized, but not unserialized.  To patch...

in: is_serialized()
change: preg_match("/^(i|s|a|o|d):(.*);/si",$val)
to: preg_match("/^(i|s|a|o|d):(.*);/si",$val) !== false

arbie samong (10-Sep-2009 03:42)

__PHP_Incomplete_Class Object Demystified

1. First take note of the output. A simple example:

__PHP_Incomplete_Class Object (
[__PHP_Incomplete_Class_Name] => SomeObject1
[obj1property1] => somevalue1 [obj1property2] => __PHP_Incomplete_Class Object ( [__PHP_Incomplete_Class_Name] => SomeObject2 [obj2property1] => somevalue1 [obj2property2] => Array (
['key1'] => somevalue3, ['key2'] => somevalue4 ) ) )

2. We analyze this and break it down.
__PHP_Incomplete_Class Object tells you there is an object that needs to be declared somehow.
__PHP_Incomplete_Class_Name simply tells you the expected class name. It is just one of the properties for now.

So we have:
a) an unknown object that has a class name SomeObject1 (first class)
b) it has 2 properties, namely obj1property1 and obj2property2
c) obj2property2 is itself an object whose class name is SomeObject2 (the second class)
d) SomeObject2 has two properties, obj2property1 and obj2property2
e) obj2property2 is an array that contains two elements

3. Now that we have an idea of the structure, we shall create class definitions based from it. We will just create properties for now, methods are not required as a minimum.

<?php
class SomeObject1 {
        public
$obj1property1;
        public
$obj1property2;
}
class
SomeObject2 {
        public
$obj2property1;
        public
$obj2property2;
}
?>

4. Have that accessible to your script and it will solve the __PHP_Incomplete_Class Object problem as far as the output is concerned. Now you will have:

SomeObject1 ( [obj1property1] => somevalue1 [obj1property2] => SomeObject2 ( [obj2property1] => somevalue1 [obj2property2] => Array ( ['key1'] => somevalue3, ['key2'] => somevalue4 ) ) )

As you will notice, __PHP_Incomplete_Class Object is gone and replaced by the class name. The property __PHP_Incomplete_Class_Name is also removed.

5. As for the array property obj2property2, we can directly access that and just assume that it is an array and loop through it:

<?php

// this will be SomeObject1
$data = unserialize($serialized_data);

// this will be SomeObject2
$data2 = $data->obj1property2();

foreach(
$data2->obj2property2 as $key => $value):
         print
$key.' : '. $value .'<br>';
endforeach;

?>

Outputs:
key1 : somevalue3
key2 : somevalue4

That's it. You can add more methods on the class declarations for the given properties, provided you keep your original output as basis for the data types.

TBag (07-Sep-2009 08:46)

My first post on php.net.  Hope someone finds it helpfull.  These few functions will serialize and unserialize arrays and objects.  It works recursively too.  I call them "might_..." because they test to see if any action is required.

<?php
function might_serialize($val){
    if(
is_object($val)){
       
$obj_keys = array_keys(get_object_vars($val));
        foreach(
$obj_keys as $k){ $val->$k = might_serialize($val->$k); }
       
$val = serialize($val);
    }
    if(
is_array($val)){
        foreach(
$val as &$v){ $v = might_serialize($v); }
       
$val = serialize($val);
    }
   
    return
$val;
}
function
might_unserialized($val){
   
//$pattern = "/.*\{(.*)\}/";
   
if(is_serialized($val)){
       
$ret = unserialize($val);
            foreach(
$ret as &$r){
                   
$r = might_unserialized($r);
            }
           
            return
$ret;
    }else { return
$val; }
}
function
is_serialized($val){
    if (!
is_string($val)){ return false; }
    if (
trim($val) == "") { return false; }
   
//if (preg_match("/^(i|s|a|o|d)(.*);/si",$val)) { return true; }
   
if (preg_match("/^(i|s|a|o|d):(.*);/si",$val) !== false) { return true; }
    return
false;
}
?>

CEO at CarPool2Camp dot org (26-Apr-2009 05:12)

Be aware that this function may not play nicely with SimpleXML

<?php // RAY_serialize.php
error_reporting(E_ALL);
echo
"<pre>";

// SOME TEST DATA
$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
<books>
  <book>Book 1</book>
  <book>Book 2</book>
  <book>Book 3</book>
</books>'
;

// MAKE OBJECT
$obj = SimpleXML_Load_String($xml);

// HAVE A LOOK AT THE OBJECT
var_dump($obj);

// SERIALIZE THE OBJECT
$txt = serialize($obj);

// SHOW THE TEXT FORM OF THE SERIALIZED OBJECT
var_dump($txt);

// TRY TO RETURN IT TO OBJECT STATUS
$new = unserialize($txt); // Warning: unserialize() [function.unserialize]: Node no longer exists in /home/www/public_html/RAY_serialize.php on line 38
?>

w dot laurencine at teknoa dot net (07-Apr-2009 01:54)

When dealing with a string which contain "\r", it seems that the length is not evaluated correctly. The following solves the problem for me :

<?php
// remove the \r caracters from the $unserialized string
$unserialized = str_replace("\r","",$unserialized);

// and then unserialize()
unserialize($unserialized);
?>

Gary (02-Apr-2009 01:49)

Removing __PHP_Incomplete_Class Object

this code will remove the __PHP_Incomplete_Class Object error when trying to pull data from a text sql file you dont know the class name of. i am simply using the data to generate a report
i have looked for something like this so hopefully this example will help someone the basic php to call the function is

$session_data = base64_decode($YOURSERIALIZEDDATA);
       $decodedtext=unserializeUnknownObject($session_data);

if base64 encoded

or
       $decodedtext=unserializeUnknownObject($YOURSERIALIZEDDATA);

if simply serialized

include_once 'include\phperrorclass.php';
<?php
  
class MyClass {}
  
$object = unserialize($serializedData);
?>
include_once 'include\phperrorfunction.php';
<?php
  
function unserializeUnknownObject($text)
   {
      
$matches = Array();
      
preg_match_all('/O:(\d)*:"([^":]*)":/', $text, $matches);
       foreach (
$matches[2] as $class)
       {
       if (!
class_exists($class, False)) {
                       eval(
'class '.$class.' { }');
                                            }
       }
       return
unserialize($text);
   }
  
$object = unserializeUnknownObject($serializedData);
?>
sample code

<?php
//declare the unknown object
include_once 'include\phperrorclass.php';
include_once
'include\phperrorfunction.php';
//declare the unserialize function  
$abs_path = dirname(dirname(__FILE__));
include
$abs_path.'\sunshop_reports\include\config.php';
// Connects to your Database
$connection=mysql_connect($servername, $dbusername, $dbpassword) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
$sql_query=" SELECT * FROM `ss_orders_products` LIMIT 0 , 30";
$result=mysql_query($sql_query,$connection);
if (!
$result)
{
die(
'Invalid query: ' . mysql_error());
}
 
$session_data = array();
   while(
$row=mysql_fetch_array($result))
   {
      
$return[] = $row;
       echo(
"  OrderID - ");
      
print_r($row[1]);
       echo(
"  Data Array - ");
      
$pulledata=($row[4]); 
      
$session_data = base64_decode($row[4]);
      
$decodedtext=unserializeUnknownObject($session_data);
       echo
nl2br("\n");
      
print_r($decodedtext);
       echo
nl2br("\n");
       echo
nl2br("\n");
   }

?>

John Smart (10-Feb-2009 12:35)

I also had a problem unserializing UTF-8 TEXT data from mysql.  However, the problem isn't with the text as much as it is from the connection layer.  Make sure you are connecting to mysql with the default-character-set optional set to utf8. Otherwise, you'll get back a bunch of ???? characters for UTF-8 text.

Ariz JAcinto (07-Oct-2008 07:47)

Here's another way of removing the  "__PHP_Incomplete_Class" notice especially if you're fetching the serialized object from a remote web service meaning, you don't have local copy of the class defining the object.

You can fix this by creating a class on the local machine that would define the object (*methods wouldn't be necessary).

Ex.

Object (Before):

object(__PHP_Incomplete_Class)#123 (3) {
  ["__PHP_Incomplete_Class_Name"]=>
    string(10) "SomeObject"
  ["property_one"]=>
    string(5) "Hello"
  ["property_two"]=>
    string(5) "World"
}

Class:

class SomeObject{

 public $property_one;
 public $property_two;

}

Object (After):

object(SomeObject)#31 (2) {
  ["property_one"]=>
    string(5) "Hello"
  ["property_two"]=>
    string(5) "World"
}

ogjuiceloc at yahoo dot com (16-Sep-2008 06:32)

Good time saving post by campbell at vertesi dot com on 24-May-2008 01:52 for how base64_encode is needed before storing as mySQL text. 

The order of unserializing is reversed however as you need to call base64_decode before unserialize.  Example:

<?php
$unserialized_array
= unserialize (base64_decode($serialized_array));
?>

chris AT cmbuckley DOT co DOT uk (14-Aug-2008 02:47)

As mentioned in the notes, unserialize returns false in the event of an error and for boolean false. Here is the first solution mentioned, without using error handling:

<?php
function isSerialized($str) {
    return (
$str == serialize(false) || @unserialize($str) !== false);
}

var_dump(isSerialized('s:6:"foobar";')); // bool(true)
var_dump(isSerialized('foobar'));        // bool(false)
var_dump(isSerialized('b:0;'));          // bool(true)
?>

chris at r3i dot it (28-Jul-2008 12:24)

@ Igor for single quote trouble:

<?php
function mb_unserialize($serial_str) {
$out = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
return
unserialize($out);
}
?>

Unserialize with utf8 content get trouble and the code provided by the guy works fine.

Code isn't mine: thanks to http://www.lastfm.pl/user/TheMariner

pierre dot spring at liip dot ch (23-Jun-2008 01:18)

props to steve at bluearena dot com and getmequick at gmail dot com

when using the regex proposed by steve at bluearena dot com when working with serialized objects that have been utf-8 encoded, i ran into a problem...

"\0" became 2 characters, instead of the zero ascii character.

the solution is pretty subtle:
<? php
# zero ascii "\0" becomes '\0'
$error = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $unserialized );
$works = preg_replace('!s:(\d+):"(.*?)";!se', '"s:".strlen("$2").":\"$2\";"', $unserialized );
?>

campbell at vertesi dot com (24-May-2008 09:52)

One thing to note - if you're storing your serialized string in a MySQL TEXT field, it will remove the {s and }s that make your string valid for unserialization.

I almost killed myself figuring this out - I'm sure it's basic but I had to post my solution - encode the serialized string in base 64.

$mood = array('angry','sad','happy');

$storable = base64_encode(serialize($mood));

then when you retrieve it from the database, you can access the string with

$mood=base64_decode(unserialize($storable));

dev at atshop3d dot com (13-Mar-2008 12:19)

Thanks to Igor who helped provide the solution to this. Serialize is very strict when it comes to quotes, and I spent _days_ figuring out why MySQL/PostgreSQL/etc. and locally set serialized strings returned a blank array, testing with both double and single quotes to see which one works.

Changing literal single quotes to "&#039" (I'm using numeric reference since &rsquo; and &lsquo; are different) and double quotes to "&quot;" cures all problems, while changing only one at a time only remedies a few of them. I'm interested to hear if other people have different experiences.

For example, the following string works:

<?php
//--------------------------------------------
// Set the example value. It doesn't matter if the string is from
// a database query or locally set - the side-effects are the same.
$heightoptionslist = <<<HEIGHTEND
a:3:{s:37:"Hands/inches (eg. 13&#039; 2&quot;HH)";s:6:"option";s:25:"Inches only (eg.39&quot;)";s:6:"option";s:24:"Centimeters (eg. 153cms)";s:6:"option";}
HEIGHTEND;
//--------------------------------------------
// Change the serialized string back to an array.
$heightoptionslist = unserialize($heightoptionslist);
//--------------------------------------------
// Output the value in a format we can understand.
echo "<div><pre>\$heightoptionslist = [\n".print_r($heightoptionslist, true)."\n]</pre></div>";
?>

while a string containing literal quotes doesn't (in nearly all cases on this machine):

<?php
//--------------------------------------------
// Another example value,
// this time with escaped literal quotes
$heightoptionslist = <<<HEIGHTEND
a:3:{s:26:"Hands/inches (eg. 13\' 2\"HH)";s:6:"option";s:20:"Inches only (eg.39\")";s:6:"option";s:24:"Centimeters (eg. 153cms)";s:6:"option";}
HEIGHTEND;
//--------------------------------------------
// Change the serialized string back to an array.
$heightoptionslist = unserialize($heightoptionslist);
//--------------------------------------------
// And return a blank array for some fun.
echo "<div><pre>\$heightoptionslist = [\n".print_r($heightoptionslist, true)."\n]</pre></div>";
?>

rhm31 at cam dot ac dot uk (30-Jan-2008 01:44)

Problem: I needed a way to call an object that I did not know the name of. This forced me to use a variable for the class name.

Solution: unserialize();

GACK! This is imaginative, but horrid.

Firstly, I thought this would work:
$object=new $class_name();

Otherwise, something like below will work:
$object=eval("new $class_name()");

You can use a normal constructor this way too.

jsa1971 at gmail dot com (14-Sep-2007 03:41)

Ignore all the advice to implement __autoload-ers or magical handlers, to solve problems when retrieving class instances from sessions.  It leads to terrible debugging nightmares.

After fussing with all sorts of such solutions and getting nowhere, I've found a very simple solution that works correctly and explicitly:

$_SESSION['myInstance'] = serialize($myInstance);

....

$myInstance_s = @$SESSION['myInstance']
if (!is_null($myInstance_s)) {
    $myInstance = unserialize($myInstance_s);
}

In other words, serialize the thing as a string, and put it in the session in this state - you regain control of the unserialization process and can code to handle exception cases rather than praying php's black magic does the right thing (and being sorely disappointed when it doesn't).

cory at lavacube dot com (03-Sep-2007 02:45)

Problem: I needed a way to call an object that I did not know the name of. This forced me to use a variable for the class name.

Solution: unserialize();

Unserialize supports opening objects/classes from a serialized string. In order to do so I had to do something to this effect:

<?php

// this is the variable part
$class_name = 'Some_Obscure_Class';

// here is where we take the name and dynamically create a serialize-compliant string.
$quickload = 'O:' . strlen($class_name) . ':"' .$class_name. '":0:{}';

// and here we inject the string into unserialize, this creating an object! :-)
$object = unserialize($quickload);

?>

From here I used the __wakeup() magic function to initialize/construct the class as needed. :-)

deminy at deminy dot net (08-Aug-2007 05:46)

Reply to eoin's post:

The regular expression you used to unserialize a PHP session file won't work if the session file contains string variable which contains character "|".

As I can see now, there is no any regular expression that can easily split data in a PHP session file. To read data from a session file, we may have to write a function to read content from the file, and then parse the content.

(This reply was also posted at http://www.php.net/manual/en/function.serialize.php to reply Erudd's post)

skinnepa at hotmail dot com (26-Jun-2007 06:42)

props to steve at bluearena dot com and getmequick at gmail dot com

Here's my implementation :p

function mb_unserialize($serial_str) {
    $out = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
    return unserialize($out);   
}

Works great for serialized UTF-8 content that doesn't like to be unserialized!

steve at bluearena dot com (15-Jun-2007 01:18)

To getmequick at gmail dot com

Your outstanding preg_replace

<? php
$unserialized = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $unserialized );
?>

helped me out of a hole after converting a database from latin1 to UTF8 and forgetting about how strict the strlen of serialized strings needs to be!

I just added the s modifier for it to be able to support whitespace and it fixed everything.

Thanks a million.

Ates Goral (04-May-2007 07:02)

If instead of using JSON, you'd like to stick with PHP-style serialization, here's some JavaScript code I posted at http://magnetiq.com for serializing JavaScript objects in PHP fashion:

/* Returns the class name of the argument or undefined if
   it's not a valid JavaScript object.
*/
function getObjectClass(obj)
{
    if (obj && obj.constructor && obj.constructor.toString)
    {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2)
        {
            return arr[1];
        }
    }

    return undefined;
}

/* Serializes the given argument, PHP-style.

   The type mapping is as follows:

   JavaScript Type    PHP Type
   ---------------    --------
   Number             Integer or Decimal
   String             String
   Boolean            Boolean
   Array              Array
   Object             Object
   undefined          Null

   The special JavaScript object null also becomes PHP Null.
   This function may not handle associative arrays or array
   objects with additional properties well.
*/
function phpSerialize(val)
{
    switch (typeof(val))
    {
    case "number":
        return (Math.floor(val) == val ? "i" : "d") + ":" +
            val + ";";
    case "string":
        return "s:" + val.length + ":\"" + val + "\";";
    case "boolean":
        return "b:" + (val ? "1" : "0") + ";";
    case "object":
        if (val == null)
        {
            return "N;";
        }
        else if ("length" in val)
        {
            var idxobj = { idx: -1 };

            return "a:" + val.length + ":{" + val.map(
                function (item)
                {
                    this.idx++;

                    var ser = phpSerialize(item);

                    return ser ?
                        phpSerialize(this.idx) + ser :
                        false;
                }, idxobj).filter(
                function (item)
                {
                    return item;
                }).join("") + "}";
        }
        else
        {
            var class_name = getObjectClass(val);

            if (class_name == undefined)
            {
                return false;
            }

            var props = new Array();

            for (var prop in val)
            {
                var ser = phpSerialize(val[prop]);

                if (ser)
                {
                    props.push(phpSerialize(prop) + ser);
                }
            }
            return "O:" + class_name.length + ":\"" +
                class_name + "\":" + props.length + ":{" +
                props.join("") + "}";
        }
    case "undefined":
        return "N;";
    }

    return false;
}

On the client side, you can pass in a complex (nested) JavaScript object to the phpSerialize function to get a PHP-style serialized representation. This string can be posted back and directly passed to the unserialize function to yield a representation of the complex object in PHP realm. Use of this technique requires caution on security matters.

me at no-spam dot com (10-Apr-2007 04:49)

A note to the last person. To avoid the incomplete class notice, all you need to do is make sure you include the class definition before session_start(); is called. Simple as that.

Elise van Looij (07-Apr-2007 10:15)

Thank you, thank you, thank you to Chris Hayes for

$_SESSION['my_object'] = unserialize(serialize($_SESSION['my_object']))

I wrestled through several very learned articles that dealt with creating factory classes for serializing objects and including the entire class definition in each and every file, yet one single line was all it took to stop my drupal module from whining about __PHP_Incomplete_Class when I tried to use load an instance from a session.

BenBE at omorphia dot de (02-Mar-2007 02:20)

When trying to serialize or unserialize recursive arrays or otherwise linked data you might find the undocumented R data type quite useful.

If you want a array like the one produced with
<?
$a = array();
$a[0] =& $a;
?>
serialized you can store it using a string simular to this one:
<?
$a = unserialize("a:1:{i:0;R:1;}");
?>

Both sources will make $a hold an array that self-references itself in index 0.

The argument for R is the index of the created sub-variable of the serialize-string beginning with 1.

julabz at laposte dot net (27-Feb-2007 04:07)

I couldn't get it with all these solutions, but it worked for me by mixing some of them this way:
<?php

function __serialize($object) {
   
$serialized = serialize($object);
       return
htmlentities($serialized,ENT_QUOTES);
}
//
function __unserialize($string) {
   
$unserialized = stripslashes($string);
      
$unserialized = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $unserialized );
       return
unserialize($unserialized);
}

?>

Angel from 4hoursgift.com (22-Feb-2007 05:16)

To Igor Defaye:

Thanks a lot. It worked to me.

unserialize() parameter ends when it first find a ' character, so if there is any it truncates the data and it does work properly.

(tested with PHP 4.4.1)

fuzzywoodlandcreatureSPAM at SUCKSgmail dot com (21-Feb-2007 04:59)

To Igor Defaye:
unserialize() works fine with anything I've thrown at it, single quotes included.  My guess is you're running into problems created by Magic Quotes.

Igor Defaye (16-Feb-2007 04:08)

It took me a good hour to figure out why serialized data stored in mysql database would not unserialize.
This is what I was trying to unserialize :
a:4:{i:0;s:43:"Date_Format(dateEntree,'%Y%m%d')";}

Addslashes did not work for me, I had to use :
str_replace("'", "\'", $serializedData)
in order to replace only sigle quotes and not double quotes, so I obtained this :
a:4:{i:0;s:43:"Date_Format(dateEntree,\'%Y%m%d\')";}

unserialize does not like single quotes.
Hope it can help someome.

double at dumpit dot com (19-Dec-2006 01:09)

This little function will check whether the serialized string is well formed.

PHP < 6 because i'd heard changes will be made in this php-intern function,
maybe it could be edited easy for it.

<?php

function wd_check_serialization( $string, &$errmsg )
{

   
$str = 's';
   
$array = 'a';
   
$integer = 'i';
   
$any = '[^}]*?';
   
$count = '\d+';
   
$content = '"(?:\\\";|.)*?";';
   
$open_tag = '\{';
   
$close_tag = '\}';
   
$parameter = "($str|$array|$integer|$any):($count)" . "(?:[:]($open_tag|$content)|[;])";           
   
$preg = "/$parameter|($close_tag)/";
    if( !
preg_match_all( $preg, $string, $matches ) )
    {           
       
$errmsg = 'not a serialized string';
        return
false;
    }   
   
$open_arrays = 0;
    foreach(
$matches[1] AS $key => $value )
    {
        if( !empty(
$value ) && ( $value != $array xor $value != $str xor $value != $integer ) )
        {
           
$errmsg = 'undefined datatype';
            return
false;
        }
        if(
$value == $array )
        {
           
$open_arrays++;                               
            if(
$matches[3][$key] != '{' )
            {
               
$errmsg = 'open tag expected';
                return
false;
            }
        }
        if(
$value == '' )
        {
            if(
$matches[4][$key] != '}' )
            {
               
$errmsg = 'close tag expected';
                return
false;
            }
           
$open_arrays--;
        }
        if(
$value == $str )
        {
           
$aVar = ltrim( $matches[3][$key], '"' );
           
$aVar = rtrim( $aVar, '";' );
            if(
strlen( $aVar ) != $matches[2][$key] )
            {
               
$errmsg = 'stringlen for string not match';
                return
false;
            }
        }
        if(
$value == $integer )
        {
            if( !empty(
$matches[3][$key] ) )
            {
               
$errmsg = 'unexpected data';
                return
false;
            }
            if( !
is_integer( (int)$matches[2][$key] ) )
            {
               
$errmsg = 'integer expected';
                return
false;
            }
        }
    }       
    if(
$open_arrays != 0 )
    {
       
$errmsg = 'wrong setted arrays';
        return
false;
    }
    return
true;
}

?>

getmequick at gmail dot com (20-Nov-2006 11:22)

for those who has error like "
error at offset .."

but doesn't know why.

This function might be usefull

<?php

$sObject3
= 'a:2:{i:0;s:1:"1";i:1;s:3654:"1a1dc91c907325c69271ddf0c944bc72";}';

print_r( __unserialize($sObject3  ));

function
__unserialize($sObject) {
   
   
$__ret =preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $sObject );
   
    return
unserialize($__ret);
   
}

?>

eakolb at dygel dot nizzet (02-Nov-2006 04:10)

Apparently, unserialize is really picky about anyone messing with the serial string. Just spent an hour debugging why unserialize wasn't working on a serial string stored in a database where, per client requirement, all inserted data is strtoupper'd. Can't just strtolower on a serial string, though -- if there are null values in there (signified as N;), they must be upper case.

The following call may be a bit convoluted, but it works.

unserialize(preg_replace('/;n;/', ';N;', strtolower($serial)))

Of course, if you have string data within that array, that'll get clobbered by the strtolower. In my case, I was dealing with integer values (aside from the key names). But this might save someone else out there a little trouble.

Are Pedersen (09-Aug-2006 09:46)

Be aware that if useing serialize/unserialize in a serverfarm with both 32bit and 64bit servers you can get unexpected results.

Ex: if you serialize an integer with value of 2147483648 on a 64bit system and then unserialize it on a 32bit system you will get the value -2147483648 instead. This is because an integer on 32bit cannot be above 2147483647 so it wraps.

chad 0x40 herballure 0x2e com (05-May-2006 05:08)

When unserializing in PHP5 (behavior observed with 5.1.2), __autoload() will be checked first, and unserialize_callback_func called only if __autoload failed to load the class definition.

fhummel at hotmail dot com (02-Mar-2006 05:37)

I have noticed that using the eval function as described in other posts might produce class redefinitions if separate class files are used and included.

My solution was to include_once at the top all .php files with classes that will be used on a particular page. This way the class definition exists when unserialize is called and you get the no duplicate check for free by using include_once.

Maybe someone can chime in on how this might affect performance.

onuryerlikaya at hotmail dot com (10-Feb-2006 12:00)

<?php

// Create your array()
$array = array("First","Second","Third");
// Create your package
$package = serialize($array);

// You can print your serialized package
// a:3:{i:0;s:5:"First";i:1;s:6:"Second";i:2;s:5:"Third";}
print $package."<br>";

// Unserialize your serialized package with print_r or var_dump
$data    = unserialize($package);
print_r($data);
// var_dump($data); // It's same as print_r
// Array ( [0] => First [1] => Second [2] => Third )
?>

Jules (29-Jan-2006 04:49)

"Moreover, you must be *very* careful when using eval() as it can be easily used to do something nasty."

Actually, you should probably be equally careful with unserialize, as using it might result in code from your (or standard PHP) classes being executed when you aren't expecting it.  It's clearly harder to exploit, but the possibility is there.  Therefore, only unserialize data that you know you generated yourself (either because it's stored where you put it, or because its signed, or has been validated in some other way).

mina86 at projektcode dot org (19-Jan-2006 06:28)

Accualy artistan's function does not work (there should be $serialized_data instead of $text in function body). Moreover, you must be *very* careful when using eval() as it can be easily used to do something nasty. Here comes what I've made basing on the two available versions:

<?php
function unserialize_data($str, $objs = true) {
    if (
$objs && preg_match_all('/O:\d+:"([a-zA-Z0-9_]+)":/', $str, $arr)) {
       
$callback = ini_get('unserialize_callback_func');
        foreach (
$arr[1] as $cls) {
            if (!
class_exists($cls)) {
               
call_user_func($callback, $cls);
            }
            if (!
class_exists($cls)) {
                eval(
'class ' . $cls . ' { }');
            }
        }
    }
    return
unserialize($str);  
}
?>

However, better (not tested though) sollution seems to be:

<?php
function declare_empty_class($classname) {
    static
$callback = null;
    if (
$callback===null) {
       
$callback = $classname;
        return;
    }
    if (
$callback) {
       
call_user_func($callback, $classname);
    }
    if (!
class_exists($classname)) {
        eval(
'class ' . $classname . ' { }');
    }
}
declare_empty_class(ini_get('unserialize_callback_func'));
ini_set('unserialize_callback_func', 'declare_empty_class');
?>

artistan at cableone dot net (11-Jan-2006 04:46)

// thanks to user comments I created this

    /**
        UnSerialize and return data
        @param string [$serialized_data] data to unserialize
        @return mixed
    */
    function unserialize_data($serialized_data,$objects=true){
        if($objects){
            // thanks to comment from veg@rd.no 04-Jan-2006 10:34 at http://us2.php.net/manual/en/function.unserialize.php
            // make classes for those that do not exist
            $matches = Array();
            preg_match_all('/O:(\d)*:"([^":]*)":/', $text, $matches);
            foreach ($matches[2] as $class)
            {
                if(!class_exists($class))
                    eval('class '.$class.' { }');
            }
        }
         return unserialize($serialized_data);
    }

// if using php5 you may want to modify to use __autoload function.

veg at rd dot no (04-Jan-2006 06:34)

Unserializing an object of a class that hasn't been declared where it is being unserialized will result in an unusable object. I do not know why this happens, but I know of two workarounds which I've written about here; http://vega.rd.no/entry/200601_serializing_objects_in_php

In short, the solution is to declare the class before unserializing the object; so this code will do when unserializing an object of type MyClass;

<?php
   
class MyClass {}
   
$object = unserialize($serializedData);
?>

However, if you have several different classes, which you don't necessarily know the names of beforehand, use this short function to handle it for you;

<?php
   
function unserializeUnknownObject($text)
    {
       
$matches = Array();
       
preg_match_all('/O:(\d)*:"([^":]*)":/', $text, $matches);
        foreach (
$matches[2] as $class)
        {
            eval(
'class '.$class.' { }');
        }
        return
unserialize($text);
    }
   
$object = unserializeUnknownObject($serializedData);
?>

This could also have been accomplished by using unserialize_callback_func.

tarwin at gmail dot com (18-Dec-2005 01:30)

I screwed around with this for hours and hours and it was doing my head in. Hopefully this can help.

When I was loading my page which was unserializing a string it would just hang (not finish sending information to the browser) at random places if I had not put the Class information first.

This is probably obvious (I know it says that it "will not work" if I do not declare the classes first) but the strange error of randomly stopping putting data to the page was very offputting from the actual error. It seems to go for a few KB or something and then just decide to stop.

none at none dot none (11-Dec-2005 03:57)

The only complaint I have about serializing, is that it will not save the variable name.  To fix this, as well as add support for more then one variable/array, I chose to write this class:

 class SaveVar
 {
  function store($list)
  {
   $sl = explode("|", $list);
   for ($i = 0; $i < count($sl); $i++)
   {
    $varname    = $sl[$i];
    global $$varname;
    $thevar     = $$varname;
    $serialized = serialize($thevar);
    $saved[$i] = base64_encode($varname)."@".base64_encode($serialized);
   }
   $data = implode("|", $saved);
   return($data);
  }

  function restore($stored)
  {
   $sv = explode("|", $stored);
   for ($i = 0; $i < count($sv); $i++)
   {
    $svp   = $sv[$i];
    list($name64, $value64) = explode("@", $svp);
    $name  = base64_decode($name64);
    $value = base64_decode($value64);
    global $$name;
    $$name = unserialize($value);
   }
  }
 }

----

An example of using this class is as follows...

----

 $arr1 = array("Hello", "World");
 $arr2 = array("World", "Hello");

 $sv = new SaveVar;

 $saved = $sv->store("arr1|arr2");

 $arr1 = NULL;
 $arr2 = NULL;

 echo $saved;
 echo "<HR>";
 $sv->restore($saved);

 print_r($arr1);
 echo "<BR>";
 print_r($arr2);

----

I hope someone finds this useful...

   -Jestin S Larson

martin dot goldinger at netserver dot ch (15-Aug-2005 12:48)

When you use sessions, its very important to keep the sessiondata small, due to low performance with unserialize. Every class shoud extend from this class. The result will be, that no null Values are written to the sessiondata. It will increase performance.

<?
class BaseObject
{
    function __sleep()
    {
        $vars = (array)$this;
        foreach ($vars as $key => $val)
        {
            if (is_null($val))
            {
                unset($vars[$key]);
            }
        }   
        return array_keys($vars);
    }
};
?>

ungu at terong dot com (05-Feb-2005 06:20)

I got the same case as yabba at the dot hut with his post
>> caveat: stripslashes!!!

In my server configutation the magic_quotes_gpc is on therefore it will automatically escape ' (single-quote), " (double quote), \ (backslash) and NUL's with a backslash.
And the stripslashes is the workaround for my case as well.

Erwin

Chris Hayes (chris at hypersites dot com) (23-Oct-2004 05:27)

In reply to the earlier post about having to include object definitions *before* using unserialize.  There is a workaround for this.

When an object is serialized, the first bit of the string is actually the name of the class.  When an unknown object is unserialized, this is maintained as a property.  So if you serialize it again, you get back the exact same string as if you'd serialized the original object.  Basically, to cut to the point...

If you use

$_SESSION['my_object'] = unserialize(serialize($_SESSION['my_object']))

then you get back an object of the correct type, even if the session had originally loaded it as an object of type stdClass.

hfuecks at phppatterns dot com (09-Sep-2004 12:14)

If you are accepting a serialized string from an untrusted source (e.g. generated in Javascript), you need to be careful to check that it doesn't result in "unexpected" objects being created when you unserialize it.

The following function pulls out the class names of all objects in a _valid_ serialized string. It works by first removing an serialized string values (which might contain serialized object syntax) then pulling out the class names from the remaining string. The returned value is a unique list of class names which the serialized string contains.

Note it assumes the serialized string is valid (that it will be accepted by unserialize()). There may be invalid serialized strings that could trick this function but these should fail when unserialized.

<?php
function getSerializedClassNames($string) {

   
// Stip any string representations (which might contain object syntax)
   
$string = preg_replace('/s:[0-9]+:".*"/Us','',$string);

   
// Pull out the class named
   
preg_match_all('/O:[0-9]+:"(.*)"/U', $string, $matches, PREG_PATTERN_ORDER);

   
// Make sure names are unique (same object serialized twice)
   
return array_unique($matches[1]);

}
?>

Unit tests for a version of this function can be found at:

http://cvs.sourceforge.net/viewcvs.py/xmlrpccom
    /scriptserver/tests/php/classparser.test.php?view=auto

See also the discussion here;
http://marc.theaimsgroup.com/?t=109439858700006&r=1&w=2
http://marc.theaimsgroup.com/?l=php-dev&m=109444959007776&w=2

pfister at avenir dot de (02-Sep-2004 10:25)

Having had a problem with an mysql-stored serialized array which I had edited I found out that unserialize seems to have got a problem with "\r" within the string I wanted to unserialize.

It simply quits it's job with "false".

To work arround this problem I just replaced \r with "":

<?php
$serializedArray
= 'a:1:{i:0;a:2:{s:4:"name";s:70:"Here comes the newline\r\nthis is the new line";s:5:"value";d:2.20;}}';

var_dump(unserialize($serializedArray)); //This just outputs bool(false)

$serializedArray = str_replace("\r", "", $serializedArray);

var_dump(unserialize($serializedArray)); //This outputs the array structure
?>

eoin at joy dot ucc dot ie (17-Aug-2004 07:38)

I recently found myself in need of unserializing PHP session data (stored in a database) that had expired but was not yet deleted i.e. I needed to get at the contents of the session but was unable to use the usual PHP interface. The following function takes a string of serialized session data and returns an array of PHP values. The structure of the returned array is the same as the $_SESSION array if you were using the normal interface. I haven't tested this extensively but it did the job for me.

<?php
function unserialize_session_data( $serialized_string ) {
   
$variables = array(  );
   
$a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
    for(
$i = 0; $i < count( $a ); $i = $i+2 ) {
       
$variables[$a[$i]] = unserialize( $a[$i+1] );
    }
    return(
$variables );
}
?>

yonman at gamer dot co dot il (30-May-2004 05:29)

yabba at the dot hut:

The cookie mechanism for the webserver adds the slashes automatically. instead of just dumping strings into the cookie, make sure you base64_encode them first - to protect the cookie's content from escape characters.

Of course, this means that when retrieving the cookie, you'll need to base64_decode the string.

(13-Mar-2004 06:42)

If a a string is unserializeable FALSE is returned as well as an E_NOTICE error. This is odd since you may want to know if a given string converts back to a PHP value and act accordingly. If you run your script with E_ALL reporting this will show up.

I noticed this debugging this line of code:
$b = unserialize(base64_decode($a));

Curiously, base64_decode() does not throw errors if the string can't be decoded. The only workaround is to prepend the @ operator to unserialize() or to change the error level.

yabba at the dot hut (28-Jan-2004 09:09)

caveat: stripslashes!!!

if using
       setcookie('hubba',serialize($data));
to set a cookie, you might want to check
       $data(unserialize(stripslashes($_COOKIE['hubba']));
to retrieve them back!!!

this is, if unserialize fails. you can also print_r($_COOKIE) to look into what you've got back.

beats me how the slashes got there in the first place....

Terry Johnson (10-Dec-2003 01:27)

It is possible to make a neat autoloader for class definitions using this, but there are some gotchas for the unwary programmer:

1) If you are setting the unserialize_callback_func directive in the ini or .htaccess file, use auto_prepend_file to load the definition of your callback function - otherwise objects that stay in the session may trigger errors on pages where you didn't expect the object to be used.

2) It helps if you define all your classes in files with lowercase file names from the beginning.  The callback function is always call with the class name in lower case, and it is a lot quicker to use that directly than make a lookup table:

function callback_func($classname) {
    @include_once("${classname}.class.php");
}

3) It does not appear to be possible to use a static member fuction of a class (for example, a your object persistence layer) as the unserialize callback function, so this will cause confusion:

php_value auto_prepend_file "Persist.php"
php_value unserialize_callback_func Persist::factory

The next best solution is to make it a function in the global scope and have your object factory call it as required:

Class Persist
{
    function &factory($type) {
        callback_func(strtolower($type));
        $classname = "${type}";
        if (!class_exists($classname)) {
            return PEAR::raiseError('Class Not Found',PERSIST_ERROR_CLASS_NOT_FOUND,PEAR_ERROR_RETURN);
        }
        @$obj =& new $classname;
        return $obj;
    }
...
}

aderyn at nowhere dot tld (30-Oct-2003 06:02)

A quick note:
If you store a serialized object in a session, you have to include the class _before_ you initialize (session_start()) the session.