Hatalı bayt sayısı uzunluğu nedeniyle bozulmuş serileştirilmiş bir dizge nasıl onarılır?


98

Resim Yükleme eklentisi ile Hotaru CMS kullanıyorum, bir gönderiye resim eklemeye çalışırsam bu hatayı alıyorum, aksi takdirde hata olmaz:

unserialize () [function.unserialize]: Uzaklıkta hata

Sorun teşkil eden kod (hata ** ile aynı çizgiye işaret eder):

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

Tablodaki veriler, son bitin resim bilgisine sahip olduğuna dikkat edin, PHP konusunda uzman değilim, bu yüzden sizlerin / kızların ne düşünebileceğini merak ediyordum.

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

Düzenleme: Sanırım serileştirme bitini buldum ...

/**
     * 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
Benim için bunun hızlı çözümü, serialize / unserialize işleminden önce base64_encode / decode kullanmaktı. davidwalsh.name/php-serialize-unserialize-issues
Valentin Despa

1
neden bilmiyorum ama benimki @ eklendi ile çözüldü@unserialize($product->des_txtmopscol);
Bhavin Rana

2
@BhavinRana ekleme @hata çözme değil, hata susturmadır - hiçbir şey bu teknikle "düzeltilmez".
mickmackusa

Yanıtlar:


219

unserialize() [function.unserialize]: Error at offsetiçin aidat oldu invalid serialization datageçersiz uzunluk nedeniyle

Hızlı düzeltme

Yapabileceğiniz şey, recalculating the lengthserileştirilmiş dizideki öğelerdir

Mevcut serileştirilmiş verileriniz

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

Yeniden hesaplama olmadan örnek

var_dump(unserialize($data));

Çıktı

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

Yeniden hesaplanıyor

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

Çıktı

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)

Öneri .. I

Bu tür bir hızlı düzeltmeyi kullanmak yerine ... soruyu şu şekilde güncellemenizi tavsiye edeceğim:

  • Verilerinizi nasıl serileştiriyorsunuz

  • Nasıl kurtarıyorsun ..

============================== DÜZENLE 1 ================ ===============

Hata

Hata nedeniyle çift tırnak kullanımı oluşturulduğu "yerine tek tırnak 'neden olduğu C:\fakepath\100.pngdönüştürüldüC:fakepath100.jpg

Hatayı düzeltmek için

Değiştirmeniz gerekiyor $h->vars['submitted_data'](oldukça dikkat edin ')

Değiştir

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

İle

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

Ek Filtre

Bu basit filtreyi serileştirmeyi aramadan önce de ekleyebilirsiniz.

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

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

UTF Karakterleriniz varsa ayrıca çalıştırabilirsiniz

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

Gelecekteki serileştirilmiş verilerde sorun nasıl tespit edilir

  findSerializeError ( $data1 ) ;

Çıktı

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 Fonksiyon

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

    }

}

Veritabanına kaydetmenin daha iyi bir yolu

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

1
Baba, harika findSerializeErrorişlevini kullandım ve bir sürü hata buldum. Bir göz atın lütfen benim konu
Max Koretskyi

1
base64Veritabanına eklemeden önce Makale üzerinde kullanın ... boş karakteri korur
Baba

1
Bu, veritabanına kaydetmenin daha iyi bir yolu değildir. Veritabanının amacını tamamen ihmal etmek istemediğiniz sürece. Bir grup şifrelenmiş değerde nasıl arama yapacaksın? Şişmanlıktan bahsetmiyorum bile, ugh. Doğru kodlama doğru cevaptır.
Deji

4
PHP 5.5 kullanıyorsanız, @ r00tAcc3ss cevabına bakın! stackoverflow.com/a/21389439/1003020
Vinicius Garcia

6
Bu hatayı alırsanız "preg_replace (): / e değiştiricisi artık desteklenmiyor, bunun yerine preg_replace_callback'i kullanın" php7'de - bu yanıt stackoverflow.com/a/21389439/2011434
BenB

84

Yorum yapacak kadar itibarım yok, bu yüzden yukarıdaki "doğru" yanıtı kullananların bunu görmesini umuyorum:

Php 5.5'ten beri preg_replace () içindeki / e değiştiricisi tamamen kullanımdan kaldırıldı ve yukarıdaki preg_match hata verecektir. Php belgeleri yerine preg_match_callback kullanılmasını önerir.

Lütfen yukarıda önerilen preg_match'e alternatif olarak aşağıdaki çözümü bulun.

$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
Bu, ilk yakalama grubunu iyi bir şekilde kullanmasını sağlayan sayfadaki tek cevap gibi görünüyor. Yalnızca bayt sayısının gerçekten yanlış olduğu yerlerde değişiklikler yapmak için mantıklı bir programlama olsa da , bu çözüm önbelleğe almaz strlen()ve bu nedenle fazladan işlev çağrıları yapar. Şahsen, bir satır içi koşulun eklenmesini çok ayrıntılı buluyorum, ancak bu pasaj iyi nedenlerle iyi şeyler yapıyor.
mickmackusa

4
Aşağıdaki normal ifadeyle benim için çalıştı '!s:(\d+):"(.*?)";!s'(yeni satırlar almak için bir 's' bitişi ile). Adilbo'nun aşağıdaki yorumu sayesinde.
ArnoHolo

13

unserialize()Veritabanına yanlış bir şekilde serileştirilmiş verileri yerleştirdiğiniz için başarısız olmanın başka bir nedeni daha var. Resmi Açıklama burada. Yana serialize()döner ikili veriler ve php değişkenleri yöntemleri kodlayan umurumda değil, METİN içine koyarak böylece, VARCHAR () bu hataya neden olur.

Çözüm: Serileştirilmiş verileri tablonuzdaki BLOB'da saklayın.


Bu, Laravel 5'te sorunumu çözdü. Sütun tanımını string () 'den binary ()' ye değiştirdim.
WNRosenberg

OP'nin sorusu bir mysql sütun türü sorununa sahip görünmüyor. Görünüşe göre imagedeğer üzerinde yanlış bir bayt hesaplamasıyla bozulmuş . Cevabınız OP'nin özel sorusu ile ilgili değil. Tavsiyenizi
mickmackusa

11

Hızlı düzeltme

Serileştirilmiş dizideki öğelerin uzunluğunu yeniden hesaplamak - ancak kullanımdan kaldırılan (preg_replace) kullanmayın - preg_replace_callback'i daha iyi kullanın:

Düzenleme: Yeni Sürüm şimdi sadece yanlış değil uzunluk ama aynı zamanda düzeltme hat sonları ve aczent ile doğru karakterleri saymak (sayesinde mickmackusa )

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

1
Bu yanlış çözümün nasıl 8 olumlu oyu var? Kaç kişinin farkında olmadan bu tek astarı kopyalayacağını düşünmek için kepenk çekiyorum. : [üzgün yüz] İşte bu pasajı başarısız olur ki iki yoldan kanıtıdır 3v4l.org/Cf6Nh @ benim rafine desen ve özel değiştirme Bkz stackoverflow.com/a/55074706/2943403
mickmackusa

1
Benim çözümüm artık diğer sayfada değil çünkü felaket bir şekilde zarar görmüş serileştirilmiş dizge için yanlış bir çözümdü. Snippetimi bu sayfaya ekledim ve açıklama ve gösterimler sağladım. stackoverflow.com/a/55566407/2943403
mickmackusa

5

Bu hata, karakter kümenizin yanlış olmasından kaynaklanmaktadır.

Açık etiketten sonra karakter kümesini ayarlayın:

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

Ve veritabanınızda karakter kümesi utf8'i ayarlayın:

mysql_query("SET NAMES 'utf8'");

OP'nin gönderilen sorusunda, yolsuzluğun karakter setinden kaynaklandığına dair herhangi bir belirti görmüyorum. İddianızı savunmak için ücretsiz, ancak anlayabildiğim kadarıyla birisi imagedeğeri manuel olarak güncelledi ve bayt sayısını güncelleyemedi. Aksi belirtilmedikçe, bu cevabın OP'nin sorusu için yanlış olduğunu varsaymalıyım.
mickmackusa

4

Aşağıdaki işlevi kullanarak, çok baytlı karakter işleme ile bozuk serileştirme dizesini düzeltebilirsiniz .

function repairSerializeString($value)
{

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

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

Bu cevabın önerdiği şeyin özü basitçe yanlıştır ve potansiyel olarak tamamen geçerli serileştirilmiş dizelere zarar verecektir. Bu pasaj kullanılmamalıdır / güvenilmemelidir.
mickmackusa

@mickmackusa Ne demek istediğini anlamıyorum, lütfen bunu yapmanın en iyi yolunu önerebilir misin? veya bu yanıtı düzenleme
önerisinde bulunun

Burada doğru bir çözüm sağladım: stackoverflow.com/a/55566407/2943403 ve bunun mb_strlen()uygunsuz olduğunu açıkladım çünkü serialize()karakter sayısını değil bayt sayısını saklıyor. Cevabınızı doğru olacak şekilde düzenlemek, sayfada yalnızca gereksiz tavsiyeler oluşturacaktır.
mickmackusa

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

Önerilen normal ifadeleri kullanarak bozuk bir serileştirme dizesini düzeltemezsiniz:

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

Aşağıdaki regex kullanarak bozuk serileştirme dizesini düzeltebilirsiniz:

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

var_dump(@unserialize($data));

Çıktı

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

veya

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

1
@mickmackusa Teşekkürler. Çok baytlı kodlamalarla ilgili bir sorun düzeltildi.
Даниил Путилин

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

Bu çözüm birçok durum için uygun değildir. Herkesin 2 veya daha fazla beyaz boşluk karakterini değişmez boşluğa VE trim()her eşleşen alt dizeye dönüştürmek için serileştirilmiş dizedeki değerleri mutasyona uğratmak isteyeceği varsayımını yapar . Bu nokta tek başına bu çözümü tavsiye etmeyi imkansız kılar. Dahası, satırsonu karakterlerinde boğulacak ve gereksiz yere önceden var olan bayt sayısını yakalar ve bu da zaten üzerine yazılacak. Son olarak, bu "yalnızca kod içeren bir yanıttır" ve bu tür yanıtlar, gelecekteki araştırmacıları eğitmek / güçlendirmek için çok az şey yaptıkları için düşük değerlidir.
mickmackusa

2

Resmi dokümanlar yanlış ve set E_NOTICE dönmelidir söylüyor

ancak hata aldığınız için, hata raporlama E_NOTICE tarafından tetiklenecek şekilde ayarlandı

burada, tarafından döndürülen yanlışlığı tespit etmenize olanak tanıyan bir düzeltme unserialize

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

base64 kodlama / kod çözme kullanmayı düşünebilirsiniz

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

base64_encodebenim için hile yaptı. Benim durumum, serialized verisini komut satırından geçiriyoruz ve bazı garip karakterler düzgün çalışmasını engelliyor gibi görünüyordu.
quickshiftin

base64_encode()OP tarafından sorulan sorunun çözümü değil. OP'nin sorusu / sorunu özellikle serileştirilmiş dizgede yanlış bir bayt sayısı olması (muhtemelen serileştirilmiş dizginin "son dizi öğesinde" uygun olmayan bir alt dizge değişimi yapılmasıyla ilgilidir) ile ilgilidir. Lütfen yalnızca sorulan soruyla doğrudan ilgilenen yanıtları gönderin.
mickmackusa

2

Bu sorudaki bozulma, ile serileştirilmiş dizenin sonundaki tek bir alt dizeye izole edilmiştir, büyük olasılıkla imagedosya adını yavaşça güncellemek isteyen biri tarafından manuel olarak değiştirilmiştir . Bu gerçek, OP'nin yayınlanan verilerini kullanarak aşağıdaki tanıtım bağlantımda açıkça görülecek - kısacası, C:fakepath100.jpgbir uzunluğu 19yok, olmalı 17.

Serileştirilmiş dizge bozulması yanlış bir bayt / karakter sayım numarasıyla sınırlı olduğundan, aşağıda belirtilenler bozuk dizgiyi doğru bayt sayısı değeriyle güncellemek için iyi bir iş çıkaracaktır.

Aşağıdaki normal ifadeye dayalı değiştirme, yalnızca bayt sayılarının giderilmesinde etkili olacaktır, başka bir şey değil.

Görünüşe göre önceki yayınların çoğu, başka birinden bir normal ifade kalıbını kopyalayıp yapıştırıyor. Değiştirme işleminde kullanılmayacaksa, potansiyel olarak bozuk bayt sayısı numarasını yakalamak için hiçbir neden yoktur. Ayrıca, sbir dize değerinin satırsonları / satır dönüşleri içermesi durumunda , desen değiştiricinin eklenmesi makul bir eklemedir.

* Çok baytlı karakterlerin serileştirme ile işlenmesinin farkında olmayanlar için mb_strlen(), özel geri aramada kullanmamalısınız çünkü karakter sayısı değil depolanan bayt sayısıdır, çıktıma bakın ...

Kod: ( OP verileriyle demo ) ( Rasgele örnek verilerle demo ) ( Koşul değiştirmeli demo )

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

Çıktı:

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

Tavşan deliğinin bir ayağı ... Yukarıdakiler, bir dize değerinde çift tırnak bulunsa bile iyi çalışır, ancak bir dize değeri içeriyorsa ";veya başka bir maymun kırıcı tuhaflık içeriyorsa, biraz daha ileri gitmeniz ve "bakma çözümleri" uygulamanız gerekir. Yeni kalıbım

baştaki ifadenin s:

  • tüm giriş dizesinin başlangıcı veya
  • öncesinde ;

ve şunun olduğunu kontrol eder ";:

  • tüm giriş dizesinin sonunda veya
  • ardından }veya
  • ardından bir dize veya tamsayı bildirimi s:veyai:

Her olasılığı test etmedim; aslında, serileştirilmiş bir dizedeki tüm olasılıklara göreceli olarak aşina değilim çünkü asla serileştirilmiş verilerle çalışmayı seçmiyorum - modern uygulamalarda her zaman json. Ek olası baştaki veya sondaki karakterler varsa, bir yorum bırakın ve ben de incelemeleri genişleteceğim.

Genişletilmiş 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));

Çıktı:

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

Harmanlama türünü olarak değiştirmeniz gerekecek utf8_unicode_cive sorun çözülecektir.


Harmanlamayı olarak değiştirerek OP'nin örnek verilerindeki hangi özel karakterin değiştirileceğini düşünüyorsunuz utf8_unicode_ci? Bu konuda şüphelerim var.
mickmackusa

Bu aynı zamanda benim için de işe yaradı (r00tAcc3ss'ün cevabı dışında) birinden nedenini açıklayan herhangi bir kelime? Arka plan olarak, bir API çağrısından bir ResourceSpace uygulamasına veri alıyorum, bir dizide depoluyorum, serileştiriyorum ve kaydediyorum. Serileştirilmiş veriler kaydediliyordu, bu yüzden manuel olarak UTF-8'e kodlamak zorunda kaldım, DB'de harmanlama ve karakter setiyle oynuyordum ve sonunda utf8_general_ci harmanlamasıyla bırakıldı, onu utf8_unicode_ci olarak değiştirdiğimde işe yaradı .
Roberto Becerra

1

Benim durumumda, BLOBgörünüşe göre tüm değeri içerecek kadar büyük olmayan ve onu kesen MySQL DB alanında serileştirilmiş verileri depoluyordum . Açıkçası, böyle bir dizge serileştirilemez.
O alanı MEDIUMBLOBsoruna dönüştürdükten sonra dağıldı. Ayrıca masa seçeneklerinde geçmek için gerekli olabilir ROW_FORMATiçin DYNAMICya COMPRESSED.


Ben - benimki bir TEXTtarla olmasına ve bu nedenle 65kb'de kesilmiş olmasına rağmen .
Antony

Bu soru kesintiye uğramaz. OP'nin sorusu / sorunu özellikle serileştirilmiş dizgede yanlış bir bayt sayısı olması (muhtemelen serileştirilmiş dizginin "son dizi öğesinde" uygun olmayan bir alt dizge değişimi yapılmasıyla ilgilidir) ile ilgilidir. Lütfen yalnızca sorulan soruyla doğrudan ilgilenen yanıtları gönderin.
mickmackusa

1

Bu sayfadaki bazı şeyleri başarılı olmadan denedikten sonra, sayfa kaynağına bir göz attım ve serileştirilmiş dizedeki tüm alıntıların html varlıklarıyla değiştirildiğini belirttim. Bu varlıkların kodunu çözmek, çok fazla baş ağrısını önlemeye yardımcı olur:

$myVar = html_entity_decode($myVar);

Bu soru, serileştirilmiş dizedeki html kodlu varlıklardan etkilenmez. OP'nin sorusu / sorunu özellikle serileştirilmiş dizgede yanlış bir bayt sayısı olması (muhtemelen serileştirilmiş dizginin "son dizi öğesinde" uygun olmayan bir alt dizge değişimi yapılmasıyla ilgilidir) ile ilgilidir. Lütfen yalnızca sorulan soruyla doğrudan ilgilenen yanıtları gönderin.
mickmackusa

@mickmackusa Bu soru neredeyse 7 yaşında ve cevabım ~ 1,5. Yine de bu kadar çok meşgul olman güzel!
David

SO sayfalarını seviyorum - genç ve yaşlı. İyi bir cevap ile o kadar da iyi olmayan cevap arasındaki farkı bilmeyen araştırmacılar arıyorum. Bu sayfa, talihsiz, konu dışı tavsiyelerle dolu.
mickmackusa

Harika! Nitelikli bir kontrol ve oylama zaten var, ancak sizi durdurmak için bir nedenim yok ;-)
David

Oh hayır, bir bak. Olumsuz oylanması gereken olumlu oylar var. Çok fazla insan ayırt edemez. Bu sayfada, oy sayısı kesinlikle kalite / uygunluk göstergesi değildir. Olumsuz oy kullanmakla zamanımı boşa harcamayacağım çünkü olumsuz oyum çetele üzerinde bir etki yaratmayacak. Yapabileceğim en iyi şey, neyin iyi / kötü / çirkin olduğunu açıklamak için yorum bırakmaktır.
mickmackusa

1

İşte bozuk bir serileştirilmiş dizeyi düzeltmek için bir Çevrimiçi Araç .

Bu çoğunlukla nedeniyle aramada olur ve DB ve (seri verilerine yapılan replace olduğunu eklemek istiyorum özelkey length ) ve "yolsuzluk" neden replace göre güncellenen almaz.

Bununla birlikte, yukarıdaki araç, serileştirme verilerini düzeltmek için aşağıdaki mantığı kullanır ( Buradan Kopyalanır ).

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

Bu sorunun bir başka nedeni de "payload" oturum tablosunun sütun türü olabilir. Oturumda çok büyük veriniz varsa, bir metin sütunu yeterli olmayacaktır. MEDIUMTEXT veya hatta LONGTEXT'e ihtiyacınız olacak.


Bu soru kesintiye uğramaz. OP'nin sorusu / sorunu özellikle serileştirilmiş dizgede yanlış bir bayt sayısı olması (muhtemelen serileştirilmiş dizginin "son dizi öğesinde" uygun olmayan bir alt dizge değişimi yapılmasıyla ilgilidir) ile ilgilidir. Lütfen yalnızca sorulan soruyla doğrudan ilgilenen yanıtları gönderin.
mickmackusa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.