2

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)
yivi
  • 42,438
  • 18
  • 116
  • 138
Uirapuru
  • 119
  • 1
  • 8
  • Duplicate(?): https://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset – Pinke Helga Feb 16 '19 at 16:05
  • Is there any framework and/or extension installed? – Pinke Helga Feb 16 '19 at 16:17
  • 1
    nope, it's pure php 7.3 – Uirapuru Feb 16 '19 at 16:23
  • 1
    PHP's serialization is pretty unpredictable sometimes and is full of nuances. My guess is implementing the serialization interface somehow changes the serialization process (by altering what data to use) it's no more the same what it used to be when no interface was used, and therefore the serialization is complaining about invalid data. Better you migrate to json if possible. – Vinay Feb 16 '19 at 17:39
  • Close votes on this question are really no longer appropriate. It contains a complete MCVE reproducing the issue. – yivi Feb 18 '19 at 05:48

1 Answers1

2

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.

yivi
  • 42,438
  • 18
  • 116
  • 138