Comment réparer une chaîne sérialisée qui a été corrompue par une longueur de nombre d'octets incorrecte?


97

J'utilise Hotaru CMS avec le plugin Image Upload, j'obtiens cette erreur si j'essaye de joindre une image à une publication, sinon il n'y a pas d'erreur:

unserialize () [function.unserialize]: Erreur au décalage

Le code incriminé (l'erreur pointe vers la ligne avec **):

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

Les données du tableau, notez que le bit de fin contient les informations sur l'image, je ne suis pas un expert en PHP, alors je me demandais ce que vous pourriez penser?

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: Je pense avoir trouvé le bit de sérialisation ...

/**
     * 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
Pour moi, la solution rapide pour cela consistait à utiliser base64_encode / decode avant de sérialiser / désérialiser. davidwalsh.name/php-serialize-unserialize-issues
Valentin Despa

1
Je ne sais pas pourquoi mais le mien est résolu avec @ ajouté,@unserialize($product->des_txtmopscol);
Bhavin Rana

2
L'ajout de @BhavinRana @ne résout pas les erreurs, c'est la suppression des erreurs - rien n'est réellement "corrigé" avec cette technique.
mickmackusa

Réponses:


218

unserialize() [function.unserialize]: Error at offsetla cotisation était invalid serialization datadue à une longueur invalide

Solution rapide

Ce que vous pouvez faire est recalculating the lengthdes éléments dans un tableau sérialisé

Vos données sérialisées actuelles

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

Exemple sans recalcul

var_dump(unserialize($data));

Production

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

Recalculer

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

Production

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)

Recommandation .. I

Au lieu d'utiliser ce type de solution rapide ... je vous conseille de mettre à jour la question avec

  • Comment vous sérialisez vos données

  • Comment vous le sauvegardez.

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

L'erreur

L'erreur a été générée en raison de l'utilisation de guillemets doubles "au lieu de guillemets simples, 'c'est pourquoi a C:\fakepath\100.pngété convertie enC:fakepath100.jpg

Pour corriger l'erreur

Vous devez changer de $h->vars['submitted_data'](notez le singe assez ')

Remplacer

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

Avec

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

Filtre supplémentaire

Vous pouvez également ajouter ce filtre simple avant d'appeler sérialiser

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

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

Si vous avez des caractères UTF, vous pouvez également exécuter

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

Comment détecter le problème dans les futures données sérialisées

  findSerializeError ( $data1 ) ;

Production

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 Fonction

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

    }

}

Une meilleure façon d'enregistrer dans la base de données

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

1
Baba, j'ai utilisé ta findSerializeErrorfonction incroyable et j'ai trouvé beaucoup d'erreurs. S'il vous plaît jeter un oeil à mon sujet
Max Koretskyi

1
utiliser base64sur l'article avant de l'ajouter à la base de données ... cela conserverait le caractère nul
Baba

1
Ce n'est donc pas une meilleure façon d'enregistrer dans la base de données. C'est le cas, à moins que vous ne vouliez complètement négliger le but de la base de données. Comment allez-vous effectuer une recherche dans un tas de valeurs chiffrées? Sans parler du ballonnement, ugh. Un bon encodage est la bonne réponse.
Deji

4
Si vous utilisez PHP 5.5, consultez la réponse @ r00tAcc3ss! stackoverflow.com/a/21389439/1003020
Vinicius Garcia

6
Si vous obtenez cette erreur "preg_replace (): Le modificateur / e n'est plus pris en charge, utilisez plutôt preg_replace_callback" dans php7 - cette réponse fonctionne stackoverflow.com/a/21389439/2011434
BenB

82

Je n'ai pas assez de réputation pour commenter, alors j'espère que les personnes qui utilisent la réponse "correcte" ci-dessus le verront:

Depuis php 5.5, le modificateur / e dans preg_replace () a été complètement obsolète et le preg_match ci-dessus sera une erreur. La documentation php recommande d'utiliser preg_match_callback à sa place.

Veuillez trouver la solution suivante comme alternative au preg_match proposé ci-dessus.

$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
Cela semble être la seule réponse sur la page qui utilise réellement le premier groupe de capture à bon escient. Bien que la programmation judicieuse n'effectue que des remplacements lorsque le nombre d'octets est en fait erroné, cette solution ne met pas en cache le strlen()et effectue donc des appels de fonction redondants. Personnellement, je trouve l'ajout d'une condition en ligne trop verbeux, mais cet extrait de code fait de bonnes choses pour de bonnes raisons.
mickmackusa

4
Cela a fonctionné pour moi avec la regex suivante '!s:(\d+):"(.*?)";!s'(avec une fin 's' pour prendre également de nouvelles lignes). Merci au commentaire d'adilbo ci-dessous.
ArnoHolo

13

Il y a une autre raison qui a unserialize()échoué parce que vous avez mal mis des données sérialisées dans la base de données, voir l' explication officielle ici. Puisque serialize()renvoie les données binaires et les variables php ne se soucient pas des méthodes de codage, de sorte que le mettre dans TEXT, VARCHAR () provoquera cette erreur.

Solution: stockez les données sérialisées dans BLOB dans votre table.


Cela a résolu mon problème dans Laravel 5. J'ai changé la définition de colonne de string () en binary ().
WNRosenberg

La question de l'OP ne semble pas avoir de problème de type de colonne mysql. Il est apparemment corrompu par un calcul d'octet incorrect sur la imagevaleur. Votre réponse ne concerne pas la question spécifique du PO. Vous pouvez déplacer vos conseils sur: stackoverflow.com/q/5544749/2943403
mickmackusa

11

Solution rapide

Recalculer la longueur des éléments dans un tableau sérialisé - mais n'utilisez pas (preg_replace) c'est obsolète - mieux utiliser preg_replace_callback:

Edit: Nouvelle version maintenant non seulement une mauvaise longueur, mais elle corrige également les sauts de ligne et compte les caractères corrects avec aczent (grâce à mickmackusa )

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

1
Comment cette solution incorrecte a-t-elle 8 votes positifs? Je me ferme pour penser au nombre de personnes qui auraient involontairement copié-collé ce one-liner. [visage triste] Voici la preuve de deux façons dont cet extrait de code échouera: 3v4l.org/Cf6Nh Voir mon modèle raffiné et mon remplacement personnalisé @ stackoverflow.com/a/55074706/2943403
mickmackusa

1
Ma solution n'est plus sur l'autre page car c'était une solution incorrecte pour la chaîne sérialisée endommagée de manière catastrophique. J'ai ajouté mon extrait à cette page et fourni des explications et des démonstrations. stackoverflow.com/a/55566407/2943403
mickmackusa

5

Cette erreur est due au fait que votre jeu de caractères est incorrect.

Définir le jeu de caractères après la balise ouverte:

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

Et définissez charset utf8 dans votre base de données:

mysql_query("SET NAMES 'utf8'");

Je ne vois aucune indication dans la question postée du PO suggérant que la corruption est due au jeu de caractères. Gratuit pour défendre votre réclamation, mais pour autant que je sache, quelqu'un a mis à jour manuellement la imagevaleur et n'a pas réussi à mettre à jour le nombre d'octets. Sauf indication contraire, je dois supposer que cette réponse est incorrecte pour la question du PO.
mickmackusa

4

Vous pouvez corriger une chaîne de sérialisation cassée en utilisant la fonction suivante, avec la gestion des caractères multi-octets .

function repairSerializeString($value)
{

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

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

Le cœur de ce que cette réponse recommande est tout simplement faux et endommagera potentiellement les chaînes sérialisées parfaitement valides. Cet extrait de code ne doit pas être utilisé / approuvé.
mickmackusa

@mickmackusa Je ne comprends pas votre point, pouvez-vous suggérer la meilleure façon de le faire? ou suggérer de modifier cette réponse ..
Rajesh Meniya

J'ai fourni une solution correcte ici: stackoverflow.com/a/55566407/2943403 et expliqué que mb_strlen()c'est inapproprié car serialize()stocke le nombre d'octets, pas le nombre de caractères. Modifier votre réponse pour qu'elle soit correcte ne créerait que des conseils redondants sur la page.
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

Cette solution ne convient pas dans de nombreux cas. Il suppose que tout le monde voudra muter les valeurs de la chaîne sérialisée pour convertir 2 caractères d'espacement ou plus en un espace littéral ET trim()chaque sous-chaîne correspondante. Ce seul point rend cette solution impossible à recommander. De plus, il s'étouffera avec les caractères de nouvelle ligne et capture inutilement le nombre d'octets préexistant qui va juste être écrasé de toute façon. Enfin, il s'agit d'une «réponse codée uniquement» et ces types de réponses sont de faible valeur car ils ne contribuent guère à éduquer / autonomiser les futurs chercheurs.
mickmackusa

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

Vous ne pouvez pas réparer une chaîne de sérialisation cassée à l'aide des expressions régulières proposées:

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

Vous pouvez corriger la chaîne de sérialisation cassée à l'aide de l'expression régulière suivante:

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

var_dump(@unserialize($data));

Production

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

ou

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

1
@mickmackusa Merci. Correction d'un problème avec les encodages multi-octets.
Даниил Путилин

2

les documents officiels dit qu'il devrait retourner false et définir E_NOTICE

mais comme vous avez une erreur, le rapport d'erreur est configuré pour être déclenché par E_NOTICE

voici un correctif pour vous permettre de détecter les faux retournés par unserialize

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

vous voudrez peut-être envisager d'utiliser l'encodage / décodage base64

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

base64_encodea fait l'affaire pour moi. Dans mon cas, nous transmettons des serializedonnées sur la ligne de commande et il semblait que des caractères étranges l'empêchaient de fonctionner correctement.
quickshift du

base64_encode()n'est pas la solution à la question posée par le PO. La question / problème de l'OP traite spécifiquement du fait que (probablement en cas de remplacement de sous-chaîne inapproprié sur "l'élément de tableau final" de la chaîne sérialisée) il y a un nombre d'octets incorrect dans la chaîne sérialisée. Veuillez ne publier que des réponses qui traitent directement de la question posée.
mickmackusa

2

La corruption dans cette question est isolée sur une seule sous-chaîne à la fin de la chaîne sérialisée avec probablement été remplacée manuellement par quelqu'un qui voulait paresseusement mettre à jour le imagenom de fichier. Ce fait sera apparent dans mon lien de démonstration ci-dessous en utilisant les données publiées par le PO - en bref, il C:fakepath100.jpgn'a pas une longueur de 19, il devrait l'être 17.

Étant donné que la corruption de chaîne sérialisée est limitée à un nombre d'octets / caractères incorrect, ce qui suit fera un bon travail de mise à jour de la chaîne corrompue avec la valeur de nombre d'octets correcte.

Le remplacement suivant basé sur les expressions régulières ne sera efficace que pour remédier au nombre d'octets, rien de plus.

Il semble que la plupart des articles précédents ne font que copier-coller un modèle d'expression régulière de quelqu'un d'autre. Il n'y a aucune raison de capturer le nombre d'octets potentiellement corrompu s'il n'est pas utilisé dans le remplacement. Aussi, en ajoutant les modificateur de modèle est une inclusion raisonnable dans le cas où une valeur de chaîne contient des retours à la ligne / des retours de ligne.

* Pour ceux qui ne connaissent pas le traitement des caractères multi-octets avec la sérialisation, vous ne devez pas utiliser mb_strlen()dans le rappel personnalisé car c'est le nombre d'octets qui est stocké et non le nombre de caractères , voir ma sortie ...

Code: ( Démo avec les données de l'OP ) ( Démo avec des exemples de données arbitraires ) ( Démo avec remplacement de condition )

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

Production:

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

Une jambe dans le trou du lapin ... Ce qui précède fonctionne bien même si des guillemets doubles apparaissent dans une valeur de chaîne, mais si une valeur de chaîne contient"; ou quelque autre sbustring de singe, vous devrez aller un peu plus loin et implémenter des "lookarounds". Mon nouveau modèle

vérifie que le début sest:

  • le début de toute la chaîne d'entrée ou
  • précédé par ;

et vérifie que le ";est:

  • à la fin de toute la chaîne d'entrée ou
  • suivi par } ou
  • suivi d'une déclaration de chaîne ou d'entier s:oui:

Je n'ai pas testé toutes les possibilités; en fait, je ne suis relativement pas familier avec toutes les possibilités d'une chaîne sérialisée parce que je n'ai jamais choisi de travailler avec des données sérialisées - toujours json dans les applications modernes. S'il y a d'autres caractères de début ou de fin possibles, laissez un commentaire et je vais étendre les recherches.

Extrait étendu: ( Démo )

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

Production:

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

Vous devrez modifier le type de classement utf8_unicode_ciet le problème sera résolu.


Selon vous, quel caractère spécifique des exemples de données de l'OP sera modifié en changeant le classement utf8_unicode_ci? J'ai mes doutes sur celui-ci.
mickmackusa

Cela a également fonctionné pour moi (à part la réponse de r00tAcc3ss) un mot de quelqu'un clarifiant pourquoi? En arrière-plan, je prends les données d'un appel API vers une application ResourceSpace, je les stocke dans un tableau, je la sérialise et je l'enregistre. Les données sérialisées avaient des problèmes lors de l'enregistrement, je devais donc les encoder manuellement en UTF-8, je jouais avec le classement et le jeu de caractères dans la base de données, et je me suis finalement retrouvé avec le classement utf8_general_ci, quand je l'ai changé en utf8_unicode_ci, cela a fonctionné .
Roberto Becerra

1

Dans mon cas, je stockais des données sérialisées dans le BLOBchamp de la base de données MySQL qui n'était apparemment pas assez grande pour contenir la valeur entière et je l'ai tronquée. Une telle chaîne ne pouvait évidemment pas être désérialisée.
Une fois converti, ce champ en MEDIUMBLOBproblème s'est dissipé. Il peut également être nécessaire de basculer les options de table ROW_FORMATvers DYNAMICou COMPRESSED.


Moi à - bien que le mien était un TEXTchamp et en tant que tel tronqué à 65kb.
Antony

Cette question ne souffre pas de troncature. La question / problème de l'OP traite spécifiquement du fait que (probablement en cas de remplacement de sous-chaîne inapproprié sur le "dernier élément de tableau" de la chaîne sérialisée) il y a un nombre d'octets incorrect dans la chaîne sérialisée. Veuillez ne publier que des réponses qui traitent directement de la question posée.
mickmackusa

1

Après avoir essayé certaines choses sur cette page sans succès, j'ai jeté un coup d'œil dans la page-source et j'ai remarqué que toutes les citations de la chaîne sérialisée ont été remplacées par des entités html. Le décodage de ces entités permet d'éviter beaucoup de maux de tête:

$myVar = html_entity_decode($myVar);

Cette question ne souffre pas d'entités codées html dans la chaîne sérialisée. La question / problème de l'OP traite spécifiquement du fait que (probablement en cas de remplacement de sous-chaîne inapproprié sur le "dernier élément de tableau" de la chaîne sérialisée) il y a un nombre d'octets incorrect dans la chaîne sérialisée. Veuillez ne publier que des réponses qui traitent directement de la question posée.
mickmackusa

@mickmackusa Cette question a presque 7 ans et ma réponse ~ 1,5. Néanmoins sympa que tu t'engages autant!
David

J'adore les pages SO - jeunes et vieux. Je recherche des chercheurs qui ne connaissent pas la différence entre une bonne réponse et une moins bonne réponse. Cette page, malheureusement, regorge de conseils hors sujet.
mickmackusa

Génial! Il y a déjà un contrôle de qualité et un vote, mais je n'ai aucune raison de vous arrêter ;-)
David

Oh non, regarde. Il y a des réponses qui devraient être votées contre. Trop de gens ne peuvent pas se différencier. Sur cette page, le décompte des votes n'est absolument pas une indication de qualité / pertinence. Je ne vais pas perdre mon temps à voter contre parce que mon vote négatif ne fera pas de différence dans le décompte. Le mieux que je puisse faire est de laisser des commentaires pour expliquer ce qui est bon / mauvais / laid.
mickmackusa

1

Voici un outil en ligne pour réparer une chaîne sérialisée corrompue.

Je voudrais ajouter que cela se produit principalement en raison d'une recherche et d'un remplacement effectués sur la base de données et les données de sérialisation (en particulier lekey length ) ne sont pas mises à jour selon le remplacement et cela provoque la «corruption».

Néanmoins, l'outil ci-dessus utilise la logique suivante pour corriger les données de sérialisation ( copiées à partir d'ici ).

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

Une autre raison de ce problème peut être le type de colonne de la table de sessions "payload". Si vous avez d'énormes données sur la session, une colonne de texte ne suffirait pas. Vous aurez besoin de MEDIUMTEXT ou même de LONGTEXT.


Cette question ne souffre pas de troncature. La question / problème de l'OP traite spécifiquement du fait que (probablement en cas de remplacement de sous-chaîne inapproprié sur le "dernier élément de tableau" de la chaîne sérialisée) il y a un nombre d'octets incorrect dans la chaîne sérialisée. Veuillez ne publier que des réponses qui traitent directement de la question posée.
mickmackusa
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.