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.