如何修复因字节计数长度不正确而损坏的序列化字符串? [英] How to repair a serialized string which has been corrupted by an incorrect byte count length?

查看:35
本文介绍了如何修复因字节计数长度不正确而损坏的序列化字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Hotaru CMS 和图像上传插件,如果我尝试将图像附加到帖子,我会收到此错误,否则没有错误:

<块引用>

unserialize() [function.unserialize]:偏移量错误

违规代码(错误指向带有**的行):

/*** 检索提交步骤数据** @param $key - 设置时为空* @return 布尔值*/公共函数 loadSubmitData($h, $key = ''){//删除该表中超过 30 分钟的所有内容:$this->deleteTempData($h->db);if (!$key) { 返回假;}$cleanKey = preg_replace('/[^a-z0-9]+/','',$key);如果(strcmp($key,$cleanKey)!= 0){返回假;} 别的 {$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 { 返回假;}**}}

表格中的数据,注意末尾有图像信息,我不是 PHP 专家,所以我想知道你们/女孩会怎么想?

临时数据值:

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:"图像";s:19:"C:fakepath100.jpg";}

我想我已经找到了序列化位...

/*** 保存提交步骤数据** @return 布尔值*/公共函数 saveSubmitData($h){//删除该表中超过 30 分钟的所有内容:$this->deleteTempData($h->db);$sid = preg_replace('/[^a-z0-9]+/i', '', session_id());$key = md5(microtime() . $sid . rand());$sql = "插入".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));返回 $key;}

解决方案

unserialize() [function.unserialize]: Error at offset was due to invalid serialization data due到无效长度

快速修复

你可以做的是重新计算序列化数组中元素的长度

您当前的序列化数据

$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:"未找到标题";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:"图像";s:19:"C:fakepath100.jpg";}';

没有重新计算的例子

var_dump(unserialize($data));

输出

注意:unserialize() [function.unserialize]:338 字节的偏移量 337 处出错

重新计算

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

输出

数组'提交编辑' =>布尔假'submit_orig_url' =>字符串www.bbc.co.uk"(长度=13)'submit_title' =>字符串未找到标题"(长度 = 14)'submit_content' =>字符串dnfsdkfjdfdf"(长度=12)'submit_category' =>输入 2'submit_tags' =>字符串 'bbc'(长度 = 3)'submit_id' =>布尔假'submit_subscribe' =>整数 0'submit_comments' =>字符串打开"(长度=4)'图像' =>字符串'C:fakepath100.jpg'(长度=17)

推荐..我

不要使用这种快速修复......我建议你用

更新问题
  • 您如何序列化数据

  • 你是如何保存它的..

================================ 编辑 1 ================================

错误

错误是由于使用双引号 " 而不是单引号 ' 而产生的,这就是为什么 C:\fakepath\100.png被转换为C:fakepath100.jpg

修复错误

你需要把 $h->vars['submitted_data'] 改成(注意很')

替换

 $h->vars['submitted_data']['image'] = "C:\fakepath\100.png" ;

 $h->vars['submitted_data']['image'] = 'C:\fakepath\100.png' ;

附加过滤器

你也可以在调用序列化之前添加这个简单的过滤器

function satitize(&$value, $key){$value = addlashes($value);}array_walk($h->vars['submitted_data'], "satitize");

如果你有 UTF 字符,你也可以运行

 $h->vars['submitted_data'] = array_map("utf8_encode",$h->vars['submitted_data']);

如何检测未来序列化数据中的问题

 findSerializeError ( $data1 ) ;

输出

差异 9 != 7->ORD 编号 57 != 55->行号 = 315->Section Data1 = pen";s:5:"image";s:19:"C:fakepath100.jpg->Section Data2 = pen";s:5:"image";s:17:"C:fakepath100.jpg^------- 错误(元素长度)

findSerializeError 函数

function findSerializeError($data1) {echo "

";$data2 = preg_replace ( '!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'",$数据1);$max = (strlen ( $data1 ) > strlen ( $data2 )) ?strlen ( $data1 ) : strlen ( $data2 );回声 $data1 .PHP_EOL;回声 $data2 .PHP_EOL;for($i = 0; $i < $max; $i ++) {如果 (@$data1 {$i} !== @$data2 {$i}) {echo "差异", @$data1 {$i}, " != ", @$data2 {$i}, PHP_EOL;echo "\t-> ORD number ", ord ( @$data1 {$i} ), " != ", ord ( @$data2 {$i} ), PHP_EOL;echo "\t-> 行号 = $i" .PHP_EOL;$start = ($i - 20);$start = ($start <0) ?0:$开始;$length = 40;$point = $max - $i;如果 ($point <20) {$rlength = 1;$rpoint = - $point;} 别的 {$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;}}}

保存到数据库的更好方法

$toDatabse = base64_encode(serialize($data));//保存到数据库$fromDatabase = 反序列化(base64_decode($data));//获取保存格式

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

解决方案

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 

这篇关于如何修复因字节计数长度不正确而损坏的序列化字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆