Magento 2.2:无法反序列化值?


33

在运行Magento 2.2.0-rc3.0 / PHP 7.0.23的网站上遇到问题

启用或禁用所有第3方扩展时,都会发生以下问题。

从类别或产品页面向比较中添加项目或从产品页面提交评论时,在浏览器中出现以下错误:

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}

除非您清除cookie,尤其是法师消息cookie,否则错误不会消失。 在此处输入图片说明

感谢您提供协助解决这些错误。


这不是核心错误吗?对此有GitHub问题吗?
Alex

这会给你一个想法scommerce-mage.com/blog/...
stevensagaar

Answers:


59

我可以通过从CLI刷新我的Redis缓存来解决此问题

redis-cli flushall

希望这对将来的用户有所帮助。


2
做得很好。这可能应该是公认的答案。
肖恩·艾布拉姆森

似乎并不总是解决方案。就我而言,我什至没有使用redis(还)
Alex

谢谢。我重新启动清漆,以为会冲洗它,但这确实成功了。
ladle3000


从2.2.9升级到2.3.2时,这对我有帮助。执行php bin / magento setup:upgrade
Mohammed Joraid

30

问题出在/vendor/magento/framework/Serialize/Serializer/Json.php中,有一个函数unserialize($ string),如果字符串已序列化(不是json,而是php序列化),则会给您语法错误。

有一种解决方法-您可以检查string是否已序列化(与json编码),然后使用serialize($ string)。将反序列化更改为:

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

保存后。类别没有问题,您可以将类别还原为默认值,以后也不会出现此类问题。


1
它的工作对我来说100%罚款。非常感谢!
mapaladiya

2
它不起作用... :-(
Arfan Mirza

检查如果传递值a:0:{}会发生什么。逐行走。如果将反序列化的结果传递给需要数组的强类型方法,会发生什么情况?您可能需要更改答案。
vitoriodachef '18年

20

不要编辑核心文件以获取解决方案。覆盖跟随方式只需将以下行放在etc目录中的di.xml中

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

在Namespace \ ModuleName \ Serialize \ Serializer目录中:文件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;
    }
}

完美运作


2
实现有缺陷。如果将值a:0:{}传递给Json:unserialize方法会怎样?这是期望的行为吗?is_serialized方法中结果变量的意义是什么?它不会返回,也不会影响任何内容,因为在方法调用时,不会将任何变量作为第二个参数传递。
vitoriodachef '18年

这应该是公认的解决方案,并且比上面的文章直接在供应商中编辑文件要好得多。您很有可能必须在本地运行安装程序升级任务,然后在登台/生产环境中再次运行,因此它必须保留环境,并且vendor /目录是在构建时创建的工件。
马克·舒斯特

@vitoriodachef我正在面对您提到的确切案例。您找到任何解决方案了吗?
Knight017 '18

我已经使用以下函数来确定私有函数isSerialized($ value){return(boolean)preg_match('/ ^((s | i | d | b | a | O | C):| N;)/',$ value ); }
Knight017 '18

没用。我必须手动将数据库中的所有条目从更改a:0:{}[]
本地主机

16

就我而言,我进行了如下修补,以对序列化的字符串进行反序列化:File:/vendor/magento/framework/Serialize/Serializer/Json.php

找:

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

替换为:

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

该问题已解决。感谢您的询问!
西瓦

1
嗯...谢谢!!!
MageLearner

1
感谢@MageLearner,在将数据从magento 1迁移到magento 2之后,它也可以在2.3.1中工作
Pradeep Thakur

5

刷新Redis后,问题已解决。谢谢Craig提供的解决方案。

我将端口6379用于缓存,因此我运行command:

redis-cli -p 6379 flushall


3

原来是一个权限问题,其中magento设置了对此服务器上受限制的生成文件的权限。

通过在根目录中创建magento_umask文件并使用适合服务器的umask来解决。

有关其他详细信息,请参见http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.html


您好,我正面临与此相关的问题。你能看看这个吗?
Aditya Shah)

@chunk我的所有目录都是755,文件是644,要设置的适当umask是什么?tia
Kris Wen

2

尽管我不得不在块中使用不同的代码,但Sameers的上述回答对我有用。

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

根目录1。 public_html/vendor/magento/framework/Serialize/Serializer/Json.php

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

2.只需替换下面的函数(反序列化)并添加新函数,或仅下载附件并替换为默认值

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.添加新功能:

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

我的问题未解决..请帮助我
穆罕默德·艾哈迈德

1

我个人发现此问题使它开始运行以下命令:

php bin/magento setup:upgrade

迁移后。我发现我在以下位置缺少“ crypt ”哈希键src/app/etc/env.php

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

    ...

确保它不为空,并且最好与您项目的其他环境匹配!


我在安装过程中将加密密钥留空,希望生成一个新密钥,但显然不会发生。
Shapeshifter

0

我在前端的CMS页面中收到错误。

导致问题的原因是CMS页面内容中的Magento小部件代码(我从其他来源复制了此代码)。我删除了窗口小部件代码,并使用CMS页面编辑屏幕中的“插入窗口小部件”按钮插入了相同的窗口小部件,它可以正常工作。

上面的过程对小部件代码的格式进行了不同的设置,从而使错误消失了。


0

我发现整个序列化数据无法放入具有TEXT数据类型的数据库MySQL表列中。
我刚刚发现行的列flag_datasystem_config_snapshot被修剪。

MEDIUMTEXT在本专栏中,我不得不将其更改为flag.flag_data


0

是同样的错误。尝试使用新代码(版本2.3.2)更新数据库(版本2.2.6)时。

修复-已运行

composer update

0

这不是直接运行sql的最佳方法,但我这样做是为了节省时间。只需运行此查询

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

如果您使用的是2.3.0或更高版本,则需要使用MageLearner提供的解决方案。用case语句的旧方法已经过时了。如果您未在2.3.0或更高版本上使用MageLearner的解决方案;您将在查看订单数据和可配置产品时遇到各种问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.