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
変更内容
次の内容の部分を削除
/**
* {@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));
}
次の内容の部分を削除
/**
* {@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