How to Repair a Serialized String Which Has Been Corrupted by an Incorrect Byte Count Length

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



Leave a reply



Submit