How to repair a serialized string which has been corrupted by an incorrect byte count length?
unserialize() [function.unserialize]: Error at offset
was dues to invalid serialization data
due to invalid length
Quick Fix
What you can do is is recalculating the length
of the elements in serialized array
You current serialized data
$data = 'a:10:{s:16:"submit_editorial";b:0;s:15:"submit_orig_url";s:13:"www.bbc.co.uk";s:12:"submit_title";s:14:"No title found";s:14:"submit_content";s:12:"dnfsdkfjdfdf";s:15:"submit_category";i:2;s:11:"submit_tags";s:3:"bbc";s:9:"submit_id";b:0;s:16:"submit_subscribe";i:0;s:15:"submit_comments";s:4:"open";s:5:"image";s:19:"C:fakepath100.jpg";}';
Example without recalculation
var_dump(unserialize($data));
Output
Notice: unserialize() [function.unserialize]: Error at offset 337 of 338 bytes
Recalculating
$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $data);
var_dump(unserialize($data));
Output
array
'submit_editorial' => boolean false
'submit_orig_url' => string 'www.bbc.co.uk' (length=13)
'submit_title' => string 'No title found' (length=14)
'submit_content' => string 'dnfsdkfjdfdf' (length=12)
'submit_category' => int 2
'submit_tags' => string 'bbc' (length=3)
'submit_id' => boolean false
'submit_subscribe' => int 0
'submit_comments' => string 'open' (length=4)
'image' => string 'C:fakepath100.jpg' (length=17)
Recommendation .. I
Instead of using this kind of quick fix ... i"ll advice you update the question with
How you are serializing your data
How you are Saving it ..
================================ EDIT 1 ===============================
The Error
The Error was generated because of use of double quote "
instead single quote '
that is why C:\fakepath\100.png
was converted to C:fakepath100.jpg
To fix the error
You need to change $h->vars['submitted_data']
From (Note the singe quite '
)
Replace
$h->vars['submitted_data']['image'] = "C:\fakepath\100.png" ;
With
$h->vars['submitted_data']['image'] = 'C:\fakepath\100.png' ;
Additional Filter
You can also add this simple filter before you call serialize
function satitize(&$value, $key)
{
$value = addslashes($value);
}
array_walk($h->vars['submitted_data'], "satitize");
If you have UTF Characters you can also run
$h->vars['submitted_data'] = array_map("utf8_encode",$h->vars['submitted_data']);
How to detect the problem in future serialized data
findSerializeError ( $data1 ) ;
Output
Diffrence 9 != 7
-> ORD number 57 != 55
-> Line Number = 315
-> Section Data1 = pen";s:5:"image";s:19:"C:fakepath100.jpg
-> Section Data2 = pen";s:5:"image";s:17:"C:fakepath100.jpg
^------- The Error (Element Length)
findSerializeError
Function
function findSerializeError($data1) {
echo "<pre>";
$data2 = preg_replace ( '!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'",$data1 );
$max = (strlen ( $data1 ) > strlen ( $data2 )) ? strlen ( $data1 ) : strlen ( $data2 );
echo $data1 . PHP_EOL;
echo $data2 . PHP_EOL;
for($i = 0; $i < $max; $i ++) {
if (@$data1 {$i} !== @$data2 {$i}) {
echo "Diffrence ", @$data1 {$i}, " != ", @$data2 {$i}, PHP_EOL;
echo "\t-> ORD number ", ord ( @$data1 {$i} ), " != ", ord ( @$data2 {$i} ), PHP_EOL;
echo "\t-> Line Number = $i" . PHP_EOL;
$start = ($i - 20);
$start = ($start < 0) ? 0 : $start;
$length = 40;
$point = $max - $i;
if ($point < 20) {
$rlength = 1;
$rpoint = - $point;
} else {
$rpoint = $length - 20;
$rlength = 1;
}
echo "\t-> Section Data1 = ", substr_replace ( substr ( $data1, $start, $length ), "<b style=\"color:green\">{$data1 {$i}}</b>", $rpoint, $rlength ), PHP_EOL;
echo "\t-> Section Data2 = ", substr_replace ( substr ( $data2, $start, $length ), "<b style=\"color:red\">{$data2 {$i}}</b>", $rpoint, $rlength ), PHP_EOL;
}
}
}
A better way to save to Database
$toDatabse = base64_encode(serialize($data)); // Save to database
$fromDatabase = unserialize(base64_decode($data)); //Getting Save Format
How to repair a serialized string that has been corrupted due to a removed slash before a single quote?
After doing further research I have found a work around solution. According to this blog post:
"It turns out that if there's a ", ', :, or ; in any of the array
values the serialization gets corrupted."
If I was working on a site that hadn't yet been put live, a prevention method would have been to base64_encode
my serialized data before it was stored in the database like so:
base64_encode( serialize( $my_data ) );
And then:
unserialize( base64_decode( $encoded_serialized_string ) );
when retrieving the data.
However, as I cannot change what has already been stored in the database, this very helpful post(original post no longer available, but looks like this) provides a solution that works around the problem:
$fixed_serialized_data = preg_replace_callback ( '!s:(\d+):"(.*?)";!', function($match) {
return ($match[1] == strlen($match[2])) ? $match[0] : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
}, $my_data );
$result = unserialize( $fixed_serialized_data );
PHP Unserilize is not working
Your serialized string has been damaged. As I rub my crystal ball, I can imagine someone manually performed string replacements (inappropriately) to update the url that immediately follows Have you listened
in the array at index 4
.
This is revealed after analyzing the data at this location:
s:1876:"Havе yоu listenеd
http://boletines.consumer.es/?p=50&u=https://gdfgl/96D4u9";
You see this stored value has 81 bytes/characters in it.
The serialized data strictly claims that the value must have 1876 bytes/characters in it.
Ultimately, your serialized data has been compromised -- either the length or the value.
If you are not bothered by the current value, you can manually repair the serialized data with this: https://3v4l.org/GqsHu
This is from a post of mine here: https://stackoverflow.com/a/55074706/2943403
With the provided snippet, you can either repair the corrupted serialized data on the fly each time, or you can take the time to repair all corrupted data and update your database so that this headache doesn't present itself again.
Let this occurrence be a lesson to developers -- Never try to take a short cut to update serialized data. You must unserialize it, modifying it, then re-serialize it so that a valid string is generated.
PHP: error: Notice: unserialize(): Error at offset 438 of 750 bytes in
Baba already wrote a great answer in this post. If you are in need of a quick fix, this code will do the job.
$data = preg_replace_callback(
'!s:(\d+):"(.*?)";!',
function($m) {
return 's:'.strlen($m[2]).':"'.$m[2].'";';
},
$sri);
var_dump(unserialize($data));
Saved state generates notice error at offset
The two missing characters are null bytes that are used for the protected attribute. You cannot see them but they are still there. Thus, your $string
is just not a valid serialization.
Update:
Actually the null bytes can be made visible (with the invalid character symbol) in UTF-8 encoding. You can see it in this demo if you select Output: Textbox
string(40) "O:6:"Object":1:{s:11:"�*�variable";b:1;}"
unserialize(): Error at offset 181 of 849 bytes
The second one is invalid the reason being that field s:12:"amount"
states that this value is a string of length 12. However amount
only has 6 bytes. so you want to use s:6:"amount"
That being said its probably easier to unserialize
then make a change then serialize
the new value.
Unserialize - Error at offset 9179 of 11507 bytes
This is probably an encoding issue. The issue starts with the string
s:137:"?A9 Hashrate is 50Ksol/s ...
When I copy the string it's only 135 bytes long, and it unserializes correctly with s:135:"...
You could correct those strings manually (there're only 4 of them in your example), or find out what charset you used for serialization and use the same for unserialization. I think the ? mark was a 3-byte character originally.
This issue came up in the past. For a semi automated solution you can try the regex in this answer. But that regex will choke when you have double quotes followed by semi-colons in your serialized strings.
Related Topics
Use PHP to Create, Edit and Delete Crontab Jobs
How to Remove  from the Beginning of a File
Getting the Screen Resolution Using PHP
Compare 2-Dimensional Data Sets Based on a Specified Second Level Value
When Do I Use the PHP Constant "PHP_Eol"
MySQLi_Query() Expects At Least 2 Parameters, 1 Given
PHP Sort a Multidimensional Array by Element Containing Y-M-D H:I:S Date
Sending Email With Gmail Smtp With Codeigniter Email Library
Property [Title] Does Not Exist on This Collection Instance
How to Strip All Spaces Out of a String in PHP
How to Call a Function from a String Stored in a Variable
How to Access Object Properties With Names Like Integers or Invalid Property Names