114

I am using Hotaru CMS with the Image Upload plugin, I get this error if I try to attach an image to a post, otherwise there is no error:

unserialize() [function.unserialize]: Error at offset

The offending code (error points to line with **):

/**
     * Retrieve submission step data
     *
     * @param $key - empty when setting
     * @return bool
     */
    public function loadSubmitData($h, $key = '')
    {
        // delete everything in this table older than 30 minutes:
        $this->deleteTempData($h->db);

        if (!$key) { return false; }

        $cleanKey = preg_replace('/[^a-z0-9]+/','',$key);
        if (strcmp($key,$cleanKey) != 0) {
            return false;
        } else {
            $sql = "SELECT tempdata_value FROM " . TABLE_TEMPDATA . " WHERE tempdata_key = %s ORDER BY tempdata_updatedts DESC LIMIT 1";
            $submitted_data = $h->db->get_var($h->db->prepare($sql, $key));
            **if ($submitted_data) { return unserialize($submitted_data); } else { return false; }** 
        }
    }

Data from the table, notice the end bit has the image info, I am not an expert in PHP so I was wondering what you guys/gals might think?

tempdata_value:

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";}

Edit: I think I've found the serialize bit...

/**
     * Save submission step data
     *
     * @return bool
     */
    public function saveSubmitData($h)
    {
        // delete everything in this table older than 30 minutes:
        $this->deleteTempData($h->db);

        $sid = preg_replace('/[^a-z0-9]+/i', '', session_id());
        $key = md5(microtime() . $sid . rand());
        $sql = "INSERT INTO " . TABLE_TEMPDATA . " (tempdata_key, tempdata_value, tempdata_updateby) VALUES (%s,%s, %d)";
        $h->db->query($h->db->prepare($sql, $key, serialize($h->vars['submitted_data']), $h->currentUser->id));
        return $key;
    }
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
user576820
  • 1,289
  • 2
  • 11
  • 13
  • 3
    For me the quick fix for this was using base64_encode / decode before serialize / unserialize. http://davidwalsh.name/php-serialize-unserialize-issues – Valentin Despa Jun 12 '13 at 09:15
  • 1
    i dont know why but mine solved with added @, `@unserialize($product->des_txtmopscol);` – Bhavin Rana Oct 16 '13 at 11:29
  • 5
    @BhavinRana adding `@` is not error resolving, it is error silencing -- nothing actually "gets fixed" with that technique. – mickmackusa Apr 08 '19 at 08:06

17 Answers17

236

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 
Baba
  • 94,024
  • 28
  • 166
  • 217
  • 1
    Baba, I used your amazing `findSerializeError` function and found a lots of errors. Please take a look at [my topic](http://stackoverflow.com/questions/19469068/unserialize-function-unserialize-error-at-offset-65530-of-65535-bytes) – Max Koretskyi Oct 19 '13 at 17:39
  • 1
    use `base64` on Article before adding it to the database ... it would preserve the null character – Baba Oct 19 '13 at 18:36
  • thanks! I used base64_encode\base64_decode thing and it worked. But now I get the same error with different data and it's not working even with base64_encode\base64_decode thing in place. What does your function do? – Max Koretskyi Oct 20 '13 at 12:00
  • What does your function do? I've created a [topic](http://stackoverflow.com/questions/19477115/what-does-findserializeerror-function-do) to investigate that. – Max Koretskyi Oct 20 '13 at 13:58
  • 1
    That is so not a better way to save to the database. It is, unless you want to completely neglect the purpose of the database. How are you going to perform a search in a bunch of encrypted values? Not to mention the bloat, ugh. Proper encoding is the proper answer. – Deji Mar 04 '16 at 18:55
  • 4
    If using PHP 5.5, see @r00tAcc3ss answer! http://stackoverflow.com/a/21389439/1003020 – Vinicius Garcia Apr 29 '16 at 17:20
  • 6
    If you get this error " preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead" in php7 - this answer works https://stackoverflow.com/a/21389439/2011434 – BenB Aug 18 '17 at 19:53
  • Man, you saved my day! If someone from Czech Republic will be searching that - used for Mioweb Wordpress serialized DB fields! Don't know how some companies can still exist when selling code like this... – Jaroslav Štreit Oct 09 '20 at 21:14
108

I don't have enough reputation to comment, so I hope this is seen by people using the above "correct" answer:

Since php 5.5 the /e modifier in preg_replace() has been deprecated completely and the preg_match above will error out. The php documentation recommends using preg_match_callback in its place.

Please find the following solution as an alternative to the above proposed preg_match.

$fixed_data = preg_replace_callback ( '!s:(\d+):"(.*?)";!', function($match) {      
    return ($match[1] == strlen($match[2])) ? $match[0] : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
},$bad_data );
r00tAcc3ss
  • 1,281
  • 3
  • 10
  • 9
  • 3
    This seems like the only only answer on the page that actually puts the first capture group to good use. While sensible programming to only make replacements where the byte count is _actually_ wrong, this solution does not cache the `strlen()` and therefore makes redundant function calls. Personally, I find the addition of an inline condition to be too verbose, but this snippet is doing good things for good reasons. – mickmackusa Apr 08 '19 at 05:46
  • 6
    It worked for me with the following regex `'!s:(\d+):"(.*?)";!s'` (with an ending 's' to take new lines as well). Thanks to adilbo's comment below. – ArnoHolo Aug 27 '19 at 23:57
  • 3
    For me it failed on some complex serialized objects, so I used rexeg `'#s:(\d+):"(.*?)";(?=\\}*(?:[aOsidbN][:;]|\\z))#s'` – Sanya_Zol May 17 '21 at 10:53
  • Thanks! It used in a PHP7+ project and worked – Andrés Damesón Jan 04 '22 at 13:17
  • Sanya_Zol's regex worked for me, it is a complex data comprised of cyrillic text and HTML, thank you Sanya! – Milos Aug 21 '23 at 12:38
19

Quick Fix

Recalculating the length of the elements in serialized array - but don't use (preg_replace) it's deprecated - better use preg_replace_callback:

Edit: New Version now not just wrong length but it also fix line-breaks and count correct characters with aczent (thanks to mickmackusa)

// New Version
$data = preg_replace_callback('!s:\d+:"(.*?)";!s', 
    function($m) {
        return "s:" . strlen($m[1]) . ':"'.$m[1].'";'; 
    }, $data
);
adilbo
  • 910
  • 14
  • 22
  • 1
    How does this incorrect solution have 8 upvotes? I shutter to think how many people would have unwittingly copy pasted this one-liner. [sad face] Here is proof of two ways in which this snippet will fail: https://3v4l.org/Cf6Nh See my refined pattern and custom replacement @ https://stackoverflow.com/a/55074706/2943403 – mickmackusa Apr 07 '19 at 06:10
  • 1
    My solution is no longer at the other page because it was an incorrect solution for the catastrophically damaged serialized string. I've added my snippet to this page and provided explanation and demonstrations. https://stackoverflow.com/a/55566407/2943403 – mickmackusa Apr 08 '19 at 04:48
16

There's another reason unserialize() failed because you improperly put serialized data into the database see Official Explanation here. Since serialize() returns binary data and php variables don't care encoding methods, so that putting it into TEXT, VARCHAR() will cause this error.

Solution: store serialized data into BLOB in your table.

Ge Rong
  • 416
  • 5
  • 17
  • This solved my problem in Laravel 5. I changed the column definition from string() to binary(). – WNRosenberg Sep 09 '15 at 16:56
  • The OP's question does not appear to have a mysql column type issue. It is apparently corrupted by an incorrect byte calculation on the `image` value. Your answer does not pertain to the OP's specific question. You may wish to move your advice to: https://stackoverflow.com/q/5544749/2943403 – mickmackusa Apr 08 '19 at 05:35
10
$badData = 'a:2:{i:0;s:16:"as:45:"d";
Is \n";i:1;s:19:"as:45:"d";
Is \r\n";}';

You can not fix a broken serialize string using the proposed regexes:

$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $badData);
var_dump(@unserialize($data)); // Output: bool(false)

// or

$data = preg_replace_callback(
    '/s:(\d+):"(.*?)";/',
    function($m){
        return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);
var_dump(@unserialize($data)); // Output: bool(false)

You can fix broken serialize string using following regex:

$data = preg_replace_callback(
    '/(?<=^|\{|;)s:(\d+):\"(.*?)\";(?=[asbdiO]\:\d|N;|\}|$)/s',
    function($m){
        return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);

var_dump(@unserialize($data));

Output

array(2) {
  [0] =>
  string(17) "as:45:"d";
Is \n"
  [1] =>
  string(19) "as:45:"d";
Is \r\n"
}

or

array(2) {
  [0] =>
  string(16) "as:45:"d";
Is \n"
  [1] =>
  string(18) "as:45:"d";
Is \r\n"
}
6

This error is caused because your charset is wrong.

Set charset after open tag:

header('Content-Type: text/html; charset=utf-8');

And set charset utf8 in your database :

mysql_query("SET NAMES 'utf8'");
Will
  • 71
  • 1
  • 1
  • I don't see any indication in the OP's posted question to suggest that the corruption is due to the charset. Fee free to defend your claim, but as far as I can tell, someone has manually updated the `image` value and failed to update the byte count. Unless informed otherwise, I have to assume that this answer is incorrect for the OP's question. – mickmackusa Apr 08 '19 at 05:32
5
public function unserializeKeySkills($string) {
    $output = array();
    $string = trim(preg_replace('/\s\s+/', ' ',$string));
    $string = preg_replace_callback('!s:(\d+):"(.*?)";!', function($m) { return 's:'.strlen($m[2]).':"'.$m[2].'";'; }, utf8_encode( trim(preg_replace('/\s\s+/', ' ',$string)) ));
    try {
        $output =  unserialize($string);
    } catch (\Exception $e) {
        \Log::error("unserialize Data : " .print_r($string,true));
    }
    return $output;
}
Barry
  • 3,303
  • 7
  • 23
  • 42
Pardeep Goyal
  • 164
  • 1
  • 5
  • php unserialize – Pardeep Goyal Feb 28 '18 at 10:37
  • This solution is not suitable for many cases. It makes the assumption that everyone will want to mutation the values in the serialized string to convert 2-or-more whitespace characters to a literal space AND `trim()` every matched substring. **That point alone makes this solution impossible to recommend.** Furthermore, it will choke on newline characters and unnecessarily captures the pre-existing byte count which is just going to be overwritten anyhow. Finally, this is a "code-only answer" and these types of answers are low-value since they do little to educate/empower future researchers. – mickmackusa Apr 08 '19 at 05:28
3

You can fix broken serialize string using following function, with multibyte character handling.

function repairSerializeString($value)
{

    $regex = '/s:([0-9]+):"(.*?)"/';

    return preg_replace_callback(
        $regex, function($match) {
            return "s:".mb_strlen($match[2]).":\"".$match[2]."\""; 
        },
        $value
    );
}
Rajesh Meniya
  • 753
  • 1
  • 7
  • 17
  • The core of what this answer is recommending is simply wrong and will potentially damage perfectly valid serialized strings. This snippet should not be used/trusted. – mickmackusa Apr 08 '19 at 05:30
  • @mickmackusa I'm not getting your point, Can you please suggest best way to do it? or suggest edit on this answer.. – Rajesh Meniya Apr 08 '19 at 07:38
  • 1
    I have provided a correct solution here: https://stackoverflow.com/a/55566407/2943403 and explained that `mb_strlen()` is inappropriate because `serialize()` stores the byte count, not the character count. Editing your answer to be correct would only create redundant advice on the page. – mickmackusa Apr 08 '19 at 07:56
3

The corruption in this question is isolated to a single substring at the end of the serialized string with was probably manually replaced by someone who lazily wanted to update the image filename. This fact will be apparent in my demonstration link below using the OP's posted data -- in short, C:fakepath100.jpg does not have a length of 19, it should be 17.

Since the serialized string corruption is limited to an incorrect byte/character count number, the following will do a fine job of updating the corrupted string with the correct byte count value.

The following regex based replacement will only be effective in remedying byte counts, nothing more.

It looks like many of the earlier posts are just copy-pasting a regex pattern from someone else. There is no reason to capture the potentially corrupted byte count number if it isn't going to be used in the replacement. Also, adding the s pattern modifier is a reasonable inclusion in case a string value contains newlines/line returns.

*For those that are not aware of the treatment of multibyte characters with serializing, you must not use mb_strlen() in the custom callback because it is the byte count that is stored not the character count, see my output...

Code: (Demo with OP's data) (Demo with arbitrary sample data) (Demo with condition replacing)

$corrupted = <<<STRING
a:4:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";}
STRING;

$repaired = preg_replace_callback(
        '/s:\d+:"(.*?)";/s',
        //  ^^^- matched/consumed but not captured because not used in replacement
        function ($m) {
            return "s:" . strlen($m[1]) . ":\"{$m[1]}\";";
        },
        $corrupted
    );

echo $corrupted , "\n" , $repaired;
echo "\n---\n";
var_export(unserialize($repaired));

Output:

a:4:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
Newline2";i:3;s:6:"garçon";}
a:4:{i:0;s:5:"three";i:1;s:4:"five";i:2;s:17:"newline1
Newline2";i:3;s:7:"garçon";}
---
array (
  0 => 'three',
  1 => 'five',
  2 => 'newline1
Newline2',
  3 => 'garçon',
)

One leg down the rabbit hole... The above works fine even if double quotes occur in a string value, but if a string value contains "; or some other monkeywrenching sbustring, you'll need to go a little further and implement "lookarounds". My new pattern

checks that the leading s is:

  • the start of the entire input string or
  • preceded by ;

and checks that the "; is:

  • at the end of the entire input string or
  • followed by } or
  • followed by a string or integer declaration s: or i:

I haven't test each and every possibility; in fact, I am relatively unfamiliar with all of the possibilities in a serialized string because I never elect to work with serialized data -- always json in modern applications. If there are additional possible leading or trailing characters, leave a comment and I'll extend the lookarounds.

Extended snippet: (Demo)

$corrupted_byte_counts = <<<STRING
a:12:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";i:4;s:111:"double " quote \"escaped";i:5;s:1:"a,comma";i:6;s:9:"a:colon";i:7;s:0:"single 'quote";i:8;s:999:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:1:"monkey";wrenching doublequote-semicolon";s:3:"s:";s:9:"val s: val";}
STRING;

$repaired = preg_replace_callback(
        '/(?<=^|;)s:\d+:"(.*?)";(?=$|}|[si]:)/s',
        //^^^^^^^^--------------^^^^^^^^^^^^^-- some additional validation
        function ($m) {
            return 's:' . strlen($m[1]) . ":\"{$m[1]}\";";
        },
        $corrupted_byte_counts
    );

echo "corrupted serialized array:\n$corrupted_byte_counts";
echo "\n---\n";
echo "repaired serialized array:\n$repaired";
echo "\n---\n";
print_r(unserialize($repaired));

Output:

corrupted serialized array:
a:12:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";i:4;s:111:"double " quote \"escaped";i:5;s:1:"a,comma";i:6;s:9:"a:colon";i:7;s:0:"single 'quote";i:8;s:999:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:1:"monkey";wrenching doublequote-semicolon";s:3:"s:";s:9:"val s: val";}
---
repaired serialized array:
a:12:{i:0;s:5:"three";i:1;s:4:"five";i:2;s:17:"newline1
newline2";i:3;s:7:"garçon";i:4;s:24:"double " quote \"escaped";i:5;s:7:"a,comma";i:6;s:7:"a:colon";i:7;s:13:"single 'quote";i:8;s:10:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:39:"monkey";wrenching doublequote-semicolon";s:2:"s:";s:10:"val s: val";}
---
Array
(
    [0] => three
    [1] => five
    [2] => newline1
newline2
    [3] => garçon
    [4] => double " quote \"escaped
    [5] => a,comma
    [6] => a:colon
    [7] => single 'quote
    [8] => semi;colon
    [assoc] => yes
    [9] => monkey";wrenching doublequote-semicolon
    [s:] => val s: val
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
3

Here is an Online Tool for fixing a corrupted serialized string.

I'd like to add that this mostly happens due to a search and replace done on the DB and the serialization data(specially the key length) doesn't get updated as per the replace and that causes the "corruption".

Nonetheless, The above tool uses the following logic to fix the serialization data (Copied From Here).

function error_correction_serialise($string){
    // at first, check if "fixing" is really needed at all. After that, security checkup.
    if ( unserialize($string) !== true &&  preg_match('/^[aOs]:/', $string) ) {
         $string = preg_replace_callback( '/s\:(\d+)\:\"(.*?)\";/s',    function($matches){return 's:'.strlen($matches[2]).':"'.$matches[2].'";'; },   $string );
    }
    return $string;
} 
Mohd Abdul Mujib
  • 13,071
  • 8
  • 64
  • 88
2

the official docs says it should return false and set E_NOTICE

but since you got error then the error reporting is set to be triggered by E_NOTICE

here is a fix to allow you detect false returned by unserialize

$old_err=error_reporting(); 
error_reporting($old_err & ~E_NOTICE);
$object = unserialize($serialized_data);
error_reporting($old_err);

you might want to consider use base64 encode/decode

$string=base64_encode(serialize($obj));
unserialize(base64_decode($string));
Muayyad Alsadi
  • 1,506
  • 15
  • 23
  • `base64_encode` did the trick for me. Im my case we're passing `serialize`d data over the command line and it looked like some strange characters were preventing it from working correctly. – quickshiftin Feb 24 '16 at 18:31
  • `base64_encode()` is not the solution to the question asked by the OP. The OP's question/issue is specifically dealing with the fact that (likely do to an inappropriate substring replacement on the "final array element" of the serialized string) there is an incorrect byte count in the serialized string. Please only post answers that directly deal with the question asked. – mickmackusa Apr 08 '19 at 05:21
1

You will have to alter the collation type to utf8_unicode_ci and the problem will be fixed.

sth
  • 222,467
  • 53
  • 283
  • 367
Ankit Vishwakarma
  • 1,573
  • 16
  • 13
  • What specific character in the OP's sample data do you believe will be modified by changing the collation to `utf8_unicode_ci`? I have my doubts on this one. – mickmackusa Apr 08 '19 at 05:58
  • This also actually worked for me (apart from r00tAcc3ss' answer) any word from someone clarifying why? As background, I take data from an API call to a ResourceSpace application, store it in an array, serialize it and save it. The serialized data was having issues being saved so i had to manually encode it to UTF-8, I was playing around with collation and character set in the DB, and finally was left with utf8_general_ci collation, when I changed it to utf8_unicode_ci, it worked. – Roberto Becerra Dec 02 '19 at 08:09
1

In my case I was storing serialized data in BLOB field of MySQL DB which apparently wasn't big enough to contain the whole value and truncated it. Such a string obviously could not be unserialized.
Once converted that field to MEDIUMBLOB the problem dissipated. Also it may be needed to switch in table options ROW_FORMAT to DYNAMIC or COMPRESSED.

Adam Bubela
  • 9,433
  • 4
  • 27
  • 31
  • Me to - although mine was a `TEXT` field and as such truncated at 65kb. – Antony Oct 19 '16 at 08:22
  • This question does not suffer from truncation. The OP's question/issue is specifically dealing with the fact that (likely do to an inappropriate substring replacement on the "final array element" of the serialized string) there is an incorrect byte count in the serialized string. Please only post answers that directly deal with the question asked. – mickmackusa Apr 08 '19 at 05:09
1

After having tried some things on this page without success I had a look in the page-source and remarked that all quotes in the serialized string have been replaced by html-entities. Decoding these entities helps avoiding much headache:

$myVar = html_entity_decode($myVar);
David
  • 5,882
  • 3
  • 33
  • 44
  • This question does not suffer from html encoded entities in the serialized string. The OP's question/issue is specifically dealing with the fact that (likely do to an inappropriate substring replacement on the "final array element" of the serialized string) there is an incorrect byte count in the serialized string. Please only post answers that directly deal with the question asked. – mickmackusa Apr 08 '19 at 05:11
  • @mickmackusa This question is almost 7 years old and my answer ~1,5. Nevertheless nice that you engage so much! – David Apr 08 '19 at 05:35
  • I love SO pages -- young and old. I am looking out for researchers that don't know the difference between a good answer and a not-so-good answer. This page, unfortunatey, is full of off-topic advice. – mickmackusa Apr 08 '19 at 05:36
  • Great! There is already qualitiy control and voting, but I've no reason to stop you ;-) – David Apr 08 '19 at 05:38
  • Oh no, have a look. There are upvoted answers that should be downvoted. Too many people can't differentiate. On this page, the vote tally is absolutely no indication of quality / appropriateness. I am not going to waste my time downvoting because my downvote won't make a dent on the tally. The best I can do is leave comments to explain what is good/bad/ugly. – mickmackusa Apr 08 '19 at 05:40
  • I found this issue by the headline, and the described step was a solution for my own problem according to the headline. And someone found it helpful. So what? – David Apr 08 '19 at 05:42
  • That is the next thing on my list to do. (I'm working my way up the page from the bottom) -- Fix the question to clarify the Title and Question Body. – mickmackusa Apr 08 '19 at 05:44
  • So you think the question is still relevant to "Hotaru CMS"? Maybe the old code-base was completely replaced? – David Apr 08 '19 at 05:46
  • The `Hotaru CMS` part is irrelevant to researchers. The relevant part is explaining that the corruption is limited to a bad byte count. – mickmackusa Apr 08 '19 at 05:47
  • Ok, then good luck and see you at another question. I'm sure to see you again when you're so busy ;-) – David Apr 08 '19 at 05:51
  • This solution dose not work for the string '. Dose anyone solve this? – Leo S Nov 18 '20 at 03:17
  • @LeoS it depends exclusively on your string which solution might work. So if you've a special string and can't find a sufficient answer on this page or on Stack Overflow in general then open a new question and post your string there. – David Nov 18 '20 at 17:01
1

change the column size of the particular field(LONGTEXT)

ATHIRA
  • 11
  • 1
1

You can use this for all case:

$newdata = preg_replace_callback(
    '/(?<=^|\{|;)s:(\d+):\"(.*?)\";(?=[asbdiO]\:\d|N;|\}|$)/s',
    function($m){
        return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);
Lewis Smith
  • 1,271
  • 1
  • 14
  • 39
Pham Dai
  • 11
  • 1
0

Another reason of this problem can be column type of "payload" sessions table. If you have huge data on session, a text column wouldn't be enough. You will need MEDIUMTEXT or even LONGTEXT.

GarryOne
  • 1,430
  • 17
  • 21
  • This question does not suffer from truncation. The OP's question/issue is specifically dealing with the fact that (likely do to an inappropriate substring replacement on the "final array element" of the serialized string) there is an incorrect byte count in the serialized string. Please only post answers that directly deal with the question asked. – mickmackusa Apr 08 '19 at 05:19