Php Serialization serialize () and deserialization unserialize ()

Source: Internet
Author: User
Tags goto serialization urlencode

Compress complex data types into a string
 
Serialize () encodes variables and their values into text form
 
Unserialize () restore original variable
 
Eg:

The code is as follows: Copy code

$ Stooges = array ('Moe', 'Larry ', 'Curly ');
$ New = serialize ($ stooges );
Print_r ($ new );
Echo "<br/> ";
Print_r (unserialize ($ new ));

Result:
A: 3: {I: 0; s: 3: "Moe"; I: 1; s: 5: "Larry"; I: 2; s: 5: "Curly ";}
Array ([0] => Moe [1] => Larry [2] => Curly)

When the serialized data is placed in a URL and transmitted between pages, you need to call urlencode () to ensure that the URL metacharacters in the URL are processed:
 

The code is as follows: Copy code

$ Shopping = array ('Poppy seed bagel '=> 2, 'plain Bagel' => 1, 'lor' => 4 );

Echo '<a href = "next. php? Cart = '. urlencode (serialize ($ shopping).' "> next </a> ';

The settings of the margic_quotes_gpc and magic_quotes_runtime parameters affect the data transmitted to unserialize.
 
If magic_quotes_gpc is enabled, stripslashes () must be used to process the data transmitted in URLs, POST variables, and cookies before Deserialization:
 

The code is as follows: Copy code

 

$ New_cart = unserialize (stripslashes ($ cart ));

// If magic_quotes_gpc is enabled
$ New_cart = unserialize ($ cart );

If magic_quotes_runtime is enabled, you must use addslashes () for processing before writing serialized data to the file, and use stripslashes () for processing before reading them:
 

The code is as follows: Copy code

$ Fp = fopen ('/tmp/cart', 'w ');

Fputs ($ fp, addslashes (serialize ($ )));

Fclose ($ fp );

// If magic_quotes_runtime is enabled
$ New_cat = unserialize (stripslashes (file_get_contents ('/tmp/cart ')));

// If magic_quotes_runtime is disabled
$ New_cat = unserialize (file_get_contents ('/tmp/cart '));

When magic_quotes_runtime is enabled, the serialized data read from the database must also be processed by stripslashes (). The serialized data saved to the database must be processed by addslashes, in order to be properly stored.

The code is as follows: Copy code

Mysql_query ("insert into cart (id, data) values (1, '". addslashes (serialize ($ cart ))."')");

$ Rs = mysql_query ('select data from cart where id = 1 ');

$ Ob = mysql_fetch_object ($ rs );

// If magic_quotes_runtime is enabled
$ New_cart = unserialize (stripslashes ($ ob-> data ));

// If magic_quotes_runtime is disabled
$ New_cart = unserialize ($ ob-> data );

When an object is deserialized, PHP automatically calls its _ wakeUp () method. This allows the object to re-establish various states that are not retained during serialization. For example, database connection.

Let me explain it to you using examples.

The code is as follows: Copy code

<? Php

// Declare a class

Class dog {

Var $ name;

Var $ age;

Var $ owner;

Function dog ($ in_name = "unnamed", $ in_age = "0", $ in_owner = "unknown "){

$ This-> name = $ in_name;

$ This-> age = $ in_age;

$ This-> owner = $ in_owner;

}

Function getage (){

Return ($ this-> age * 365 );

}

Function getowner (){

Return ($ this-> owner );

}

Function getname (){

Return ($ this-> name );

}

}

// Instantiate this class

$ Ourfirstdog = new dog ("Rover", 12, "Lisa and Graham ");

// Use the serialize function to convert this instance into a serialized string

$ Dogdisc = serialize ($ ourfirstdog );

Print $ dogdisc; // $ ourfirstdog has been serialized as a string O: 3: "dog": 3: {s: 4: "name"; s: 5: "Rover "; s: 3: "age"; I: 12; s: 5: "owner"; s: 15: "Lisa and Graham ";}

/*

Bytes -----------------------------------------------------------------------------------------

Here you can store the string $ dogdisc anywhere, such as session, cookie, database, and PHP files.

Bytes -----------------------------------------------------------------------------------------

*/

// Cancel this class here

Unset ($ ourfirstdog );

?>

B. php

<? Php

 

?>

<? Php

// Declare a class

Class dog {

Var $ name;

Var $ age;

Var $ owner;

Function dog ($ in_name = "unnamed", $ in_age = "0", $ in_owner = "unknown "){

$ This-> name = $ in_name;

$ This-> age = $ in_age;

$ This-> owner = $ in_owner;

}

Function getage (){

Return ($ this-> age * 365 );

}

Function getowner (){

Return ($ this-> owner );

}

Function getname (){

Return ($ this-> name );

}

}

/* Restore operation */

/*

Bytes -----------------------------------------------------------------------------------------

Here, you can read the string $ dogdisc from your storage location, such as session, cookie, database, and PHP files.

Bytes -----------------------------------------------------------------------------------------

*/

$ Dogdisc = 'O: 3: "dog": 3: {s: 4: "name"; s: 5: "Rover"; s: 3: "age "; i: 12; s: 5: "owner"; s: 15: "Lisa and Graham ";}';

// Here we use unserialize () to restore serialized objects.

$ Pet = unserialize ($ dogdisc); // $ pet is the previous $ ourfirstdog object.

// Get the age and name attributes

$ Old = $ pet-> getage ();

$ Name = $ pet-> getname ();

// This class can be used without instantiation at this time, and both attributes and values remain in the state before serialization.

Print "Our first dog is called $ name and is $ old days old <br> ";

?>

Security risks caused by inconsistent serialization and deserialization syntax parsing

. PHP string serialize ()-related source code analysis
------------------------------------

The code is as follows: Copy code

Static inline void php_var_serialize_string (smart_str * buf, char * str, int len )/*{{{*/
  {
Smart_str_appendl (buf, "s:", 2 );
Smart_str_append_long (buf, len );
Smart_str_appendl (buf, ": \" ", 2 );
Smart_str_appendl (buf, str, len );
Smart_str_appendl (buf, "\"; ", 2 );
  }

 


The code snippet above shows how serialize () serializes strings as follows:

 

The code is as follows: Copy code
$ Str = 'ryatsyne ';
Var_dump (serialize ($ str ));
// $ Str serialized string output
// S: 8: "ryatsyne ";

Ii. PHP string unserialize () source code analysis
---------------------------------------

The unserialize () function deserializes strings in two formats:

The code is as follows: Copy code

Switch (yych ){
...
Case's ': goto yy9;
...
Yy9:
Yych = * (YYMARKER = ++ YYCURSOR );
If (yych = ':') goto yy46;
Goto yy3;
...
Yy46:
Yych = * ++ YYCURSOR;
If (yych = '+') goto yy47;
If (yych <= '/') goto yy18;
If (yych <= '9') goto yy48;
Goto yy18;
Yy47:
Yych = * ++ YYCURSOR;
If (yych <= '/') goto yy18;
If (yych> = ':') goto yy18;
Yy48:
++ YYCURSOR;
If (YYLIMIT-YYCURSOR) <2) YYFILL (2 );
Yych = * YYCURSOR;
If (yych <= '/') goto yy18;
If (yych <= '9') goto yy48;
If (yych> = ';') goto yy18;
Yych = * ++ YYCURSOR;
If (yych! = '"') Goto yy18;
++ YYCURSOR;
{
Size_t len, maxlen;
Char * str;
 
Len = parse_uiv (start + 2 );
Maxlen = max-YYCURSOR;
If (maxlen <len ){
* P = start + 2;
Return 0;
}
 
Str = (char *) YYCURSOR;
 
YYCURSOR + = len;
 
If (* (YYCURSOR )! = '"'){
* P = YYCURSOR;
Return 0;
}
// Make sure the format is s: x: "x"
 
YYCURSOR + = 2;
* P = YYCURSOR;
// Note here, * the p pointer directly moves two digits behind, that is to say, it does not judge whether "is followed;
 
INIT_PZVAL (* rval );
ZVAL_STRINGL (* rval, str, len, 1 );
Return 1;

 

The other is to process the series string in the S: format (this format is not defined in serialize () function serialization ):

The code is as follows: Copy code

Static char * unserialize_str (const unsigned char ** p, size_t * len, size_t maxlen)
  {
Size_t I, j;
Char * str = safe_emalloc (* len, 1, 1 );
Unsigned char * end = * (unsigned char **) p + maxlen;
 
If (end <* p ){
Efree (str );
Return NULL;
}
 
For (I = 0; I <* len; I ++ ){
If (* p> = end ){
Efree (str );
Return NULL;
  }
If (** p! = '\\'){
Str [I] = (char) ** p;
} Else {
Unsigned char ch = 0;
 
For (j = 0; j <2; j ++ ){
(* P) ++;
If (** p> = '0' & ** p <= '9 '){
Ch = (ch <4) + (** p-'0 ');
} Else if (** p> = 'A' & ** p <= 'F '){
Ch = (ch <4) + (** p-'A' + 10 );
} Else if (** p> = 'A' & ** p <= 'F '){
Ch = (ch <4) + (** p-'A' + 10 );
} Else {
Efree (str );
Return NULL;
  }
}
Str [I] = (char) ch;
  }
(* P) ++;
}
Str [I] = 0;
* Len = I;
Return str;
  }
// The above function is to convert a hexadecimal string like \ 72 \ 79 \ 61 \ 74 \ 73 \ 79 \ 6e \ 65
...
Switch (yych ){
...
Case's ': goto yy10;
// The processing process is the same as that of s:
If (str = unserialize_str (& YYCURSOR, & len, maxlen) = NULL ){
Return 0;
}
// The processing process is the same as that of s:

 

From the code snippet above, we can see that unserialize () processes the serialized string deserialization as follows:

The code is as follows: Copy code

$ Str1 ='s: 8: "ryatsyne ";';
$ Str2 ='s: 8: "ryatsyne" t ';
$ Str3 ='s: 8: "\ 72 \ 79 \ 61 \ 74 \ 73 \ 79 \ 6e \ 65 "';
Var_dump (unserialize ($ str ));
// $ Str1, $ str2 and $ str3 unserialized string output
// Ryatsyne;

 

Iii. Security risks caused by inconsistent syntax parsing
-----------------------------

From the above analysis process, we can see that PHP does not strictly follow the serialization format s: x: "x"; when deserializing the string, and does not judge whether "is followed, at the same time, the processing of hexadecimal strings is added, which makes the inconsistency between the pre-processing and post-processing confusing. Due to the absence of detailed descriptions in the PHP Manual, most programmers do not understand this process, which may lead to omissions in the coding process, and even cause serious security problems.

Back to the IPB vulnerability mentioned at the beginning of the article, we can use this funny feature of PHP to easily filter bypass safeUnserialize () function :)

The code is as follows: Copy code

* 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
*/
Static public function safeUnserialize ($ 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;
}
 
// A: 1: {s: 8: "ryatsyne" tO: 8: "ryatsyne": 0 :{}}
// As long as similar serialized strings are constructed, the filter here can be easily broken through.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.