Làm thế nào để sửa chữa một chuỗi được tuần tự hóa đã bị hỏng do độ dài đếm byte không chính xác?


96

Tôi đang sử dụng Hotaru CMS với plugin Tải lên hình ảnh, tôi gặp lỗi này nếu cố gắng đính kèm hình ảnh vào bài đăng, nếu không thì không có lỗi:

unserialize () [function.unserialize]: Lỗi khi bù đắp

Mã vi phạm (lỗi trỏ đến dòng **):

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

Dữ liệu từ bảng, để ý bit cuối có thông tin hình ảnh, tôi không phải là một chuyên gia về PHP nên tôi không biết các bạn có thể nghĩ gì?

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

Chỉnh sửa: Tôi nghĩ rằng tôi đã tìm thấy bit tuần tự hóa ...

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

3
Đối với tôi, cách khắc phục nhanh chóng cho việc này là sử dụng base64_encode / decode trước khi serialize / unserialize. davidwalsh.name/php-serialize-unserialize-issues
Valentin Despa

1
tôi không biết tại sao nhưng tôi đã giải quyết bằng cách thêm @,@unserialize($product->des_txtmopscol);
Bhavin Rana

2
Việc thêm @BhavinRana @không phải là giải quyết lỗi, đó là lỗi im lặng - không có gì thực sự "được sửa" với kỹ thuật đó.
mickmackusa

Câu trả lời:


219

unserialize() [function.unserialize]: Error at offsetbị tính phí invalid serialization datado độ dài không hợp lệ

Sửa chữa nhanh

Những gì bạn có thể làm là recalculating the lengthvề các phần tử trong mảng được tuần tự hóa

Dữ liệu được tuần tự hóa hiện tại của bạn

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

Ví dụ mà không cần tính toán lại

var_dump(unserialize($data));

Đầu ra

Notice: unserialize() [function.unserialize]: Error at offset 337 of 338 bytes

Tính toán lại

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

Đầu ra

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)

Khuyến nghị .. Tôi

Thay vì sử dụng loại sửa chữa nhanh này ... tôi sẽ khuyên bạn cập nhật câu hỏi với

  • Cách bạn đang tuần tự hóa dữ liệu của mình

  • Bạn đang lưu nó như thế nào ..

================================ CHỈNH SỬA 1 ================= ===============

Lỗi

Lỗi được tạo ra do sử dụng dấu ngoặc kép "thay vì dấu ngoặc kép ', đó là lý do tại sao C:\fakepath\100.pngđược chuyển đổi thànhC:fakepath100.jpg

Để sửa lỗi

Bạn cần thay đổi $h->vars['submitted_data']Từ (Lưu ý khá đơn ')

Thay thế

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

Với

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

Bộ lọc bổ sung

Bạn cũng có thể thêm bộ lọc đơn giản này trước khi gọi serialize

function satitize(&$value, $key)
{
    $value = addslashes($value);
}

array_walk($h->vars['submitted_data'], "satitize");

Nếu bạn có Ký tự UTF, bạn cũng có thể chạy

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

Cách phát hiện sự cố trong dữ liệu tuần tự hóa trong tương lai

  findSerializeError ( $data1 ) ;

Đầu ra

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 Chức năng

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

    }

}

Một cách tốt hơn để lưu vào Cơ sở dữ liệu

$toDatabse = base64_encode(serialize($data));  // Save to database
$fromDatabase = unserialize(base64_decode($data)); //Getting Save Format 

1
Baba, tôi đã sử dụng findSerializeErrorchức năng tuyệt vời của bạn và tìm thấy rất nhiều lỗi. Xin hãy nhìn vào chủ đề của tôi
Max Koretskyi

1
sử dụng base64trên Điều trước khi thêm nó vào cơ sở dữ liệu ... nó sẽ duy trì các ký tự null
Baba

1
Đó không phải là cách tốt hơn để lưu vào cơ sở dữ liệu. Đó là, trừ khi bạn muốn hoàn toàn bỏ qua mục đích của cơ sở dữ liệu. Bạn sẽ thực hiện tìm kiếm như thế nào trong một loạt các giá trị được mã hóa? Không phải đề cập đến sự cồng kềnh, ugh. Mã hóa thích hợp là câu trả lời thích hợp.
Deji

4
Nếu sử dụng PHP 5.5, hãy xem câu trả lời @ r00tAcc3ss! stackoverflow.com/a/21389439/1003020
Vinicius Garcia

5
Nếu bạn nhận được lỗi này "preg_replace (): Các / e modifier không còn được hỗ trợ, sử dụng preg_replace_callback thay vì" trong php7 - Câu trả lời này làm việc stackoverflow.com/a/21389439/2011434
BenB

81

Tôi không có đủ danh tiếng để bình luận, vì vậy tôi hy vọng điều này sẽ được nhìn thấy bởi những người sử dụng câu trả lời "đúng" ở trên:

Vì php 5.5, công cụ sửa đổi / e trong preg_replace () đã hoàn toàn không được dùng nữa và preg_match ở trên sẽ bị lỗi. Tài liệu php khuyến nghị sử dụng preg_match_callback ở vị trí của nó.

Vui lòng tìm giải pháp sau thay thế cho preg_match được đề xuất ở trên.

$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 );

3
Đây dường như là câu trả lời duy nhất trên trang thực sự đưa nhóm chụp đầu tiên vào sử dụng tốt. Trong khi lập trình hợp lý để chỉ thực hiện thay thế khi số byte thực sự sai, giải pháp này không lưu vào bộ nhớ cachestrlen() và do đó thực hiện các lệnh gọi hàm dư thừa. Cá nhân tôi thấy việc bổ sung một điều kiện nội tuyến là quá dài dòng, nhưng đoạn mã này đang hoạt động tốt vì những lý do chính đáng.
mickmackusa

3
Nó hoạt động với tôi với regex sau đây '!s:(\d+):"(.*?)";!s'(với phần cuối là 's' để có các dòng mới). Cảm ơn bình luận của adilbo bên dưới.
ArnoHolo

13

Có một lý do khác unserialize()không thành công là do bạn đưa dữ liệu tuần tự vào cơ sở dữ liệu không đúng cách, hãy xem Giải thích chính thức tại đây. Vì serialize()dữ liệu nhị phân trả về và các biến php không quan tâm đến các phương pháp mã hóa, do đó việc đưa nó vào TEXT, VARCHAR () sẽ gây ra lỗi này.

Giải pháp: lưu trữ dữ liệu tuần tự vào BLOB trong bảng của bạn.


Điều này đã giải quyết vấn đề của tôi trong Laravel 5. Tôi đã thay đổi định nghĩa cột từ string () thành binary ().
WNRosenberg

Câu hỏi của OP dường như không có vấn đề về loại cột mysql. Nó dường như bị hỏng do tính toán byte không chính xác trên imagegiá trị. Câu trả lời của bạn không liên quan đến câu hỏi cụ thể của OP. Bạn có thể muốn chuyển lời khuyên của mình đến: stackoverflow.com/q/5544749/2943403
mickmackusa

11

Sửa chữa nhanh

Tính toán lại độ dài của các phần tử trong mảng được tuần tự - nhưng không sử dụng (preg_replace), nó không được dùng nữa - tốt hơn nên sử dụng preg_replace_callback:

Chỉnh sửa: Phiên bản mới bây giờ không chỉ sai độ dài mà nó còn sửa lỗi ngắt dòng và đếm các ký tự chính xác với aczent (nhờ mickmackusa )

// New Version
$data = preg_replace_callback('!s:\d+:"(.*?)";!s', function($m) { return "s:" . strlen($m[1]) . ':"'.$m[1].'";'; }, $data);

1
Làm thế nào để giải pháp không chính xác này có 8 ủng hộ? Tôi giật mình nghĩ rằng có bao nhiêu người sẽ vô tình sao chép việc dán một lớp lót này. [khuôn mặt buồn] Đây là bằng chứng về hai cách, trong đó đoạn này sẽ thất bại: 3v4l.org/Cf6Nh Xem mẫu tinh của tôi và thay thế tùy chỉnh @ stackoverflow.com/a/55074706/2943403
mickmackusa

1
Giải pháp của tôi không còn ở trang khác vì đó là giải pháp không chính xác cho chuỗi tuần tự bị hỏng nghiêm trọng. Tôi đã thêm đoạn mã của mình vào trang này và đưa ra lời giải thích và minh chứng. stackoverflow.com/a/55566407/2943403
mickmackusa

5

Lỗi này là do bộ ký tự của bạn sai.

Đặt bộ mã sau thẻ mở:

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

Và đặt bộ ký tự utf8 trong cơ sở dữ liệu của bạn:

mysql_query("SET NAMES 'utf8'");

Tôi không thấy bất kỳ dấu hiệu nào trong câu hỏi đã đăng của OP cho thấy rằng tham nhũng là do bộ ký tự. Miễn phí để bảo vệ khiếu nại của bạn, nhưng theo như tôi có thể nói, ai đó đã cập nhật imagegiá trị theo cách thủ công và không cập nhật được số byte. Trừ khi được thông báo khác, tôi phải cho rằng câu trả lời này không chính xác đối với câu hỏi của OP.
mickmackusa

4

Bạn có thể sửa chuỗi serialize bị hỏng bằng cách sử dụng chức năng sau, với xử lý ký tự multibyte .

function repairSerializeString($value)
{

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

    return preg_replace_callback(
        $regex, function($match) {
            return "s:".mb_strlen($match[2]).":\"".$match[2]."\""; 
        },
        $value
    );
}

Cốt lõi của những gì câu trả lời này đề xuất chỉ đơn giản là sai và sẽ có khả năng làm hỏng các chuỗi được tuần tự hợp lệ hoàn hảo. Đoạn mã này không nên được sử dụng / đáng tin cậy.
mickmackusa

@mickmackusa Tôi không hiểu ý bạn, Bạn có thể vui lòng đề xuất cách tốt nhất để làm điều đó không? hoặc đề xuất chỉnh sửa câu trả lời này ..
Rajesh Meniya

Tôi đã cung cấp giải pháp chính xác ở đây: stackoverflow.com/a/55566407/2943403 và giải thích rằng điều đó mb_strlen()không phù hợp vì serialize()lưu trữ số lượng byte chứ không phải số ký tự. Chỉnh sửa câu trả lời của bạn cho đúng sẽ chỉ tạo ra lời khuyên thừa trên trang.
mickmackusa

4

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

php unserialize
Pardeep Goyal

Giải pháp này không phù hợp với nhiều trường hợp. Nó đưa ra giả định rằng mọi người sẽ muốn đột biến các giá trị trong chuỗi được tuần tự hóa để chuyển đổi 2 hoặc nhiều ký tự khoảng trắng thành khoảng trắng và trim()mọi chuỗi con phù hợp. Chỉ riêng điểm đó thôi đã khiến giải pháp này không thể được khuyến nghị. Hơn nữa, nó sẽ làm nghẹt các ký tự dòng mới và bắt không cần thiết số byte đã có từ trước mà dù sao đi nữa, nó sẽ bị ghi đè. Cuối cùng, đây là "câu trả lời chỉ có mã" và những loại câu trả lời này có giá trị thấp vì chúng không có tác dụng giáo dục / trao quyền cho các nhà nghiên cứu trong tương lai.
mickmackusa

4
$badData = 'a:2:{i:0;s:16:"as:45:"d";
Is \n";i:1;s:19:"as:45:"d";
Is \r\n";}';

Bạn không thể sửa một chuỗi số tuần tự bị hỏng bằng cách sử dụng các regex được đề xuất:

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

Bạn có thể sửa chuỗi serialize bị hỏng bằng cách sử dụng regex sau:

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

var_dump(@unserialize($data));

Đầu ra

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

hoặc là

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

1
@mickmackusa Cảm ơn. Đã khắc phục sự cố với mã hóa nhiều byte.
Даниил Путилин

2

các tài liệu chính thức cho biết họ phải trả lại E_NOTICE giả và thiết lập

nhưng vì bạn gặp lỗi nên báo cáo lỗi được thiết lập để kích hoạt bởi E_NOTICE

đây là một bản sửa lỗi để cho phép bạn phát hiện sai do unserialize

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

bạn có thể muốn xem xét sử dụng mã hóa / giải mã base64

$string=base64_encode(serialize($obj));
unserialize(base64_decode($string));

base64_encodeđã làm thủ thuật cho tôi. Tôi là trường hợp của tôi, chúng tôi đang truyền serializedữ liệu d qua dòng lệnh và có vẻ như một số ký tự lạ đã ngăn nó hoạt động chính xác.
quickshiftin

base64_encode()không phải là giải pháp cho câu hỏi của OP. Câu hỏi / vấn đề của OP đặc biệt giải quyết thực tế là (có thể xảy ra với sự thay thế chuỗi con không phù hợp trên "phần tử mảng cuối cùng" của chuỗi được tuần tự hóa) có số byte không chính xác trong chuỗi được tuần tự hóa. Vui lòng chỉ đăng câu trả lời trực tiếp giải quyết câu hỏi được hỏi.
mickmackusa

2

Lỗi trong câu hỏi này bị cô lập với một chuỗi con duy nhất ở cuối chuỗi được tuần tự hóa với có thể đã được thay thế theo cách thủ công bởi ai đó lười biếng muốn cập nhật imagetên tệp. Thực tế này sẽ được rõ ràng trong liên kết trình diễn của tôi dưới đây bằng cách sử dụng dữ liệu đã đăng của OP - trong ngắn hạn, C:fakepath100.jpgkhông có độ dài 19, nó phải như vậy 17.

Vì tham nhũng chuỗi tuần tự được giới hạn ở một số byte / ký tự không chính xác, phần sau sẽ thực hiện tốt công việc cập nhật chuỗi bị hỏng với giá trị đếm byte chính xác.

Việc thay thế dựa trên regex sau đây sẽ chỉ có hiệu quả trong việc khắc phục số lượng byte, không có gì khác.

Có vẻ như nhiều bài viết trước đó chỉ là sao chép-dán một mẫu regex từ người khác. Không có lý do gì để nắm bắt số đếm byte có khả năng bị hỏng nếu nó không được sử dụng để thay thế. Ngoài ra, việc thêm công cụ ssửa đổi mẫu là một bao gồm hợp lý trong trường hợp giá trị chuỗi chứa các dòng mới / dòng trả về.

* Đối với những người không biết về việc xử lý các ký tự nhiều byte với tuần tự hóa, bạn không được sử dụng mb_strlen()trong lệnh gọi lại tùy chỉnh vì đó là số byte được lưu trữ không phải là số ký tự , hãy xem đầu ra của tôi ...

Mã: ( Demo với dữ liệu của OP ) ( Demo với dữ liệu mẫu tùy ý ) ( Demo với điều kiện thay thế )

$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));

Đầu ra:

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',
)

Một chân xuống lỗ thỏ ... Ở trên hoạt động tốt ngay cả khi dấu ngoặc kép xảy ra trong một giá trị chuỗi, nhưng nếu một giá trị chuỗi chứa"; hoặc một số khỉwrenching khác, bạn sẽ cần phải đi xa hơn một chút và triển khai "cách xem xét". Mẫu mới của tôi

kiểm tra xem hàng đầu slà:

  • phần bắt đầu của toàn bộ chuỗi đầu vào hoặc
  • trước bởi ;

và kiểm tra xem đó ";là:

  • ở cuối toàn bộ chuỗi đầu vào hoặc
  • theo sau }hoặc
  • theo sau là khai báo chuỗi hoặc số nguyên s:hoặci:

Tôi chưa thử nghiệm từng khả năng; trên thực tế, tôi tương đối xa lạ với tất cả các khả năng trong một chuỗi được tuần tự hóa bởi vì tôi không bao giờ chọn làm việc với dữ liệu được tuần tự hóa - luôn luôn json trong các ứng dụng hiện đại. Nếu có thêm các ký tự đầu hoặc cuối có thể có, hãy để lại nhận xét và tôi sẽ mở rộng cách nhìn.

Đoạn mã mở rộng: ( 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));

Đầu ra:

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
)

1

Bạn sẽ phải thay đổi kiểu đối chiếu utf8_unicode_civà sự cố sẽ được khắc phục.


Bạn tin rằng ký tự cụ thể nào trong dữ liệu mẫu của OP sẽ được sửa đổi bằng cách thay đổi đối chiếu thành utf8_unicode_ci? Tôi có nghi ngờ của tôi về điều này.
mickmackusa

Điều này cũng thực sự làm việc cho tôi (ngoài câu trả lời của r00tAcc3ss) bất kỳ từ nào từ một người nào đó giải thích tại sao? Về cơ bản, tôi lấy dữ liệu từ lệnh gọi API tới ứng dụng ResourceSpace, lưu trữ nó trong một mảng, tuần tự hóa nó và lưu nó. Dữ liệu tuần tự hóa đang gặp sự cố khi lưu nên tôi phải mã hóa nó thành UTF-8 theo cách thủ công, tôi đang chơi với đối chiếu và bộ ký tự trong DB và cuối cùng bị bỏ lại với đối chiếu utf8_general_ci, khi tôi thay đổi nó thành utf8_unicode_ci, nó đã hoạt động .
Roberto Becerra

1

Trong trường hợp của tôi, tôi đang lưu trữ dữ liệu được tuần tự hóa trong BLOBtrường MySQL DB dường như không đủ lớn để chứa toàn bộ giá trị và đã cắt ngắn nó. Một chuỗi như vậy rõ ràng là không thể được phi công nghệ hóa.
Sau khi chuyển đổi trường đó MEDIUMBLOBthành vấn đề tiêu tan. Ngoài ra, có thể cần chuyển các tùy chọn bảng ROW_FORMATthành DYNAMIChoặc COMPRESSED.


Tôi đến - mặc dù của tôi là một TEXTlĩnh vực và như vậy bị cắt ngắn ở 65kb.
Antony

Câu hỏi này không bị cắt bớt. Câu hỏi / vấn đề của OP đặc biệt giải quyết thực tế là (có thể xảy ra với sự thay thế chuỗi con không phù hợp trên "phần tử mảng cuối cùng" của chuỗi được tuần tự hóa) có số byte không chính xác trong chuỗi được tuần tự hóa. Vui lòng chỉ đăng câu trả lời trực tiếp giải quyết câu hỏi được hỏi.
mickmackusa

1

Sau khi thử một số điều trên trang này mà không thành công, tôi đã xem trong nguồn trang và nhận xét rằng tất cả các dấu ngoặc kép trong chuỗi được tuần tự hóa đã được thay thế bằng các thực thể html. Giải mã các thực thể này giúp tránh được nhiều vấn đề đau đầu:

$myVar = html_entity_decode($myVar);

Câu hỏi này không mắc phải các thực thể được mã hóa html trong chuỗi được tuần tự hóa. Câu hỏi / vấn đề của OP đặc biệt giải quyết thực tế là (có thể xảy ra với sự thay thế chuỗi con không phù hợp trên "phần tử mảng cuối cùng" của chuỗi được tuần tự hóa) có số byte không chính xác trong chuỗi được tuần tự hóa. Vui lòng chỉ đăng câu trả lời trực tiếp giải quyết câu hỏi được hỏi.
mickmackusa

@mickmackusa Câu hỏi này gần 7 năm rồi và câu trả lời của tôi ~ 1,5. Tuy nhiên, thật tuyệt khi bạn tham gia rất nhiều!
David

Tôi yêu các trang SO - trẻ và già. Tôi đang tìm kiếm những nhà nghiên cứu không biết sự khác biệt giữa một câu trả lời tốt và một câu trả lời không quá hay. Thật không may, trang này chứa đầy những lời khuyên lạc đề.
mickmackusa

Tuyệt quá! Đã có kiểm soát qualitiy và bỏ phiếu, nhưng tôi không có lý do gì để ngăn chặn bạn ;-)
David

Ồ không, hãy xem. Có những câu trả lời được ủng hộ nên được bỏ phiếu từ chối. Quá nhiều người không thể phân biệt được. Trên trang này, việc kiểm phiếu hoàn toàn không có dấu hiệu về chất lượng / sự phù hợp. Tôi sẽ không lãng phí thời gian của mình cho việc phản đối bởi vì phiếu phản đối của tôi sẽ không tạo ra vết rạn trên bảng kiểm đếm. Điều tốt nhất tôi có thể làm là để lại bình luận để giải thích điều gì là tốt / xấu / xấu.
mickmackusa

1

Đây là Công cụ trực tuyến để sửa một chuỗi tuần tự bị hỏng.

Tôi muốn nói thêm rằng điều này chủ yếu xảy ra do quá trình tìm kiếm và thay thế được thực hiện trên DB và dữ liệu tuần tự hóa ( đặc biệtkey length) không được cập nhật theo lần thay thế và điều đó gây ra "hỏng".

Tuy nhiên, công cụ trên sử dụng logic sau để sửa dữ liệu tuần tự hóa ( Sao chép từ đây ).

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

0

Một lý do khác của vấn đề này có thể là loại cột của bảng phiên "tải trọng". Nếu bạn có dữ liệu lớn về phiên, một cột văn bản sẽ không đủ. Bạn sẽ cần MEDIUMTEXT hoặc thậm chí là LONGTEXT.


Câu hỏi này không bị cắt bớt. Câu hỏi / vấn đề của OP đặc biệt giải quyết thực tế là (có thể xảy ra với sự thay thế chuỗi con không phù hợp trên "phần tử mảng cuối cùng" của chuỗi được tuần tự hóa) có số byte không chính xác trong chuỗi được tuần tự hóa. Vui lòng chỉ đăng câu trả lời trực tiếp giải quyết câu hỏi được hỏi.
mickmackusa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.