Uirapuru
Uirapuru

Reputation: 119

unserialize() stopped working after adding Serializable interface

I have an object that is stored in MySql using serialize().

Now I have updated the class definition by making it implement the Serializable interface, and I can't unserialize object because:

Erroneous data format for unserializing 'ClassName'

Debugging method unserialize() of this class does not help - it's not even called.

Just as an example, let's say I've got old (A) and new (B) declaration of class:

<?php

 class A {
     public $hello = "world";
 }

  class B implements Serializable {
     public $hello = "world";
     public function serialize() {}
     public function unserialize($serialized) { throw new Exception("test"); }
 }

now when I try to deserialize data:

$data1 = 'O:1:"A":1:{s:5:"hello";s:5:"world";}';
$data2 = 'O:1:"B":1:{s:5:"hello";s:5:"world";}';

var_dump(unserialize($data1));
var_dump(unserialize($data2));

I get

object(A)#2 (1) {
  ["hello"]=>
  string(5) "world"
}
<br />
<b>Warning</b>:  Erroneous data format for unserializing 'B' in <b>[...][...]</b> on line <b>20</b><br />
<br />
<b>Notice</b>:  unserialize(): Error at offset 11 of 36 bytes in <b>[...][...]</b> on line <b>20</b><br />
bool(false)

Upvotes: 2

Views: 353

Answers (1)

yivi
yivi

Reputation: 47370

The problem is that classes implementing Serializable and those not implementing the interface use a different serialization format.

Classes that do not implement the interface will use "O notation":

O:1:"A":1:{s:5:"hello";s:5:"world";}

Whereas classes imlementing Serializable will use "C notation". Your B class, serializaed would look like this:

C:1:"B":12:{s:5:"world";}

Unserializing just won't work because you are trying to unserialize to the "wrong" definition.

This change came about in 5.6, was reported as a bug and the response was wontfix because of the security implications of the old behavior.

What you are trying to do only worked from PHP 5.3 to 5.5, as far as I can tell. Documentation used to mention that for classes implementing Serializable the __wakeup() method was called before calling unserialize() but that was part of what was removed on 5.6.

You'll need to use some workaround to unserialize that data, and in the long term I would migrate the serialized data to a safer, more portable format like JSON.

Upvotes: 2

Related Questions