Magento 2.2: Impossible de désérialiser la valeur?


33

Rencontrer des problèmes sur un site en cours d'exécution Rencontrer des Magento 2.2.0-rc3.0 / PHP 7.0.23

Le problème suivant se produit avec toutes les extensions tierces activées ou désactivées.

Lorsque vous ajoutez un article à une comparaison à partir d'une catégorie ou d'une page produit ou que vous soumettez un avis à partir d'une page produit, nous obtenons l'erreur suivante dans le navigateur:

1 exception(s):
Exception #0 (InvalidArgumentException): Unable to unserialize value.

Exception #0 (InvalidArgumentException): Unable to unserialize value.
#0 /home/___/public_html/app/code/Magento/Theme/Controller/Result/MessagePlugin.php(157): Magento\Framework\Serialize\Serializer\Json->unserialize('[{\\"type\\":\\"su...')
#1 /home/___/public_html/app/code/Magento/Theme/Controller/Result/MessagePlugin.php(135): Magento\Theme\Controller\Result\MessagePlugin->getCookiesMessages()
#2 /home/___/public_html/app/code/Magento/Theme/Controller/Result/MessagePlugin.php(84): Magento\Theme\Controller\Result\MessagePlugin->getMessages()
#3 /home/___/public_html/lib/internal/Magento/Framework/Interception/Interceptor.php(146): Magento\Theme\Controller\Result\MessagePlugin->afterRenderResult(Object(Magento\Framework\View\Result\Page\Interceptor), Object(Magento\Framework\View\Result\Page\Interceptor), Object(Magento\Framework\App\Response\Http\Interceptor))
#4 /home/___/public_html/lib/internal/Magento/Framework/Interception/Interceptor.php(153): Magento\Framework\View\Result\Page\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Response\Http\Interceptor))
#5 /home/___/public_html/generated/code/Magento/Framework/View/Result/Page/Interceptor.php(26): Magento\Framework\View\Result\Page\Interceptor->___callPlugins('renderResult', Array, Array)
#6 /home/___/public_html/lib/internal/Magento/Framework/App/Http.php(139): Magento\Framework\View\Result\Page\Interceptor->renderResult(Object(Magento\Framework\App\Response\Http\Interceptor))
#7 /home/___/public_html/lib/internal/Magento/Framework/App/Bootstrap.php(256): Magento\Framework\App\Http->launch()
#8 /home/___/public_html/index.php(39): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http))
#9 {main}

L'erreur ne disparaît que si vous effacez les cookies, en particulier le cookie mage-messages. entrez la description de l'image ici

Toute aide au dépannage de ces erreurs est appréciée.


N'est-ce pas un bug de base? y a-t-il un problème avec GitHub?
Alex

cela vous donnera une idée scommerce-mage.com/blog/…
stevensagaar

Réponses:


60

J'ai pu résoudre ce problème en vidant mon cache Redis de la CLI

redis-cli flushall

J'espère que cela aidera les futurs utilisateurs.


2
Bien fait. Cela devrait probablement être la réponse acceptée.
Shawn Abramson

Cela ne semble pas toujours être la solution. Dans mon cas, je n'utilise même pas (encore) redis
Alex

Merci. J'ai redémarré le vernis, pensant que cela le rincerait, mais cela a fait l'affaire.
ladle3000

cela fonctionne pour moi
Jared Chu

Cela m'a aidé lors de la mise à niveau de 2.2.9 vers 2.3.2. J'ai eu l'erreur quand j'ai exécuté l' installation de
Mohammed Joraid

30

Le problème est dans /vendor/magento/framework/Serialize/Serializer/Json.php, il y a une fonction unserialize ($ string) qui vous donne une erreur de syntaxe si la chaîne est sérialisée (pas json mais la sérialisation php).

Il existe une solution de contournement - vous pouvez vérifier si la chaîne est sérialisée (par rapport au codage json), puis utiliser la sérialisation ($ chaîne). Modifiez la désérialisation en:

public function unserialize($string)
{
    if($this->is_serialized($string))
    {
        $string = $this->serialize($string);
    }
    $result = json_decode($string, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
         throw new \InvalidArgumentException('Unable to unserialize value.');

    }
    return $result;
}

et ajoutez une fonction pour vérifier si la chaîne est sérialisée:

function is_serialized($value, &$result = null)
{
    // Bit of a give away this one
    if (!is_string($value))
    {
        return false;
    }
    // Serialized false, return true. unserialize() returns false on an
    // invalid string or it could return false if the string is serialized
    // false, eliminate that possibility.
    if ($value === 'b:0;')
    {
        $result = false;
        return true;
    }
    $length = strlen($value);
    $end    = '';
    switch ($value[0])
    {
        case 's':
            if ($value[$length - 2] !== '"')
            {
                return false;
            }
        case 'b':
        case 'i':
        case 'd':
            // This looks odd but it is quicker than isset()ing
            $end .= ';';
        case 'a':
        case 'O':
            $end .= '}';
            if ($value[1] !== ':')
            {
                return false;
            }
            switch ($value[2])
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    break;
                default:
                    return false;
            }
        case 'N':
            $end .= ';';
            if ($value[$length - 1] !== $end[0])
            {
                return false;
            }
            break;
        default:
            return false;
    }
    if (($result = @unserialize($value)) === false)
    {
        $result = null;
        return false;
    }
    return true;
}

Après avoir enregistré fe. catégorie sans problème, vous pouvez restaurer la classe par défaut et il n'y aura plus de problème à l'avenir.


1
Cela fonctionne à 100% pour moi. Merci beaucoup!
mapaladiya

2
ça ne marche pas ... :-(
Arfan Mirza

Vérifiez ce qui se passe si la valeur a: 0: {} est transmise. Allez ligne par ligne. Que se passe-t-il si le résultat de la désérialisation est transmis à une méthode typée forte qui attend un tableau? Vous voudrez peut-être changer votre réponse.
vitoriodachef

20

Ne modifiez pas les fichiers principaux pour la solution. Remplacer la manière suivante Il suffit de mettre la ligne suivante dans di.xml dans le répertoire etc

<preference for="Magento\Framework\Serialize\Serializer\Json" type="Namespace\ModuleName\Serialize\Serializer\Json" />

Et dans Namespace \ ModuleName \ Serialize \ Serializer Directory: fichier Json.php

<?php
namespace Namespace\ModuleName\Serialize\Serializer;



class Json extends \Magento\Framework\Serialize\Serializer\Json
{


    /**
     * {@inheritDoc}
     * @since 100.2.0
     */
    public function unserialize($string)
    {
      if($this->is_serialized($string))
        {
            $string = $this->serialize($string);
        }
        $result = json_decode($string, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
             throw new \InvalidArgumentException('Unable to unserialize value.');

        }
        return $result;
    }


    function is_serialized($value, &$result = null)
    {
    // Bit of a give away this one
        if (!is_string($value))
        {
            return false;
        }
        // Serialized false, return true. unserialize() returns false on an
        // invalid string or it could return false if the string is serialized
        // false, eliminate that possibility.
        if ($value === 'b:0;')
        {
            $result = false;
            return true;
        }
        $length = strlen($value);
        $end    = '';
        switch ($value[0])
        {
            case 's':
                if ($value[$length - 2] !== '"')
                {
                    return false;
                }
            case 'b':
            case 'i':
            case 'd':
                // This looks odd but it is quicker than isset()ing
                $end .= ';';
            case 'a':
            case 'O':
                $end .= '}';
                if ($value[1] !== ':')
                {
                    return false;
                }
                switch ($value[2])
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                    case 8:
                    case 9:
                        break;
                    default:
                        return false;
                }
            case 'N':
                $end .= ';';
                if ($value[$length - 1] !== $end[0])
                {
                    return false;
                }
                break;
            default:
                return false;
        }
        if (($result = @unserialize($value)) === false)
        {
            $result = null;
            return false;
        }
        return true;
    }
}

Fonctionne parfaitement


2
La mise en œuvre est défectueuse. Que se passe-t-il si la valeur a: 0: {} est transmise à la méthode Json: unserialize? Est-ce le comportement souhaité? Quel est l'intérêt de la variable de résultat dans la méthode is_serialized? Elle n'est pas renvoyée et n'a aucun impact sur quoi que ce soit car lors de l'appel de méthode, aucune variable n'est passée comme deuxième argument.
vitoriodachef

Cela devrait être la solution acceptée, et c'est bien mieux que le post ci-dessus pour éditer le fichier directement chez le fournisseur. Plus que probablement, vous devrez exécuter la tâche de mise à niveau de l'installation localement, puis à nouveau sur le transfert / la production, de sorte qu'il devra persister dans les environnements et le fournisseur / répertoire est un artefact créé au moment de la construction.
Mark Shust

@vitoriodachef Je fais face au cas exact que vous avez mentionné. Avez-vous trouvé une solution?
Knight017

J'ai utilisé la fonction suivante pour déterminer la fonction privée isSerialized ($ value) {return (boolean) preg_match ('/ ^ ((s | i | d | b | a | O | C): | N;) /', $ value ); }
Knight017

Ne fonctionnait pas. Je devais changer manuellement toutes les entrées de la base de données de a:0:{}la[]
localhost

16

Dans mon cas, j'ai corrigé comme suit pour désérialiser une chaîne sérialisée: Fichier: /vendor/magento/framework/Serialize/Serializer/Json.php

Trouver:

public function unserialize($string)
{
    $result = json_decode($string, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \InvalidArgumentException('Unable to unserialize value.');
    }
    return $result;
}

remplacer par:

public function unserialize($string)
{
    $result = json_decode($string, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        if(false !== @unserialize($string)){
            return unserialize($string);
        }
        throw new \InvalidArgumentException('Unable to unserialize value.');
    }
    return $result;
}

J'ai essayé cela mais cela ne fonctionne pas comme prévu. Quelqu'un
Siva

Quels problèmes avez-vous rencontrés?
MageLearner

Le problème a été résolu. Merci d'avoir posé la question!
Siva

1
Grt ... Merci !!!
MageLearner

1
Merci @MageLearner, Il fonctionne également en 2.3.1 après la migration des données de magento 1 vers magento 2
Pradeep Thakur

5

Après avoir vidé Redis, le problème a été résolu. Merci Craig pour la solution.

J'utilise le port 6379 pour le cache, donc j'exécute la commande:

redis-cli -p 6379 flushall

4

Il est principalement lié au cache Redis, alors essayez de le vider avec une commande simple dans votre SSH

redis-cli flushall


3

Il s'est avéré être un problème d'autorisations, où magento définissait des autorisations pour les fichiers générés qui étaient restreints sur ce serveur.

Résolu en créant un fichier magento_umask dans le répertoire racine avec le umask approprié pour le serveur.

Voir http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.html pour plus de détails.


Bonjour, je suis confronté au problème connexe comme celui-ci. Pouvez-vous s'il vous plaît regarder cela .
Aditya Shah

@chunk tous mes dir sont 755, et les fichiers sont 644, quel est le umask approprié à définir? tia
Kris Wen

2

La réponse de Sameers ci-dessus a fonctionné pour moi, même si j'ai dû utiliser un code différent dans le bloc.

public function serialize($data)
{
    $result = json_encode($data);
    if (false === $result) {
        throw new \InvalidArgumentException('Unable to serialize value.');
    }
    return $result;
}

function is_serialized($value, &$result = null)
{
    // Bit of a give away this one
    if (!is_string($value))
    {
        return false;
    }
    // Serialized false, return true. unserialize() returns false on an
    // invalid string or it could return false if the string is serialized
    // false, eliminate that possibility.
    if ($value === 'b:0;')
    {
        $result = false;
        return true;
    }
    $length = strlen($value);
    $end    = '';
    switch ($value[0])
    {
        case 's':
            if ($value[$length - 2] !== '"')
            {
                return false;
            }
        case 'b':
        case 'i':
        case 'd':
            // This looks odd but it is quicker than isset()ing
            $end .= ';';
        case 'a':
        case 'O':
            $end .= '}';
            if ($value[1] !== ':')
            {
                return false;
            }
            switch ($value[2])
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    break;
                default:
                    return false;
            }
        case 'N':
            $end .= ';';
            if ($value[$length - 1] !== $end[0])
            {
                return false;
            }
            break;
        default:
            return false;
    }
    if (($result = @unserialize($value)) === false)
    {
        $result = null;
        return false;
    }
    return true;
}

/**
 * {@inheritDoc}
 */
public function unserialize($string)
{
    if($this->is_serialized($string))
        {
        $result = $this->serialize($string);
        }
    $result = json_decode($string, true);

    return $result;
}

1

Répertoire ROOT 1. public_html/vendor/magento/framework/Serialize/Serializer/Json.php

Téléchargez JSON.php https://gist.github.com/manojind/9f18bbecaeb3e2bbfb056a634ade62a2

2. Il suffit de remplacer la fonction ci-dessous (désérialiser) et d'ajouter une nouvelle fonction OU simplement de télécharger le fichier joint et de le remplacer par défaut

public function unserialize($string)
{
    if($this->is_serialized($string))
    {
        $string = $this->serialize($string);
    }
    $result = json_decode($string, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
         throw new \InvalidArgumentException('Unable to unserialize value.');

    }
    return $result;
}

3. Ajoutez une nouvelle fonction:

function is_serialized($value, &$result = null)
{

    if (!is_string($value))
    {
        return false;
    }

    if ($value === 'b:0;')
    {
        $result = false;
        return true;
    }
    $length = strlen($value);
    $end    = '';
    switch ($value[0])
    {
        case 's':
            if ($value[$length - 2] !== '"')
            {
                return false;
            }
        case 'b':
        case 'i':
        case 'd':
                       $end .= ';';
        case 'a':
        case 'O':
            $end .= '}';
            if ($value[1] !== ':')
            {
                return false;
            }
            switch ($value[2])
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    break;
                default:
                    return false;
            }
        case 'N':
            $end .= ';';
            if ($value[$length - 1] !== $end[0])
            {
                return false;
            }
            break;
        default:
            return false;
    }
    if (($result = @unserialize($value)) === false)
    {
        $result = null;
        return false;
    }
    return true;
} 

Mon problème n'est pas résolu ... aidez-moi s'il vous plaît
Muhammad Ahmed

1

J'ai personnellement trouvé que ce problème provenait de la tête exécutant la commande:

php bin/magento setup:upgrade

Après une migration. J'ai découvert qu'il me manquait la clé de hachage " crypt " dans src/app/etc/env.php:

<?php
return [
    'backend' => [
        'frontName' => 'admin'
    ],
    'crypt' => [
        'key' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    ],

    ...

Assurez-vous qu'il n'est pas vide et correspond de préférence aux autres environnements de vos projets!


J'ai laissé la clé de cryptage vide pendant l'installation en m'attendant à ce qu'une nouvelle soit générée, ce qui ne se produit clairement pas.
Shapeshifter

0

J'obtenais l'erreur dans une page CMS en frontal.

C'était le code du widget Magento dans le contenu de la page CMS qui posait problème (que j'ai copié à partir d'une autre source). J'ai supprimé le code du widget et inséré le même widget à l'aide du bouton Insérer un widget dans l'écran d'édition de la page CMS et cela a fonctionné.

Le processus ci-dessus a formaté le code du widget différemment et a fait disparaître l'erreur.


0

J'ai découvert que des données sérialisées entières ne peuvent pas être insérées dans une colonne de table MySQL de base de TEXTdonnées avec un type de données.
Je viens de découvrir que la flag_datavaleur de colonne de la system_config_snapshotligne est coupée.

J'ai dû le changer MEDIUMTEXTpour cette colonne flag.flag_data.


0

C'était la même erreur. Lorsque vous essayez de mettre à jour la base de données (ver 2.2.6) avec un nouveau code (ver 2.3.2).

Pour correctif - exécuté

composer update

0

Ce n'est pas la meilleure façon d'exécuter SQL directement mais je l'ai fait pour gagner du temps. Exécutez simplement cette requête

ALTER TABLE flag MODIFY flag_data LONGTEXT;
UPDATE flag SET flag_data = '{"system":"","scopes":"","themes":""}' WHERE flag_code = 'config_hash';
UPDATE flag SET flag_data = '{}' WHERE flag_code = 'system_config_snapshot';

0

Si vous êtes sur 2.3.0 ou supérieur, vous voudrez utiliser la solution fournie par MageLearner. L'ancienne méthode avec les déclarations de cas est obsolète. Si vous n'utilisez pas la solution de MageLearner sur 2.3.0 ou supérieur; vous rencontrerez toutes sortes de problèmes avec l'affichage des données de commande et des produits configurables.

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.