Magento 2.2: ¿No se puede deserializar el valor?

33

Encontrarse con problemas en un sitio que ejecuta Magento 2.2.0-rc3.0 / PHP 7.0.23

El siguiente problema ocurre con todas las extensiones de terceros habilitadas o deshabilitadas.

Al agregar un elemento a la comparación desde la página de categoría o producto o al enviar una revisión desde la página del producto, aparece el siguiente error en el navegador:

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}

El error no desaparece a menos que borre las cookies, en particular, la cookie de mensajes de mago. ingrese la descripción de la imagen aquí

Se agradece cualquier ayuda para solucionar estos errores.

Arrojar
fuente
¿No es eso un error central? ¿Hay un problema de GitHub para esto?
Alex
esto te dará una idea scommerce-mage.com/blog/…
stevensagaar

Respuestas:

60

Pude resolver este problema borrando mi Redis Cache de la CLI

redis-cli flushall

Espero que esto ayude a los futuros usuarios.

Craig
fuente
2
Bien hecho. Probablemente esta debería ser la respuesta aceptada.
Shawn Abramson
Parece que no siempre es la solución. En mi caso, ni siquiera uso redis (todavía)
Alex
Gracias. reinicié el barniz, pensando que eso lo enjuagaría, pero esto funcionó.
ladle3000
funciona para mí
Jared Chu
Esto me ayudó durante la actualización de 2.2.9 a 2.3.2. Recibí el error cuando ejecuté la configuración de
Mohammed Joraid
30

El problema está en /vendor/magento/framework/Serialize/Serializer/Json.php, hay una función unserialize ($ string) que le da un error de sintaxis si la cadena se serializa (no json sino serialización php).

Hay una solución alternativa: puede verificar si la cadena está serializada (frente a codificada por json) y luego usar serializar ($ cadena). Cambie no serializar a:

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

y agregue la función para verificar si la cadena está serializada:

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

Después de guardar fe. categoría sin problema, puede restaurar la clase a la predeterminada y no habrá tal problema en el futuro.

Edmund
fuente
1
Funciona 100% bien para mí. ¡Muchas gracias!
mapaladiya
2
no funciona ... :-(
Arfan Mirza
Verifique qué sucede si se pasa el valor a: 0: {}. Ir línea por línea. ¿Qué sucede si el resultado de unserialize se pasa a un método de tipo fuerte que espera una matriz? Es posible que desee cambiar su respuesta.
vitoriodachef
20

No edite archivos principales para la solución. Reemplazar la siguiente forma Simplemente coloque la siguiente línea en di.xml dentro del directorio etc.

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

Y dentro del espacio de nombres \ ModuleName \ Serialize \ Serializer Directory: archivo 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;
    }
}

Funciona perfectamente

Sameer Bhayani
fuente
2
La implementación es defectuosa. ¿Qué sucede si el valor a: 0: {} se pasa al método Json: unserialize? ¿Es el comportamiento deseado? ¿Cuál es el punto de la variable de resultado en el método is_serialized? No se devuelve y no tiene impacto sobre nada, ya que en la llamada al método no se pasa ninguna variable como segundo argumento.
vitoriodachef
Esta debería ser la solución aceptada, y es mucho mejor que la publicación anterior para editar el archivo directamente en el proveedor. Lo más probable es que tenga que ejecutar la tarea de actualización de configuración localmente y luego nuevamente en la preparación / producción, por lo que tendrá que persistir en los entornos y el proveedor / directorio es un artefacto creado en el momento de la compilación.
Mark Shust
@vitoriodachef Estoy enfrentando el caso exacto que has mencionado. ¿Has encontrado alguna solución?
Knight017
He utilizado la siguiente función para decidir si la función privada es Serializada ($ valor) {return (boolean) preg_match ('/ ^ ((s | i | d | b | a | O | C): | N;) /', $ value ); }
Knight017
No funcionó. Tuve que cambiar manualmente todas las entradas en el DB de a:0:{}a[]
localhost
16

En mi caso, parcheé lo siguiente para deserializar una cadena serializada: Archivo: /vendor/magento/framework/Serialize/Serializer/Json.php

Encontrar:

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

sustituir por:

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;
}
MageLearner
fuente
He intentado esto pero no funciona como se esperaba. ¿Alguien ha intentado esto y si funciona, por favor ayúdame
Siva
¿Qué problemas estabas enfrentando?
MageLearner
El problema se solucionó. ¡Gracias por preguntar!
Siva
1
Grt ... gracias !!!
MageLearner
1
Gracias @MageLearner, también funciona en 2.3.1 después de migrar los datos de magento 1 a magento 2
Pradeep Thakur
5

Después de enrojecer a Redis, el problema se ha solucionado. Gracias Craig por la solución.

Estoy usando el puerto 6379 para caché, así que ejecuto el comando:

redis-cli -p 6379 flushall
Praveen P. Rokade
fuente
4

Está relacionado principalmente con la memoria caché de Redis, así que trate de eliminar esto con un comando simple en su SSH

redis-cli flushall

Tahir Iqbal Najam
fuente
3

Resultó ser un problema de permisos, donde magento estaba configurando permisos para archivos generados que estaban restringidos en este servidor.

Se resolvió creando el archivo magento_umask en el directorio raíz con la umask adecuada para el servidor.

Consulte http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.html para obtener detalles adicionales.

Arrojar
fuente
Hola, me enfrento a un problema relacionado como este. ¿Puedes mirar esto ?
Aditya Shah
@chunk todos mis directorios son 755, y los archivos son 644, ¿cuál es la umask adecuada para configurar? tia
Kris Wen
2

La respuesta anterior de Sameers funcionó para mí, aunque tuve que usar un código diferente en el bloque.

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;
}
Adam Jackson
fuente
1

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

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

2. Simplemente reemplace la siguiente función (deserializar) y agregue una nueva función O simplemente descargue el archivo adjunto y reemplácelo por defecto

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. Añadir nueva función:

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;
} 
mnojind
fuente
Mi problema no se solucionó ... por favor ayúdenme
Muhammad Ahmed
1

Personalmente, encontré que este problema se basaba en ejecutar el comando:

php bin/magento setup:upgrade

Después de una migración. Descubrí que me faltaba la clave hash " cripta " en src/app/etc/env.php:

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

    ...

¡Asegúrese de que esto no esté vacío y de que coincida con los otros entornos de sus proyectos!

Chris Rogers
fuente
Dejé la clave de cripta vacía durante la instalación esperando que se generara una nueva, lo que claramente no sucede.
Cambiaformas
0

Estaba recibiendo el error en una página CMS en el front-end.

Fue el código del widget Magento en el contenido de la página CMS lo que estaba causando el problema (que copié de otra fuente). Eliminé el código del widget e inserté el mismo widget usando el botón Insertar widget en la pantalla de edición de la página CMS y funcionó.

El proceso anterior formateó el código del widget de manera diferente e hizo que el error desapareciera.

Binod
fuente
0

Descubrí que toda la información serializada no puede encajar en una columna de la tabla MySQL de la base de TEXTdatos con el tipo de datos.
Acabo de encontrar que el flag_datavalor de la columna de la system_config_snapshotlínea está recortado.

Tuve que cambiarlo MEDIUMTEXTpara esta columna flag.flag_data.

Kirby
fuente
0

Fue el mismo error. Cuando trató de actualizar la base de datos (ver 2.2.6) con código nuevo (ver 2.3.2).

Para arreglar - ejecutado

composer update
Alex
fuente
0

Esta no es la mejor manera de ejecutar sql directamente, pero lo hice para ahorrarme tiempo. Solo ejecuta esta consulta

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';
gh darvishani
fuente
0

Si tiene la versión 2.3.0 o superior, querrá usar la solución provista por MageLearner. La forma más antigua con declaraciones de casos es obsoleta. Si no utiliza la solución de MageLearner en 2.3.0 o superior; enfrentará todo tipo de problemas con la visualización de datos de pedidos y productos configurables.

Andy
fuente