go to bug id or search bugs for
Unserialize method of PHP corrupts random values inside serialized objects. Corrupted value may be a string (in this case it is clearly visible on the website).
We have encountered this issue on every PHP version from 5.3 to 5.5
and multiple environments (linux, windows). PHP 5.2 was free from this bug (version switching proved it).
The corruption occurs only on some value combinations, for example after we change one of the string values the corruption does not appear, when we changed it back: the corruption occurs again.
The type of object does not matter, it often happens for stdClass.
Please check an example object, which was used in Test script:
Please compare it with the object which is an output of unserialize function.
Clearly one of the values has changed:
Instead of "Make-up & Styling", value is now: "Make-up ' Sty
Please note that pasting of the corrupt string works only until letter "y", please check the load_corrupt.txt file to see the full string.
The corruption may have a various form, it can be an additional letter, changed letter, for example: "Stylid" instead of "Styling".
file_put_contents('load.txt', $data); // correct object
file_put_contents('load_corrupt.txt', serialize(unserialize($data))); // one of the value was changed by unserialize, we serialize it back to save it to file
"make-up-styling";s:4:"name";s:17:"Make-up & Styling"
s:15:"make-up-styling";s:4:"name";s:17:"Make-up ' Sty
Add a Patch
Add a Pull Request
It seems that serialize function has something to do with it, it gives different outputs:
Case1, output of:
Case 2, output of:
I attach this example, because data corruption does seem to occur in Case 1. It seems only to occur in Case 2.
Please excuse the error in the sentence:
I attach this example, because data corruption does NOT seem to occur in Case 1. It seems only to occur in Case 2.
It turns out I simplified Case 1 too much, I attach the whole information again:
It seems that serialize function has something to do with it. It returns different outputs in the following cases:
echo serialize($data); // output:
echo serialize($data); // output:
Data corruption DOES NOT occur when I run unserialize on the output of Case 1.
Data corruption DOES occur when I run unserialize on the output of Case 2.
Example of the currupted outputs are attached in the original post.
To summarize: putting additional unserialize(serialize($data)); before serialize($data); seems to workaround the corruption by resulting in a different output of the second call of serialize function. This output can then be safely passed to unserialize function and the corruption does not occur.
The information in comments is irrelevant. The corruption does not occur, because the object itself changes, but it is the same with any change of it - only some combinations of values cause corruption. The difference in serialize output is related to classes serialize method which removes the "parent" field.
Regarding the original problem with unserialize corruption issue:
In this single case "Make-up & Styling" became "Make-up ' Sty ing"
& = hex 26 became ' = hex 27
l = hex 6c became (nul) = hex 00
The changes in characters are always different and seem random.
It is worth mentioning that the issue appears out of nowhere and can be fixed by restarting the server. It seems memory related. For this reason it is not possible to provide a bug testing snippet, because it simply won't create the same issue on another machine, although it may get it's own unique corruption on a random day.
The issue presents itself always on Apache server (various versions 2-2.4), mod_php or FCGI.
I just experienced the same issue on a totally different setup
apache + mod_php 5.5.11 + zend opcache
String "Opinion Leader des Tages"
became "Opinion Leader dfs Taes"
We just had the same issue on a different server (FCGI 5.4.27)
String currupted by unserialize:
"ticketshop-promo-summer-ticket" => "ticketshop-promo.summ(NUL)r-ticket"
"ticketshop-kilometer-bank" => "ticketshop-kilomfter-(NUL)ank"
"ticketshop-promo-spar-holiday" => "ticketshop-promo.spar(NUL)holiday"
"ticketshop-promo-weekend" => "ticketshop-promo.week(NUL)nd"
Is someone still encountering this problem in PHP >= 5.6? If so, could you please specify whether you use opcache? If you do, can you check whether you get a reproducible crash if you set opcache.protect_memory=1?
I wish you a Happy New Year with lots of happiness and joy.
It has been so long since the issue was reported, that we managed to implement some workarounds in the meantime and we do not encounter it anymore.
That said, if I encounter it again, I will open another issue, ok?
Maybe I should add that the issue was present for sure without opcache and it was not the case of shared memory, because we could repeat it any time, on any day with the same result and same corruption.
Not sure if this is the correct issue but I came across some problem with serialize/unserialize. (php-5.6.14)
I have created a gist to reproduce it:
The problem is that if an object contains a another object as child in multiple places that child does not get (un)serialized correctly. Not just that the identity of the multiple occurrences is not preserved but the object is not unserialized correctly at all. It's easier to understand by looking at gist.
@laszlokorte: That is most likely bug #66085, which is fixed in PHP 7.0 (but not 5.6).
@nikic Thanks, indeed the problem of the gist I posted is solved by php7. But in my real application I now get many "Notice: unserialize(): Error at offset 1026 of 1348 bytes" errors.
@laszlokorte, there's a mistake in your gist. Definition::unserialize should pass $data to unserialize, or use $value as a parameter. Unserializing an uninitialized variable causes the false values, and not unserializing the parameter messes up the references. See https://3v4l.org/vioIT .
@nikic, imho the cause of bug #66085 is serializing additional data during serialization. Of course this can result in similar behaviour. See https://3v4l.org/9hVS2 .
@jh1711 You re right. I fixed the bug in the gist. But mainDef is not correctly unserialized in php<7 anyway and in my real application I still get the "unserialize(): Error at offset 1026 of 1348 byte error" in a similar but more complex situation (deeper nestings, more properties, but no cycles)
@laszlokorte: In that case you're probably hit by bug #66052 (see also my comment on bug #73253).