Magento 2.2: Incapaz de desserializar valor?

33

Correndo para problemas em um site executando o Magento 2.2.0-rc3.0 / PHP 7.0.23

O seguinte problema ocorre com todas as extensões de terceiros ativadas ou desativadas.

Ao adicionar um item à comparação da página de categoria ou produto ou ao enviar uma revisão da página do produto, obtemos o seguinte erro no 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}

O erro não desaparece, a menos que você limpe os cookies, em particular o cookie de mensagens de imagem. insira a descrição da imagem aqui

Qualquer assistência na solução desses erros é apreciada.

Mandril
fonte
Isso não é um bug do núcleo? existe um problema no GitHub para isso?
Alex
isto lhe dará uma idéia scommerce-mage.com/blog/...
stevensagaar

Respostas:

59

Consegui resolver esse problema liberando meu cache Redis da CLI

redis-cli flushall

Espero que isso ajude futuros usuários.

Craig
fonte
2
Bem feito. Provavelmente essa deve ser a resposta aceita.
Shawn Abramson
Parece nem sempre ser a solução. No meu caso eu nem sequer usar o Redis (ainda)
Alex
obrigado. Eu reiniciei o verniz, pensando que iria liberá-lo, mas isso fez o truque.
ladle3000 13/01
funciona para mim
Jared Chu
Isso me ajudou na atualização do 2.2.9 para o 2.3.2. Eu recebi o erro ao executar a instalação do php bin / magento: upgrade;
Mohammed Joraid
30

O problema está em /vendor/magento/framework/Serialize/Serializer/Json.php. Existe uma função unserialize ($ string) que fornece um erro de sintaxe se a string for serializada (não json, mas serialização php).

Existe uma solução alternativa - você pode verificar se a string é serializada (vs codificada por json) e, em seguida, usar serialize ($ string). Altere a desserialização para:

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 adicione a função para verificar se a sequência é 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;
}

Depois de salvar fe. categoria sem problema, você pode restaurar a classe para o padrão e não haverá esse problema no futuro.

Edmund
fonte
1
Está funcionando 100% bem para mim. Muito obrigado!
Mapaladiya
2
não está funcionando ... :-(
Arfan Mirza
Verifique o que acontece se o valor a: 0: {} for passado. Vá linha por linha. O que acontece se o resultado de desserializar for passado para um método de tipo forte que está esperando uma matriz? Você pode alterar sua resposta.
Vitoriodachef #
20

Não edite os arquivos principais da solução. Substituir a seguinte maneira Basta colocar a seguinte linha no di.xml dentro do diretório etc

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

E dentro do espaço para nome \ ModuleName \ Serialize \ Serializer Directory: arquivo 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 perfeitamente

Sameer Bhayani
fonte
2
A implementação é falha. O que acontece se o valor a: 0: {} for passado para o método Json: unserialize? É o comportamento desejado? Qual é o ponto da variável de resultado no método is_serialized? Não é retornado e não tem impacto sobre nada, pois na chamada do método nenhuma variável é passada como segundo argumento.
Vitoriodachef #
Essa deve ser a solução aceita e é muito melhor que a postagem acima para editar o arquivo diretamente no fornecedor. Muito provavelmente, você precisará executar a tarefa de atualização da instalação localmente e, novamente, na preparação / produção, para que ela tenha que persistir em ambientes e o fornecedor / diretório seja um artefato criado no momento da construção.
Mark Shust
@vitoriodachef Estou enfrentando o caso exato que você mencionou. Você encontrou alguma solução?
precisa saber é o seguinte
Eu usei a seguinte função para decidir a função privada isSerialized ($ value) {return (boolean) preg_match ('/ ^ ((s | i | d | b | a | O | C): | N;) /', $ value ); }
Knight017
Não funciona. Eu tive que alterar manualmente todas as entradas no banco de dados de a:0:{}para[]
localhost
16

No meu caso, fiz o patch da seguinte maneira para desserializar uma string serializada: File: /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;
}

substituir 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
fonte
Eu tentei isso, mas não está funcionando como esperado. Alguém já tentou isso e se conseguiu, por favor me ajude
Siva
Quais problemas você estava enfrentando?
MageLearner
O problema foi corrigido. Obrigado por perguntar!
Siva
1
Grt ... Obrigado !!!
MageLearner
1
Obrigado @MageLearner, Ele também está trabalhando no 2.3.1 depois de migrar os dados do magento 1 para o magento 2
Pradeep Thakur
5

Após liberar o Redis, o problema foi resolvido. Obrigado Craig pela solução.

Estou usando a porta 6379 para cache, então executo o comando:

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

É principalmente relacionado ao cache Redis, então tente liberar isso com um simples comando no seu SSH

redis-cli flushall

Tahir Iqbal Najam
fonte
3

Acabou sendo um problema de permissão, onde o magento estava definindo permissões para arquivos gerados que eram restritos neste servidor.

Resolvido criando o arquivo magento_umask no diretório raiz com o umask apropriado para o servidor.

Veja http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.html para detalhes adicionais.

Mandril
fonte
Olá, estou enfrentando o problema relacionado como este. Você pode, por favor, olhar para isso .
Aditya Shah
@chunk todos os meus diretórios são 755 e os arquivos são 644, qual é o umask apropriado para definir? tia
Kris Wen
2

A resposta de Sameers acima funcionou para mim, embora eu tivesse que usar código diferente no bloco.

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
fonte
1

Diretório ROOT 1. public_html/vendor/magento/framework/Serialize/Serializer/Json.php

Faça o download do JSON.php https://gist.github.com/manojind/9f18bbecaeb3e2bbfb056a634ade62a2

2. Apenas substitua a função abaixo (desserialize) e adicione uma nova função OU faça o download do arquivo anexado e substitua pelo padrão

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. Adicione uma nova função:

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
fonte
Meu problema não foi corrigido .. por favor me ajude
Muhammad Ahmed
1

Pessoalmente, encontrei esse problema criado, ele executava o comando:

php bin/magento setup:upgrade

Após uma migração. Eu descobri que estava faltando a chave de hash " cripta " em src/app/etc/env.php:

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

    ...

Verifique se isso não está vazio e, de preferência, corresponde aos outros ambientes de seus projetos!

Chris Rogers
fonte
Deixei a chave de criptografia vazia durante a instalação, esperando que uma nova fosse gerada, o que claramente não acontece.
Shapeshifter
0

Eu estava recebendo o erro em uma página do CMS no front-end.

Foi o código do widget Magento no conteúdo da página do CMS que estava causando o problema (que eu copiei de outra fonte). Excluí o código do widget e inseri o mesmo widget usando o botão Inserir widget na tela de edição da página do CMS e funcionou.

O processo acima formatou o código do widget de maneira diferente e cometeu o erro.

Binod
fonte
0

Eu descobri que dados serializados inteiros não podem ser ajustados em uma coluna da tabela MySQL do banco de TEXTdados com o tipo de dados.
Acabei de encontrar a colunaflag_data valor da da system_config_snapshotlinha é aparado.

Eu tive que mudar MEDIUMTEXTpara esta coluna flag.flag_data.

Kirby
fonte
0

Foi o mesmo erro. Quando tentou atualizar o banco de dados (versão 2.2.6) com um novo código (versão 2.3.2).

Para correção - executado

composer update
Alex
fonte
0

Esta não é a melhor maneira de executar o sql diretamente, mas fiz isso para economizar meu tempo. Basta executar 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
fonte
0

Se você estiver na versão 2.3.0 ou superior, desejará usar a solução fornecida pelo MageLearner. A maneira mais antiga com instruções de caso é obsoleta. Se você não usar a solução do MageLearner na 2.3.0 ou superior; você encontrará todos os tipos de problemas com a visualização de dados de pedidos e produtos configuráveis.

Andy
fonte