株式会社NextCodeのロゴ株式会社NextCode

BLOG

ブログ

2022/01/21

ECCUBE3.0.15 PHP7.3でunserializeのエラー

とある案件にてECCUBE3.0.15が入っているサーバーのPHPを7.3以上にバージョンアップしました。

そして、ログインの際にunserializeでエラーが発生しましたので、それについての備忘録です。

ECCUBE3系はPHP7.1より上のバージョンは対応していなかったり、そもそもサポート対象外という話は置いときます……

エラーについて

エラーの内容は次の様な物でした。

ContextErrorException in AbstractToken.php line 164:
Notice: unserialize(): Error at offset 1555 of 4227 bytes

一見、unserializeで何かしらの不具合があったと思っていたのですが、詳しく色々調べていくと….

PHP7.3で発生しているserializeのバグ?の様でした。

serializeが正常に出来ていない為、unserializeで正常に元に戻せない様ですね。

(実は原因はハッキリと分かっていません。対策はできたので、詳しい原因はほっといてます)

対策について

対策方法は単純明快でシリアライズを使わない様にしました。

良くない方法だとは思いますが、次のファイルを直接編集し修正しました。

  • vendor/symfony/security/Core/Authentication/Token/AbstractToken.php
  • vendor/symfony/security/Core/Authentication/Token/UsernamePasswordToken.php

変更内容

  • vendor/symfony/security/Core/Authentication/Token/AbstractToken.php
  • 次の内容の部分を削除

    /**
     * {@inheritdoc}
     */
    public function serialize()
    {
        return serialize(
            array(
                is_object($this->user) ? clone $this->user : $this->user,
                $this->authenticated,
                array_map(function ($role) { return clone $role; }, $this->roles),
                $this->attributes,
            )
        );
    }
    
    /**
     * {@inheritdoc}
     */
    public function unserialize($serialized)
    {
        list($this->user, $this->authenticated, $this->roles, $this->attributes) = unserialize($serialized);
    }
    
    

      ↓

    次の内容を削除した部分に追加

    public function __serialize(): array
    {
        return [$this->user, $this->authenticated, $this->roles, $this->attributes];
    }
    
    /**
     * {@inheritdoc}
     */
    public function serialize()
    {
        $serialized = $this->__serialize();
    
        if (null === $isCalledFromOverridingMethod = \func_num_args() ? func_get_arg(0) : null) {
            $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
            $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object'];
        }
    
        return $isCalledFromOverridingMethod ? $serialized : serialize($serialized);
    }
    
    public function __unserialize(array $data): void
    {
        [$this->user, $this->authenticated, $this->roles, $this->attributes] = $data;
    }
    
    /**
     * {@inheritdoc}
     */
    public function unserialize($serialized)
    {
        $this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized));
    }
    
    

  • vendor/symfony/security/Core/Authentication/Token/UsernamePasswordToken.php
  • 次の内容の部分を削除

    /**
     * {@inheritdoc}
     */
    public function serialize()
    {
        return serialize(array($this->credentials, $this->providerKey, parent::serialize()));
    }
    
    
    /**
     * {@inheritdoc}
     */
    public function unserialize($serialized)
    {
        list($this->credentials, $this->providerKey, $parentStr) = unserialize($serialized);
        parent::unserialize($parentStr);
    }
    

      ↓

    次の内容を削除した部分に追加

    /**
     * {@inheritdoc}
     */
    public function __serialize(): array
    {
        return [$this->credentials, $this->providerKey, parent::__serialize()];
    }
    
    /**
     * {@inheritdoc}
     */
    public function __unserialize(array $data): void
    {
        [$this->credentials, $this->providerKey, $parentData] = $data;
        $parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
        parent::__unserialize($parentData);
    }
    

    以上の変更を行う事で、ログインが問題なく行える様になります。

    PHP7.3でSymfony2.7〜2.8でも発生する可能性がありますので、その場合も上記の対応で直るかと思います。

    ※未検証

    参考サイト

    https://github.com/symfony/symfony/issues/29459

    https://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=22268&forum=11

    TOPへ移動
    PAGE
    TOP
    %d人のブロガーが「いいね」をつけました。