From 4a1920e2b69dbefba1bf8627e779208c367b7ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Tue, 13 May 2025 16:26:59 +0200 Subject: [PATCH 1/2] Hack to support Symfony 6 on PHP 8+ using attribute as comment marker --- composer.json | 3 +-- src/Ratchet/Session/Storage/Proxy/VirtualProxy.php | 6 ++++-- src/Ratchet/Session/Storage/VirtualSessionStorage.php | 7 +++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index fce58942..d9ce25fe 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,6 @@ , "symfony/routing": "^2.6|^3.0|^4.0|^5.0|^6.0" } , "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "symfony/http-foundation": "^2.6|^3.0|^4.0|^5.0" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" } } diff --git a/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php b/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php index b478d039..fcc88c68 100644 --- a/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php +++ b/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php @@ -26,7 +26,8 @@ public function __construct(\SessionHandlerInterface $handler) { /** * {@inheritdoc} */ - public function getId() { + #[HackSupportForSymfony6] public function getId(): string { /* + public function getId() { /**/ return $this->_sessionId; } @@ -40,7 +41,8 @@ public function setId($id) { /** * {@inheritdoc} */ - public function getName() { + #[HackSupportForSymfony6] public function getName(): string { /* + public function getName() { /**/ return $this->_sessionName; } diff --git a/src/Ratchet/Session/Storage/VirtualSessionStorage.php b/src/Ratchet/Session/Storage/VirtualSessionStorage.php index daa10bba..68c2bc27 100644 --- a/src/Ratchet/Session/Storage/VirtualSessionStorage.php +++ b/src/Ratchet/Session/Storage/VirtualSessionStorage.php @@ -25,7 +25,8 @@ public function __construct(\SessionHandlerInterface $handler, $sessionId, Handl /** * {@inheritdoc} */ - public function start() { + #[HackSupportForSymfony6] public function start(): bool { /* + public function start() { /**/ if ($this->started && !$this->closed) { return true; } @@ -51,8 +52,10 @@ public function start() { /** * {@inheritdoc} */ - public function regenerate($destroy = false, $lifetime = null) { + #[HackSupportForSymfony6] public function regenerate(bool $destroy = false, ?int $lifetime = null): bool { /* + public function regenerate($destroy = false, $lifetime = null) { /**/ // .. ? + return false; } /** From 1ef9c7f4a53be2811554d033e4bdd2ed9b5c35e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Thu, 15 May 2025 12:25:03 +0200 Subject: [PATCH 2/2] Use separate compatibility classes for Symfony 6 on PHP 8+ --- .../Session/Storage/Proxy/VirtualProxy.php | 14 ++- .../Storage/Proxy/VirtualProxyForSymfony6.php | 60 ++++++++++++ .../Session/Storage/VirtualSessionStorage.php | 14 ++- .../VirtualSessionStorageForSymfony6.php | 95 +++++++++++++++++++ 4 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php create mode 100644 src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php diff --git a/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php b/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php index fcc88c68..03c832e3 100644 --- a/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php +++ b/src/Ratchet/Session/Storage/Proxy/VirtualProxy.php @@ -2,6 +2,12 @@ namespace Ratchet\Session\Storage\Proxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; +if (PHP_VERSION_ID > 80000 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy','getId'))->hasReturnType()) { + // alias to class for Symfony 6 on PHP 8+ that uses native types like `getId(): string` + class_alias(__NAMESPACE__ . '\\VirtualProxyForSymfony6', __NAMESPACE__ . '\\VirtualProxy'); +} else { + // fall back to class without native types + class VirtualProxy extends SessionHandlerProxy { /** * @var string @@ -26,8 +32,7 @@ public function __construct(\SessionHandlerInterface $handler) { /** * {@inheritdoc} */ - #[HackSupportForSymfony6] public function getId(): string { /* - public function getId() { /**/ + public function getId() { return $this->_sessionId; } @@ -41,8 +46,7 @@ public function setId($id) { /** * {@inheritdoc} */ - #[HackSupportForSymfony6] public function getName(): string { /* - public function getName() { /**/ + public function getName() { return $this->_sessionName; } @@ -54,3 +58,5 @@ public function setName($name) { throw new \RuntimeException("Can not change session name in VirtualProxy"); } } + +} diff --git a/src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php b/src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php new file mode 100644 index 00000000..c72fd738 --- /dev/null +++ b/src/Ratchet/Session/Storage/Proxy/VirtualProxyForSymfony6.php @@ -0,0 +1,60 @@ +saveHandlerName = 'user'; + $this->_sessionName = ini_get('session.name'); + } + + /** + * {@inheritdoc} + */ + public function getId(): string { + return $this->_sessionId; + } + + /** + * {@inheritdoc} + */ + public function setId($id) { + $this->_sessionId = $id; + } + + /** + * {@inheritdoc} + */ + public function getName(): string { + return $this->_sessionName; + } + + /** + * DO NOT CALL THIS METHOD + * @internal + */ + public function setName($name) { + throw new \RuntimeException("Can not change session name in VirtualProxy"); + } +} diff --git a/src/Ratchet/Session/Storage/VirtualSessionStorage.php b/src/Ratchet/Session/Storage/VirtualSessionStorage.php index 68c2bc27..c56c5f87 100644 --- a/src/Ratchet/Session/Storage/VirtualSessionStorage.php +++ b/src/Ratchet/Session/Storage/VirtualSessionStorage.php @@ -4,6 +4,12 @@ use Ratchet\Session\Storage\Proxy\VirtualProxy; use Ratchet\Session\Serialize\HandlerInterface; +if (PHP_VERSION_ID > 80000 && (new \ReflectionMethod('Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage','start'))->hasReturnType()) { + // alias to class for Symfony 6 on PHP 8+ that uses native types like `start(): bool` + class_alias(__NAMESPACE__ . '\\VirtualSessionStorageForSymfony6', __NAMESPACE__ . '\\VirtualSessionStorage'); +} else { + // fall back to class without native types + class VirtualSessionStorage extends NativeSessionStorage { /** * @var \Ratchet\Session\Serialize\HandlerInterface @@ -25,8 +31,7 @@ public function __construct(\SessionHandlerInterface $handler, $sessionId, Handl /** * {@inheritdoc} */ - #[HackSupportForSymfony6] public function start(): bool { /* - public function start() { /**/ + public function start() { if ($this->started && !$this->closed) { return true; } @@ -52,8 +57,7 @@ public function start() { /**/ /** * {@inheritdoc} */ - #[HackSupportForSymfony6] public function regenerate(bool $destroy = false, ?int $lifetime = null): bool { /* - public function regenerate($destroy = false, $lifetime = null) { /**/ + public function regenerate($destroy = false, $lifetime = null) { // .. ? return false; } @@ -89,3 +93,5 @@ public function setSaveHandler($saveHandler = null) { $this->saveHandler = $saveHandler; } } + +} diff --git a/src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php b/src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php new file mode 100644 index 00000000..84f0e3eb --- /dev/null +++ b/src/Ratchet/Session/Storage/VirtualSessionStorageForSymfony6.php @@ -0,0 +1,95 @@ +setSaveHandler($handler); + $this->saveHandler->setId($sessionId); + $this->_serializer = $serializer; + $this->setMetadataBag(null); + } + + /** + * {@inheritdoc} + */ + public function start(): bool { + if ($this->started && !$this->closed) { + return true; + } + + // You have to call Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler::open() to use + // pdo_sqlite (and possible pdo_*) as session storage, if you are using a DSN string instead of a \PDO object + // in the constructor. The method arguments are filled with the values, which are also used by the symfony + // framework in this case. This must not be the best choice, but it works. + $this->saveHandler->open(session_save_path(), session_name()); + + $rawData = $this->saveHandler->read($this->saveHandler->getId()); + $sessionData = $this->_serializer->unserialize($rawData); + + $this->loadSession($sessionData); + + if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function regenerate(bool $destroy = false, ?int $lifetime = null): bool { + // .. ? + return false; + } + + /** + * {@inheritdoc} + */ + public function save() { + // get the data from the bags? + // serialize the data + // save the data using the saveHandler +// $this->saveHandler->write($this->saveHandler->getId(), + + if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { + $this->saveHandler->setActive(false); + } + + $this->closed = true; + } + + /** + * {@inheritdoc} + */ + public function setSaveHandler($saveHandler = null) { + if (!($saveHandler instanceof \SessionHandlerInterface)) { + throw new \InvalidArgumentException('Handler must be instance of SessionHandlerInterface'); + } + + if (!($saveHandler instanceof VirtualProxy)) { + $saveHandler = new VirtualProxy($saveHandler); + } + + $this->saveHandler = $saveHandler; + } +}