Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f5a49e5

Browse filesBrowse files
Fix session cookie handling in cli context
1 parent 38cb35a commit f5a49e5
Copy full SHA for f5a49e5

File tree

4 files changed

+84
-3
lines changed
Filter options

4 files changed

+84
-3
lines changed

‎src/Symfony/Component/HttpFoundation/Request.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Request.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,14 @@ public function getSession()
719719
{
720720
$session = $this->session;
721721
if (!$session instanceof SessionInterface && null !== $session) {
722+
/** @var SessionInterface $session */
722723
$this->setSession($session = $session());
724+
/*
725+
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
726+
* cookie need read from the cookie bag and set on the session storage.
727+
*/
728+
$sessionId = $this->cookies->get($session->getName(), '');
729+
$session->setId($sessionId);
723730
}
724731

725732
if (null === $session) {

‎src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
+46-1Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
use Psr\Container\ContainerInterface;
1515
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpFoundation\Cookie;
1617
use Symfony\Component\HttpFoundation\Session\Session;
1718
use Symfony\Component\HttpFoundation\Session\SessionInterface;
19+
use Symfony\Component\HttpFoundation\Session\SessionUtils;
1820
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
1921
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
2022
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -42,9 +44,19 @@ abstract class AbstractSessionListener implements EventSubscriberInterface
4244
protected $container;
4345
private $sessionUsageStack = [];
4446

45-
public function __construct(ContainerInterface $container = null)
47+
/**
48+
* @var array<string, mixed>
49+
*/
50+
private $sessionOptions;
51+
52+
/**
53+
* @param array<string, mixed> $sessionOptions
54+
*/
55+
public function __construct(ContainerInterface $container = null, bool $debug = false, array $sessionOptions = [])
4656
{
4757
$this->container = $container;
58+
$this->debug = $debug;
59+
$this->sessionOptions = $sessionOptions;
4860
}
4961

5062
public function onKernelRequest(GetResponseEvent $event)
@@ -115,6 +127,39 @@ public function onKernelResponse(FilterResponseEvent $event)
115127
* it is saved will just restart it.
116128
*/
117129
$session->save();
130+
131+
/*
132+
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
133+
* cookie need to be written on the response object and should not be written by PHP itself.
134+
*/
135+
$sessionName = $session->getName();
136+
$sessionId = $session->getId();
137+
$sessionCookiePath = $this->sessionOptions['cookie_path'] ?? '/';
138+
$popSessionCookie = SessionUtils::popSessionCookie($sessionName, $sessionId);
139+
140+
if (0 === \strpos($popSessionCookie, \sprintf('Set-Cookie: %s=deleted;', $sessionName))) {
141+
$response->headers->removeCookie($sessionName, $sessionCookiePath);
142+
} else {
143+
$expire = 0;
144+
$lifetime = $this->sessionOptions['cookie_lifetime'] ?? null;
145+
if ($lifetime) {
146+
$expire = time() + $lifetime;
147+
}
148+
149+
$response->headers->setCookie(
150+
Cookie::create(
151+
$session->getName(),
152+
$session->getId(),
153+
$expire,
154+
$sessionCookiePath,
155+
$this->sessionOptions['cookie_domain'] ?? null,
156+
$this->sessionOptions['cookie_secure'] ?? null,
157+
$this->sessionOptions['cookie_httponly'] ?? true,
158+
false,
159+
$this->sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX
160+
)
161+
);
162+
}
118163
}
119164
}
120165

‎src/Symfony/Component/HttpKernel/EventListener/SessionListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/EventListener/SessionListener.php
+5-2Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@
2929
*/
3030
class SessionListener extends AbstractSessionListener
3131
{
32-
public function __construct(ContainerInterface $container)
32+
/**
33+
* @param array<string, mixed> $sessionOptions
34+
*/
35+
public function __construct(ContainerInterface $container, bool $debug = false, array $sessionOptions = [])
3336
{
34-
$this->container = $container;
37+
parent::__construct($container, $debug, $sessionOptions);
3538
}
3639

3740
public function onKernelRequest(GetResponseEvent $event)

‎src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,32 @@ public function testResponseIsStillPublicIfSessionStartedAndHeaderPresent()
120120
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
121121
}
122122

123+
public function testSessionSaveAndResponseHasSessionCookie()
124+
{
125+
$session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
126+
$session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1));
127+
$session->expects($this->exactly(1))->method('getId')->willReturn('123456');
128+
$session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
129+
$session->expects($this->exactly(1))->method('save');
130+
$session->expects($this->exactly(1))->method('isStarted')->willReturn(true);
131+
132+
$container = new Container();
133+
$container->set('initialized_session', $session);
134+
135+
$listener = new SessionListener($container);
136+
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
137+
138+
$request = new Request();
139+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST));
140+
141+
$response = new Response();
142+
$listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response));
143+
144+
$cookies = $response->headers->getCookies();
145+
$this->assertSame('PHPSESSID', $cookies[0]->getName());
146+
$this->assertSame('123456', $cookies[0]->getValue());
147+
}
148+
123149
public function testUninitializedSession()
124150
{
125151
$kernel = $this->createMock(HttpKernelInterface::class);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.