Bagaimana cara memperbaiki string serial yang telah rusak oleh panjang jumlah byte yang salah?


96

Saya menggunakan CMS Hotaru dengan plugin Unggah Gambar, saya mendapatkan kesalahan ini jika saya mencoba melampirkan gambar ke posting, jika tidak, tidak ada kesalahan:

unserialize () [function.unserialize]: Kesalahan pada offset

Kode yang melanggar (poin kesalahan yang sejalan dengan **):

/**
     * 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 dari tabel, perhatikan bit akhir memiliki info gambar, saya bukan ahli dalam PHP jadi saya bertanya-tanya apa yang mungkin kalian pikirkan?

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

Sunting: Saya pikir saya telah menemukan bit berseri ...

/**
     * 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
Bagi saya, perbaikan cepat untuk ini menggunakan base64_encode / decode sebelum membuat serial / unserialize. davidwalsh.name/php-serialize-unserialize-issues
Valentin Despa

1
saya tidak tahu mengapa tapi saya diselesaikan dengan menambahkan @,@unserialize($product->des_txtmopscol);
Bhavin Rana

2
@BhavinRana menambahkan @bukanlah pemecahan kesalahan, itu adalah pembungkaman kesalahan - tidak ada yang benar-benar "diperbaiki" dengan teknik itu.
mickmackusa

Jawaban:


219

unserialize() [function.unserialize]: Error at offsetadalah iuran invalid serialization datakarena panjang yang tidak valid

Perbaikan Cepat

Apa yang dapat Anda lakukan adalah recalculating the lengthelemen dalam array serial

Anda saat ini data serial

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

Contoh tanpa penghitungan ulang

var_dump(unserialize($data));

Keluaran

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

Menghitung ulang

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

Keluaran

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)

Rekomendasi .. I

Alih-alih menggunakan perbaikan cepat semacam ini ... saya akan menyarankan Anda memperbarui pertanyaan dengan

  • Bagaimana Anda membuat serial data Anda

  • Bagaimana Anda Menyimpannya ..

================================ EDIT 1 ================ ===============

Kesalahan

Kesalahan dihasilkan karena penggunaan tanda kutip ganda, "bukan tanda kutip tunggal, 'itulah sebabnya C:\fakepath\100.pngdiubah menjadiC:fakepath100.jpg

Untuk memperbaiki kesalahan tersebut

Anda perlu mengubah $h->vars['submitted_data']Dari (Perhatikan baik-baik saja ')

Menggantikan

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

Dengan

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

Filter Tambahan

Anda juga dapat menambahkan filter sederhana ini sebelum memanggil serialize

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

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

Jika Anda memiliki Karakter UTF, Anda juga dapat menjalankan

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

Cara mendeteksi masalah dalam data serial di masa mendatang

  findSerializeError ( $data1 ) ;

Keluaran

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 Fungsi

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

    }

}

Cara yang lebih baik untuk menyimpan ke Database

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

1
Baba, saya menggunakan findSerializeErrorfungsi luar biasa Anda dan menemukan banyak kesalahan. Silakan lihat topik saya
Max Koretskyi

1
digunakan base64pada Artikel sebelum menambahkannya ke database ... itu akan mempertahankan karakter null
Baba

1
Itu bukan cara yang lebih baik untuk menyimpan ke database. Ya, kecuali jika Anda ingin sepenuhnya mengabaikan tujuan database. Bagaimana Anda akan melakukan pencarian dalam sekelompok nilai terenkripsi? Belum lagi mengasapi, ugh. Pengkodean yang tepat adalah jawaban yang tepat.
Deji

4
Jika menggunakan PHP 5.5, lihat jawaban @ r00tAcc3ss! stackoverflow.com/a/21389439/1003020
Vinicius Garcia

5
Jika Anda mendapatkan kesalahan ini "preg_replace (): Pengubah / e tidak lagi didukung, gunakan preg_replace_callback sebagai gantinya" di php7 - jawaban ini berfungsi stackoverflow.com/a/21389439/2011434
BenB

81

Saya tidak punya cukup reputasi untuk berkomentar, jadi saya harap ini dilihat oleh orang-orang yang menggunakan jawaban "benar" di atas:

Sejak php 5.5 pengubah / e di preg_replace () telah ditinggalkan sepenuhnya dan preg_match di atas akan error. Dokumentasi php merekomendasikan penggunaan preg_match_callback sebagai gantinya.

Temukan solusi berikut sebagai alternatif dari preg_match yang diusulkan di atas.

$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
Sepertinya ini satu-satunya jawaban di halaman yang benar-benar menggunakan grup tangkapan pertama dengan baik. Sementara pemrograman yang masuk akal hanya membuat penggantian di mana jumlah byte sebenarnya salah, solusi ini tidak menyimpan cache strlen()dan oleh karena itu membuat panggilan fungsi yang berlebihan. Secara pribadi, saya menemukan penambahan kondisi sebaris terlalu bertele-tele, tetapi cuplikan ini melakukan hal-hal baik untuk alasan yang baik.
mickmackusa

3
Ini bekerja untuk saya dengan regex berikut '!s:(\d+):"(.*?)";!s'(dengan akhiran 'untuk mengambil baris baru juga). Berkat komentar adilbo di bawah ini.
ArnoHolo

13

Ada alasan lain unserialize() gagal karena Anda memasukkan data serial ke dalam database dengan tidak benar, lihat Penjelasan Resmi di sini. Karena serialize()mengembalikan data biner dan variabel php tidak peduli dengan metode pengkodean, sehingga memasukkannya ke dalam TEXT, VARCHAR () akan menyebabkan kesalahan ini.

Solusi: simpan data serial ke dalam BLOB di tabel Anda.


Ini memecahkan masalah saya di Laravel 5. Saya mengubah definisi kolom dari string () menjadi binary ().
WNRosenberg

Pertanyaan OP tampaknya tidak memiliki masalah tipe kolom mysql. Tampaknya rusak oleh kalkulasi byte yang salah pada imagenilainya. Jawaban Anda tidak berkaitan dengan pertanyaan spesifik OP. Anda mungkin ingin menyampaikan saran Anda ke: stackoverflow.com/q/5544749/2943403
mickmackusa

11

Perbaikan Cepat

Menghitung ulang panjang elemen dalam array serial - tetapi jangan gunakan (preg_replace) sudah usang - lebih baik gunakan preg_replace_callback:

Sunting: Versi Baru sekarang tidak hanya panjang yang salah tetapi juga memperbaiki jeda baris dan menghitung karakter yang benar dengan aczent (terima kasih kepada mickmackusa )

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

1
Bagaimana solusi yang salah ini memiliki 8 suara positif? Saya memotret untuk memikirkan berapa banyak orang yang tanpa disadari akan menyalin menempelkan satu baris ini. [wajah sedih] Berikut adalah bukti dari dua cara di mana cuplikan ini akan gagal: 3v4l.org/Cf6Nh Lihat pola yang diperhalus dan penggantian kustom saya @ stackoverflow.com/a/55074706/2943403
mickmackusa

1
Solusi saya tidak lagi di halaman lain karena itu adalah solusi yang salah untuk string serial yang rusak parah. Saya telah menambahkan potongan saya ke halaman ini dan memberikan penjelasan dan demonstrasi. stackoverflow.com/a/55566407/2943403
mickmackusa

5

Kesalahan ini disebabkan karena rangkaian karakter Anda salah.

Setel charset setelah tag terbuka:

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

Dan setel charset utf8 di database Anda:

mysql_query("SET NAMES 'utf8'");

Saya tidak melihat indikasi apa pun dalam pertanyaan yang diposting OP yang menunjukkan bahwa korupsi disebabkan oleh rangkaian karakter. Bebas biaya untuk mempertahankan klaim Anda, tetapi sejauh yang saya tahu, seseorang telah memperbarui imagenilainya secara manual dan gagal memperbarui jumlah byte. Kecuali diinformasikan sebaliknya, saya harus berasumsi bahwa jawaban ini salah untuk pertanyaan OP.
mickmackusa

4

Anda dapat memperbaiki string serialisasi yang rusak menggunakan fungsi berikut, dengan penanganan karakter multibyte .

function repairSerializeString($value)
{

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

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

Inti dari apa yang direkomendasikan jawaban ini salah dan berpotensi merusak string serial yang benar-benar valid. Cuplikan ini tidak boleh digunakan / dipercaya.
mickmackusa

@mickmackusa Saya tidak mengerti maksud Anda, Bisakah Anda menyarankan cara terbaik untuk melakukannya? atau sarankan edit untuk jawaban ini ..
Rajesh Meniya

Saya telah memberikan solusi yang benar di sini: stackoverflow.com/a/55566407/2943403 dan menjelaskan bahwa mb_strlen()itu tidak pantas karena serialize()menyimpan jumlah byte, bukan jumlah karakter. Mengedit jawaban Anda menjadi benar hanya akan membuat saran yang berlebihan di halaman.
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

Solusi ini tidak cocok untuk banyak kasus. Itu membuat asumsi bahwa setiap orang ingin mutasi nilai dalam string serial untuk mengubah 2-atau-lebih karakter spasi putih ke spasi literal DAN trim()setiap substring yang cocok. Poin itu saja membuat solusi ini tidak mungkin untuk direkomendasikan. Selanjutnya, ini akan mencekik karakter baris baru dan tidak perlu menangkap jumlah byte yang sudah ada sebelumnya yang hanya akan ditimpa bagaimanapun juga. Terakhir, ini adalah "jawaban hanya kode" dan jenis jawaban ini bernilai rendah karena tidak banyak membantu mendidik / memberdayakan peneliti di masa depan.
mickmackusa

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

Anda tidak dapat memperbaiki string serialisasi yang rusak menggunakan regex yang diusulkan:

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

Anda dapat memperbaiki string serialisasi yang rusak menggunakan regex berikut:

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

var_dump(@unserialize($data));

Keluaran

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

atau

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

1
@ickusa Terima kasih. Memperbaiki masalah encoding multibyte.
Даниил Путилин

2

yang docs resmi mengatakan harus kembali E_NOTICE palsu dan set

tetapi karena Anda mendapatkan kesalahan maka pelaporan kesalahan diatur untuk dipicu oleh E_NOTICE

berikut adalah perbaikan untuk memungkinkan Anda mendeteksi false dikembalikan oleh unserialize

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

Anda mungkin ingin mempertimbangkan untuk menggunakan encode / decode base64

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

base64_encodemelakukan trik untuk saya. Saya kasus saya, kami mengirimkan serializedata d melalui baris perintah dan sepertinya beberapa karakter aneh mencegahnya berfungsi dengan benar.
quickshiftin

base64_encode()bukanlah solusi untuk pertanyaan yang diajukan oleh OP. Pertanyaan / masalah OP secara khusus berhubungan dengan fakta bahwa (kemungkinan besar dilakukan untuk penggantian substring yang tidak tepat pada "elemen array terakhir" dari string serial) ada jumlah byte yang salah dalam string serial. Harap hanya posting jawaban yang berhubungan langsung dengan pertanyaan yang diajukan.
mickmackusa

2

Kerusakan dalam pertanyaan ini diisolasi ke satu substring di akhir string serial dengan mungkin secara manual diganti oleh seseorang yang malas ingin memperbarui imagenama file. Fakta ini akan terlihat dalam tautan demonstrasi saya di bawah ini menggunakan data yang diposting OP - singkatnya, C:fakepath100.jpgtidak memiliki panjang 19, seharusnya 17.

Karena kerusakan string serial terbatas pada jumlah byte / karakter yang salah, berikut ini akan melakukan pekerjaan yang baik untuk memperbarui string yang rusak dengan nilai jumlah byte yang benar.

Penggantian berbasis regex berikut hanya akan efektif dalam memperbaiki jumlah byte, tidak lebih.

Sepertinya banyak dari postingan sebelumnya hanya menyalin-tempel pola regex dari orang lain. Tidak ada alasan untuk menangkap nomor hitungan byte yang berpotensi rusak jika tidak akan digunakan dalam penggantinya. Juga, menambahkans pengubah pola adalah penyertaan yang wajar jika nilai string berisi baris baru / baris kembali.

* Bagi mereka yang tidak mengetahui perlakuan karakter multibyte dengan serialisasi, Anda tidak boleh menggunakan mb_strlen()dalam panggilan balik kustom karena jumlah byte yang disimpan bukan jumlah karakter , lihat keluaran saya ...

Kode: ( Demo dengan data OP ) ( Demo dengan sampel data sewenang-wenang ) ( Demo dengan kondisi penggantian )

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

Keluaran:

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

Satu kaki ke lubang kelinci ... Cara di atas berfungsi dengan baik bahkan jika tanda kutip ganda terjadi dalam nilai string, tetapi jika nilai string berisi"; atau beberapa sbustring monkeywrenching lainnya, Anda harus melangkah lebih jauh dan menerapkan "lookarounds". Pola baru saya

memeriksa bahwa terdepan s adalah:

  • awal dari seluruh string input atau
  • didahului oleh ;

dan periksa ";apakah:

  • di akhir seluruh string input atau
  • diikuti oleh } atau
  • diikuti dengan string atau deklarasi integer s:ataui:

Saya belum menguji setiap kemungkinan; sebenarnya, saya relatif tidak terbiasa dengan semua kemungkinan dalam string berseri karena saya tidak pernah memilih untuk bekerja dengan data berseri - selalu json dalam aplikasi modern. Jika ada karakter tambahan di depan atau di belakang yang mungkin, tinggalkan komentar dan saya akan memperluas tampilan.

Cuplikan diperpanjang: ( 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));

Keluaran:

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

Anda harus mengubah jenis pemeriksaan menjadi utf8_unicode_cidan masalah akan diperbaiki.


Karakter spesifik apa dalam sampel data OP yang menurut Anda akan dimodifikasi dengan mengubah pemeriksaan utf8_unicode_ci? Saya ragu untuk yang satu ini.
mickmackusa

Ini juga benar-benar berhasil untuk saya (selain dari jawaban r00tAcc3ss) ada kata dari seseorang yang menjelaskan mengapa? Sebagai latar belakang, saya mengambil data dari panggilan API ke aplikasi ResourceSpace, menyimpannya dalam array, membuat serial dan menyimpannya. Data serial mengalami masalah saat disimpan jadi saya harus secara manual menyandikannya ke UTF-8, saya bermain-main dengan pemeriksaan dan kumpulan karakter di DB, dan akhirnya ditinggalkan dengan pemeriksaan utf8_general_ci, ketika saya mengubahnya menjadi utf8_unicode_ci, itu berhasil .
Roberto Becerra

1

Dalam kasus saya, saya menyimpan data serial di BLOBbidang MySQL DB yang tampaknya tidak cukup besar untuk memuat seluruh nilai dan memotongnya. String seperti itu jelas tidak bisa dibatalkan serialnya.
Setelah diubah bidang itu menjadi MEDIUMBLOBmasalah yang hilang. Mungkin juga diperlukan untuk mengganti opsi tabel ROW_FORMATkeDYNAMIC atau COMPRESSED.


Saya untuk - meskipun milik saya adalah TEXTladang dan dengan demikian terpotong pada 65kb.
Antony

Pertanyaan ini tidak mengalami pemotongan. Pertanyaan / masalah OP secara khusus berhubungan dengan fakta bahwa (kemungkinan besar dilakukan untuk penggantian substring yang tidak tepat pada "elemen array terakhir" dari string serial) ada jumlah byte yang salah dalam string serial. Harap hanya posting jawaban yang berhubungan langsung dengan pertanyaan yang diajukan.
mickmackusa

1

Setelah mencoba beberapa hal di halaman ini tanpa hasil, saya melihat-lihat halaman-sumber dan menyatakan bahwa semua kutipan dalam string berseri telah diganti dengan html-entity. Decoding entitas ini membantu menghindari banyak sakit kepala:

$myVar = html_entity_decode($myVar);

Pertanyaan ini tidak menderita entitas yang dikodekan html dalam string serial. Pertanyaan / masalah OP secara khusus berhubungan dengan fakta bahwa (kemungkinan besar dilakukan untuk penggantian substring yang tidak tepat pada "elemen array terakhir" dari string serial) ada jumlah byte yang salah dalam string serial. Harap hanya posting jawaban yang berhubungan langsung dengan pertanyaan yang diajukan.
mickmackusa

@mickmackusa Pertanyaan ini berusia hampir 7 tahun dan jawaban saya ~ 1,5. Namun senang Anda terlibat begitu banyak!
David

Saya suka halaman SO - tua dan muda. Saya mencari peneliti yang tidak tahu perbedaan antara jawaban yang bagus dan jawaban yang tidak terlalu bagus. Halaman ini, sayangnya, penuh dengan saran di luar topik.
mickmackusa

Bagus! Sudah ada kontrol kualifikasi dan pemungutan suara, tetapi saya tidak punya alasan untuk menghentikan Anda ;-)
David

Oh tidak, coba lihat. Ada jawaban yang diberi suara positif yang harus diberi suara negatif. Terlalu banyak orang yang tidak bisa membedakan. Pada halaman ini penghitungan suara sama sekali tidak menunjukkan kualitas / kesesuaian. Saya tidak akan menyia-nyiakan waktu saya untuk downvoting karena downvote saya tidak akan mengurangi penghitungan. Hal terbaik yang bisa saya lakukan adalah meninggalkan komentar untuk menjelaskan apa yang baik / buruk / jelek.
mickmackusa

1

Berikut adalah Alat Online untuk memperbaiki string serial yang rusak.

Saya ingin menambahkan bahwa ini sebagian besar terjadi karena pencarian dan penggantian dilakukan pada DB dan data serialisasi ( khususnya filekey length ) tidak diperbarui sesuai dengan mengganti dan yang menyebabkan "korupsi".

Meskipun demikian, alat di atas menggunakan logika berikut untuk memperbaiki data serialisasi ( Disalin Dari Sini ).

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

Alasan lain dari masalah ini adalah jenis kolom tabel sesi "payload". Jika Anda memiliki data besar pada sesi, kolom teks tidak akan cukup. Anda akan membutuhkan MEDIUMTEXT atau bahkan LONGTEXT.


Pertanyaan ini tidak mengalami pemotongan. Pertanyaan / masalah OP secara khusus berhubungan dengan fakta bahwa (kemungkinan besar dilakukan untuk penggantian substring yang tidak tepat pada "elemen array terakhir" dari string serial) ada jumlah byte yang salah dalam string serial. Harap hanya posting jawaban yang berhubungan langsung dengan pertanyaan yang diajukan.
mickmackusa
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.