Magento 2.2:値をシリアル化解除できませんか?


33

Magento 2.2.0-rc3.0 / PHP 7.0.23を実行しているサイトで問題が発生する

次の問題は、すべてのサードパーティの拡張機能を有効または無効にすると発生します。

カテゴリまたは製品ページからの比較にアイテムを追加するか、製品ページからレビューを送信すると、ブラウザーに次のエラーが表示されます。

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、特にmage-messages cookieをクリアしない限り、エラーは消えません。 ここに画像の説明を入力してください

これらのエラーのトラブルシューティングにご協力ください。


それはコアバグではありませんか?これにGitHubの問題はありますか?
アレックス

これはあなたのアイデアを与えるだろうscommerce-mage.com/blog/...
stevensagaar

回答:


59

CLIからRedisキャッシュをフラッシュすることで、この問題を解決できました

redis-cli flushall

これが将来のユーザーに役立つことを願っています。


2
よくできました。これはおそらく受け入れられた答えでしょう。
ショーンエイブラムソン

常に解決策ではないようです。私の場合、私はredisを使用していません(まだ)
アレックス

ありがとう。ワニスを再起動して、それが洗い流されると考えましたが、これでうまくいきました。
ladle3000

それは私の作品
ジャレドチュー

これは、2.2.9から2.3.2にアップグレードする際に役立ちました。php bin / magento setup:upgrade;
モハメッドジョレイド

30

問題は/vendor/magento/framework/Serialize/Serializer/Json.phpにあり、stringがシリアル化された場合(jsonではなくphpシリアル化)に構文エラーを与える関数unserialize($ string)があります。

回避策があります-stringがシリアル化されている(jsonエンコードされている)かどうかを確認し、serialize($ string)を使用できます。unserializeを次のように変更します。

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

feを保存した後。カテゴリは問題なく、クラスをデフォルトに戻すことができ、将来このような問題は発生しません。


1
それは私にとっては100%うまく動作します。どうもありがとう!
mapaladiya

2
それは機能していません... :
アルファンミルザ

値a:0:{}が渡された場合の動作を確認してください。行ごとに移動します。unserializeの結果が配列を期待している強い型付けされたメソッドに渡されるとどうなりますか?答えを変えたいかもしれません。
vitoriodachef

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メソッドの結果変数のポイントは何ですか?これは返されず、メソッド呼び出しでは変数が2番目の引数として渡されないため、何にも影響しません。
vitoriodachef

これは受け入れられる解決策であるはずであり、ベンダーで直接ファイルを編集するには上記の投稿よりもはるかに優れています。おそらく、セットアップアップグレードタスクをローカルで実行し、その後ステージング/運用環境で再度実行する必要があるため、環境を維持する必要があり、vendor /ディレクトリはビルド時に作成されるアーティファクトです。
マークシャスト

@vitoriodachefあなたが言った正確なケースに直面しています。解決策を見つけましたか?
Knight017

私は次の関数を使用してプライベート
Knight017

動作しませんでした。私は手動でからDB内のすべてのエントリを変更しなければならなかったa:0:{}[]
localhostの

16

私の場合、次のようにパッチを適用して、シリアル化された文字列を非シリアル化します。ファイル:/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
Grt ...ありがとう!!!
MageLearner

1
@MageLearnerに感謝します。また、データをmagento 1からmagento 2に移行した後、2.3.1で動作します
Pradeep Thakur

5

Redisをフラッシュした後、問題はソートされました。解決策を提供してくれたCraigに感謝します。

キャッシュにポート6379を使用しているので、コマンドを実行します:

redis-cli -p 6379 flushall

4

これは主にRedisキャッシュに関連しているため、SSHで簡単なコマンドを使用してこれをフラッシュしてみてください。

redis-cli flushall


3

これはパーミッションの問題であることが判明しました。この場合、magentoは、このサーバーで制限された生成ファイルのパーミッションを設定していました。

サーバーの適切なumaskを使用してルートディレクトリにmagento_umaskファイルを作成することで解決しました。

詳細については、http://devdocs.magento.com/guides/v2.2/install-gde/install/post-install-umask.htmlを参照してください。


こんにちは、私はこのような関連する問題に直面しています。これを見てください。
アーディティヤシャー

@chunk私のディレクトリはすべて755で、ファイルは644です、設定する適切なumaskは何ですか?tia
クリスウェン

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

ROOTディレクトリ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

同じエラーでした。データベース(ver 2.2.6)を新しいコード(ver 2.3.2)で更新しようとしたとき。

修正用-実行済み

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のソリューションを使用しない場合。注文データと設定可能な製品の表示に関するあらゆる種類の問題に遭遇します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.