I have stored data in the database in which there is an object that had private properties when serialize (), but at some point the object needed to be inherited and redefined and the properties became protected, and as a result, Unserialize () returns an object empty. How can the old data be adapted to the new object modifier?

There is an object:

class MyClass{ private $id; } 

Its serializable function serialize () property $id=123 . Then the object changes the modifier for the property.

 class MyClass{ protected $id; public function __wakeup() { if (is_string($this->id)) { $this->id = (int) $this->id } } } 

and when unserializing () with desiarization, we have a MyClass object with the $id property empty. there are also setters and getters for this property and __wakeup processing the $id property

  • Implement the __wakeup - u_mulder function
  • This is yes, but how do I adapt the modifiers, I have an object on `__wakeup` in $this for example 2 properties: id => null and AppBundle\MyEntity id => 123 - Samar
  • one

1 answer 1

He conducted a series of experiments. The answer to the question depends on the version of PHP.

Minimal example

File to serialize ser_priv.php :

 class MyClass{ private $id; public function __construct($id) { $this->id = $id; } } $o = new MyClass(123); file_put_contents(__DIR__ . '/data', serialize($o)); 

File to deserialize unser.php :

 class MyClass { // Заменили на protected protected $id; public function __construct($id) { $this->id = $id; } public function test() { $prop = new ReflectionProperty('MyClass', 'id'); printf("prop is protected: %d\n", $prop->isProtected()); printf("prop has value: %d\n", $this->id); } } $data = file_get_contents(__DIR__ . '/data'); $o = unserialize($data); $o->test(); 

On github

results

PHP 7.3.0RC4 : The protected property is set correctly, with the same value as before.

PHP 5.6.33 : The protected property is NOT set correctly after unserialize .

If you make var_dump($o); , it will be displayed

 object(MyClass)#1 (2) { ["id":protected]=> NULL ["id":"MyClass":private]=> int(123) } 

var_export($o); :

 MyClass::__set_state(array( 'id' => NULL, 'id' => 123, )) 

"Get" 123 decent way did not work. The indecent method of var_export and parsing did not consider the result, but this is also an option.

Now we serialize the same object, but in the first case it will be private , in the second it is protected . Let's see the binary, what happened:

 $ xxd data_priv 0000000: 4f3a 373a 224d 7943 6c61 7373 223a 313a O:7:"MyClass":1: 0000010: 7b73 3a31 313a 2200 4d79 436c 6173 7300 {s:11:".MyClass. 0000020: 6964 223b 693a 3132 333b 7d id";i:123;} $ xxd data_prot 0000000: 4f3a 373a 224d 7943 6c61 7373 223a 313a O:7:"MyClass":1: 0000010: 7b73 3a35 3a22 002a 0069 6422 3b69 3a31 {s:5:".*.id";i:1 0000020: 3233 3b7d 23;} 

It turns out that private is stored as ".MyClass.id", and protected as ". *. Id", only binary zeroes instead of dots. Well, the length of the string is different ( s:11 and s:5 ).

The idea is to replace private with protected . I don’t want to do something universal, maybe someone will be confused. Here is the minimum option for tinkering the id .

File unser_php56.php :

 class MyClass { // свойство с измененной областью видимости protected $id; } $data = file_get_contents(__DIR__ . '/data_priv'); $data = bin2hex($data); // Заменяем определение свойства $data = str_replace('31313a22004d79436c617373', '353a22002a', $data); $data = hex2bin($data); $o = unserialize($data); var_dump($o); 

Result:

 object(MyClass)#1 (1) { ["id":protected]=> int(123) }