How to repair a serialized string which has been corrupted by an incorrect byte count length?

后端 未结 15 1818
后悔当初
后悔当初 2020-11-22 11:46

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()

相关标签:
15条回答
  • 2020-11-22 12:48

    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.

    0 讨论(0)
  • 2020-11-22 12:50
    $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"
    }
    
    0 讨论(0)
  • 2020-11-22 12:51

    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 );
    
    0 讨论(0)
提交回复
热议问题