Magento 2.2: impossibile annullare la serializzazione del valore?


33

Problemi con un sito che esegue Magento 2.2.0-rc3.0 / PHP 7.0.23

Il seguente problema si verifica con tutte le estensioni di terze parti abilitate o disabilitate.

Quando si aggiunge un articolo al confronto dalla categoria o dalla pagina del prodotto o si invia una recensione dalla pagina del prodotto, nel browser viene visualizzato il seguente errore:

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'errore non scompare a meno che non si cancellino i cookie, in particolare il cookie dei messaggi dei maghi. inserisci qui la descrizione dell'immagine

È gradita l'assistenza nella risoluzione di questi errori.


Non è un bug di base? c'è un problema con GitHub per questo?
Alex,

Risposte:


60

Sono stato in grado di risolvere questo problema scaricando la mia cache Redis dalla CLI

redis-cli flushall

Spero che questo aiuti i futuri utenti.


2
Ben fatto. Questa dovrebbe probabilmente essere la risposta accettata.
Shawn Abramson,

Sembra non essere sempre la soluzione. Nel mio caso non uso nemmeno il redis (ancora)
Alex,

Grazie. ho riavviato la vernice, pensando che l'avrebbe scaricata, ma questo ha funzionato.
ladle3000

funziona per me
Jared Chu il

Questo mi ha aiutato durante l'aggiornamento da 2.2.9 a 2.3.2. Ho ricevuto l'errore quando ho eseguito l' installazione
Mohammed Joraid,

30

Il problema è in /vendor/magento/framework/Serialize/Serializer/Json.php c'è una funzione unserialize ($ string) che ti dà un errore di sintassi se la stringa è serializzata (non json ma serializzazione php).

Esiste una soluzione alternativa: è possibile verificare se la stringa è serializzata (vs codificata json) e quindi utilizzare la serializzazione ($ stringa). Modifica non serializzata in:

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

e aggiungi la funzione per verificare se la stringa è serializzata:

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

Dopo aver salvato fe. categoria senza problemi, è possibile ripristinare la classe ai valori predefiniti e non si verificherà tale problema in futuro.


1
Funziona al 100% per me. Molte grazie!
mapaladiya,

2
non funziona ... :-(
Arfan Mirza il

Controlla cosa succede se viene passato il valore a: 0: {}. Vai riga per riga. Cosa succede se il risultato di unserialize viene passato a un metodo tipizzato forte che prevede un array? Potresti voler cambiare la tua risposta.
vitoriodachef,

20

Non modificare i file core per la soluzione. Sostituisci il modo seguente Metti la seguente riga nella directory di.xml nella directory etc

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

E dentro Namespace \ ModuleName \ Serialize \ Serializer Directory: file 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;
    }
}

Funziona perfettamente


2
L'implementazione è difettosa. Cosa succede se il valore a: 0: {} viene passato al metodo Json: unserialize? È il comportamento desiderato? Qual è il punto della variabile risultato nel metodo is_serialized? Non viene restituito e non ha alcun impatto su nulla in quanto alla chiamata del metodo nessuna variabile viene passata come secondo argomento.
vitoriodachef,

Questa dovrebbe essere la soluzione accettata ed è molto meglio del post sopra per modificare il file direttamente nel fornitore. Molto probabilmente, dovrai eseguire l'attività di aggiornamento dell'installazione localmente e poi di nuovo sulla gestione temporanea / produzione, quindi dovrà persistere ambienti e fornitore / directory è un artefatto creato al momento della creazione.
Mark Shust,

@vitoriodachef Sto affrontando il caso esatto che hai menzionato. Hai trovato qualche soluzione?
Knight017,

Ho usato la seguente funzione per decidere la funzione privata isSerialized ($ value) {return (boolean) preg_match ('/ ^ ((s | i | d | b | a | O | C): | N;) /', $ value ); }
Knight017,

Non ha funzionato. Ho dovuto cambiare manualmente tutte le voci nel DB da a:0:{}a[]
localhost il

16

Nel mio caso, ho patchato come segue per annullare la serializzazione di una stringa serializzata: File: /vendor/magento/framework/Serialize/Serializer/Json.php

Trova:

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

sostituito da:

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

Ho provato questo ma non funziona come previsto. Qualcuno lo ha provato e se funziona, per favore aiutatemi
Siva,

Quali problemi hai riscontrato?
MageLearner,

Il problema è stato risolto. Grazie per avermelo chiesto!
Siva,

1
Grt ... Grazie !!!
MageLearner,

1
Grazie @MageLearner, Funziona anche in 2.3.1 dopo aver migrato i dati da Magento 1 a Magento 2
Pradeep Thakur

5

Dopo aver scaricato Redis il problema è stato risolto. Grazie Craig per la soluzione.

Sto usando la porta 6379 per la cache, quindi eseguo il comando:

redis-cli -p 6379 flushall

4

È principalmente correlato alla cache Redis, quindi prova a svuotare questo con un semplice comando nel tuo SSH

Redis-Cli Flushall


3

Si è rivelato essere un problema di autorizzazioni, in cui magento stava impostando le autorizzazioni per i file generati che erano limitati su questo server.

Risolto creando il file magento_umask nella directory principale con l'umask appropriato per il server.

Vedi http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.html per ulteriori dettagli.


Ciao, sto affrontando il problema correlato in questo modo. Puoi per favore dare un'occhiata a questo .
Aditya Shah,

@chunk tutte le mie dir sono 755 e i file sono 644, qual è l'umask appropriato da impostare? tia
Kris Wen,

2

La risposta di Sameers sopra ha funzionato per me anche se ho dovuto usare un codice diverso nel blocco.

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

Directory ROOT 1. public_html/vendor/magento/framework/Serialize/Serializer/Json.php

Scarica JSON.php https://gist.github.com/manojind/9f18bbecaeb3e2bbfb056a634ade62a2

2. Basta sostituire la funzione seguente (annullare la serializzazione) e aggiungere una nuova funzione O semplicemente scaricare il file allegato e sostituirlo con l'impostazione predefinita

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. Aggiungi nuova funzione:

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

Il mio problema non è stato risolto ... aiutatemi
Muhammad Ahmed,

1

Personalmente ho riscontrato che questo problema ha sollevato la testa eseguendo il comando:

php bin/magento setup:upgrade

Dopo una migrazione. Ho scoperto che mi mancava la chiave hash " crypt " in src/app/etc/env.php:

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

    ...

Assicurati che questo non sia vuoto e corrisponda preferibilmente agli altri ambienti dei tuoi progetti!


Ho lasciato vuota la chiave di crittografia durante l'installazione aspettandomi che ne venisse generata una nuova, il che chiaramente non accade.
Shapeshifter,

0

Stavo ottenendo l'errore in una pagina CMS nel front-end.

Era il codice del widget Magento nel contenuto della pagina CMS a causare il problema (che ho copiato da un'altra fonte). Ho cancellato il codice del widget e inserito lo stesso widget usando il pulsante Inserisci widget nella schermata di modifica della pagina CMS e ha funzionato.

Il processo sopra descritto ha formattato il codice del widget in modo diverso e ha eliminato l'errore.


0

Ho scoperto che interi dati serializzati non possono essere inseriti in una colonna della tabella MySQL del database con TEXTtipo di dati.
Ho appena trovato il flag_datavalore della colonna disystem_config_snapshot linea è stato tagliato.

Ho dovuto cambiarlo in MEDIUMTEXTper questa colonna flag.flag_data.


0

È stato lo stesso errore. Quando si tenta di aggiornare il database (versione 2.2.6) con codice nuovo (versione 2.3.2).

Per correzioni

composer update

0

Questo non è il modo migliore per eseguire sql direttamente ma l'ho fatto per risparmiare tempo. Basta eseguire questa query

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

Se hai la versione 2.3.0 o successiva, vorrai utilizzare la soluzione fornita da MageLearner. Il vecchio modo con le dichiarazioni dei casi è obsoleto. Se non usi la soluzione di MageLearner su 2.3.0 o versioni successive; colpirai ogni sorta di problemi con la visualizzazione dei dati degli ordini e dei prodotti configurabili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.