Skip to content

Commit 748f09d

Browse files
Merge branch '6.0' into 6.1
* 6.0: (27 commits) [DoctrineBridge] fix tests [HttpKernel] Fix session test cases for symfony [FrameworkBundle] Fix missing arguments when a serialization default context is bound [Runtime] Fix --env and --no-debug with dotenv_overload [Cache] fix merge cs fix [Finder] Fix finding VCS re-included files in excluded directory [Yaml] Improve the deprecation warnings for octal numbers to suggest migrating Fix Choice constraint with associative choices array [Form] UrlType should not add protocol to emails [Dotenv] Fix bootEnv() override with .env.local.php when the env key already exists Silence isatty warnings during tty detection [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false [Notifier] Fix encoding of messages with FreeMobileTransport [Cache] workaround PHP crash [Console] Fix PHP 8.1 deprecation in ChoiceQuestion [HttpKernel] Fix compatibility with php bridge and already started php sessions [Notifier] smsapi-notifier - correct encoding Replaced full CoC text with link to documentation Making the parser stateless ...
2 parents d0806e9 + 00303f5 commit 748f09d

File tree

2 files changed

+204
-5
lines changed

2 files changed

+204
-5
lines changed

EventListener/AbstractSessionListener.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ public function onKernelRequest(RequestEvent $event)
7373
}
7474

7575
/*
76-
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
77-
* cookie need read from the cookie bag and set on the session storage.
76+
* For supporting sessions in php runtime with runners like roadrunner or swoole, the session
77+
* cookie needs to be read from the cookie bag and set on the session storage.
78+
*
79+
* Do not set it when a native php session is active.
7880
*/
79-
if ($sess && !$sess->isStarted()) {
81+
if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) {
8082
$sessionId = $request->cookies->get($sess->getName(), '');
8183
$sess->setId($sessionId);
8284
}
@@ -147,7 +149,8 @@ public function onKernelResponse(ResponseEvent $event)
147149
$request = $event->getRequest();
148150
$requestSessionCookieId = $request->cookies->get($sessionName);
149151

150-
if ($requestSessionCookieId && ($session instanceof Session ? $session->isEmpty() : empty($session->all()))) {
152+
$isSessionEmpty = ($session instanceof Session ? $session->isEmpty() : empty($session->all())) && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
153+
if ($requestSessionCookieId && $isSessionEmpty) {
151154
$response->headers->clearCookie(
152155
$sessionName,
153156
$sessionCookiePath,
@@ -156,7 +159,7 @@ public function onKernelResponse(ResponseEvent $event)
156159
$sessionCookieHttpOnly,
157160
$sessionCookieSameSite
158161
);
159-
} elseif ($sessionId !== $requestSessionCookieId) {
162+
} elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) {
160163
$expire = 0;
161164
$lifetime = $sessionOptions['cookie_lifetime'] ?? null;
162165
if ($lifetime) {

Tests/EventListener/SessionListenerTest.php

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
use Symfony\Component\HttpFoundation\Session\Session;
2323
use Symfony\Component\HttpFoundation\Session\SessionFactory;
2424
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
25+
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorageFactory;
26+
use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorageFactory;
27+
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface;
2528
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
2629
use Symfony\Component\HttpKernel\Event\RequestEvent;
2730
use Symfony\Component\HttpKernel\Event\ResponseEvent;
@@ -124,6 +127,167 @@ public function provideSessionOptions(): \Generator
124127
];
125128
}
126129

130+
/**
131+
* @runInSeparateProcess
132+
*/
133+
public function testPhpBridgeAlreadyStartedSession()
134+
{
135+
session_start();
136+
$sessionId = session_id();
137+
138+
$request = new Request();
139+
$listener = $this->createListener($request, new PhpBridgeSessionStorageFactory());
140+
141+
$event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);
142+
143+
$listener->onKernelRequest($event);
144+
145+
$this->assertTrue($request->hasSession());
146+
$this->assertSame($sessionId, $request->getSession()->getId());
147+
}
148+
149+
/**
150+
* @runInSeparateProcess
151+
*/
152+
public function testSessionCookieWrittenNoCookieGiven()
153+
{
154+
$request = new Request();
155+
$listener = $this->createListener($request, new NativeSessionStorageFactory());
156+
157+
$kernel = $this->createMock(HttpKernelInterface::class);
158+
159+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
160+
$session = $request->getSession();
161+
$session->set('hello', 'world');
162+
163+
$response = new Response();
164+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
165+
166+
$cookies = $response->headers->getCookies();
167+
$this->assertCount(1, $cookies);
168+
$sessionCookie = $cookies[0];
169+
170+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
171+
$this->assertNotEmpty($sessionCookie->getValue());
172+
$this->assertFalse($sessionCookie->isCleared());
173+
}
174+
175+
/**
176+
* @runInSeparateProcess
177+
*/
178+
public function testSessionCookieNotWrittenCookieGiven()
179+
{
180+
$sessionId = $this->createValidSessionId();
181+
182+
$this->assertNotEmpty($sessionId);
183+
184+
$request = new Request();
185+
$request->cookies->set('PHPSESSID', $sessionId);
186+
187+
$listener = $this->createListener($request, new NativeSessionStorageFactory());
188+
189+
$kernel = $this->createMock(HttpKernelInterface::class);
190+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
191+
192+
$session = $request->getSession();
193+
$this->assertSame($sessionId, $session->getId());
194+
$session->set('hello', 'world');
195+
196+
$response = new Response();
197+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
198+
$this->assertSame($sessionId, $session->getId());
199+
200+
$cookies = $response->headers->getCookies();
201+
$this->assertCount(0, $cookies);
202+
}
203+
204+
/**
205+
* @runInSeparateProcess
206+
*/
207+
public function testSessionCookieClearedWhenInvalidated()
208+
{
209+
$sessionId = $this->createValidSessionId();
210+
$request = new Request();
211+
$request->cookies->set('PHPSESSID', $sessionId);
212+
$listener = $this->createListener($request, new NativeSessionStorageFactory());
213+
$kernel = $this->createMock(HttpKernelInterface::class);
214+
215+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
216+
217+
$session = $request->getSession();
218+
$session->start();
219+
$sessionId = $session->getId();
220+
$this->assertNotEmpty($sessionId);
221+
$_SESSION['hello'] = 'world'; // check compatibility to php session bridge
222+
223+
$session->invalidate();
224+
225+
$response = new Response();
226+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
227+
228+
$cookies = $response->headers->getCookies();
229+
$this->assertCount(1, $cookies);
230+
$sessionCookie = $cookies[0];
231+
232+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
233+
$this->assertTrue($sessionCookie->isCleared());
234+
}
235+
236+
/**
237+
* @runInSeparateProcess
238+
*/
239+
public function testSessionCookieNotClearedWhenOtherVariablesSet()
240+
{
241+
$sessionId = $this->createValidSessionId();
242+
$request = new Request();
243+
$request->cookies->set('PHPSESSID', $sessionId);
244+
$listener = $this->createListener($request, new NativeSessionStorageFactory());
245+
$kernel = $this->createMock(HttpKernelInterface::class);
246+
247+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
248+
249+
$session = $request->getSession();
250+
$session->start();
251+
$sessionId = $session->getId();
252+
$this->assertNotEmpty($sessionId);
253+
$_SESSION['hello'] = 'world';
254+
255+
$response = new Response();
256+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
257+
258+
$cookies = $response->headers->getCookies();
259+
$this->assertCount(0, $cookies);
260+
}
261+
262+
/**
263+
* @runInSeparateProcess
264+
*/
265+
public function testSessionCookieSetWhenOtherNativeVariablesSet()
266+
{
267+
$request = new Request();
268+
$listener = $this->createListener($request, new NativeSessionStorageFactory());
269+
$kernel = $this->createMock(HttpKernelInterface::class);
270+
271+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
272+
273+
$session = $request->getSession();
274+
$session->start();
275+
$sessionId = $session->getId();
276+
$this->assertNotEmpty($sessionId);
277+
$_SESSION['hello'] = 'world';
278+
279+
$response = new Response();
280+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
281+
282+
$cookies = $response->headers->getCookies();
283+
$this->assertCount(1, $cookies);
284+
$sessionCookie = $cookies[0];
285+
286+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
287+
$this->assertNotEmpty($sessionCookie->getValue());
288+
$this->assertFalse($sessionCookie->isCleared());
289+
}
290+
127291
public function testOnlyTriggeredOnMainRequest()
128292
{
129293
$listener = $this->getMockForAbstractClass(AbstractSessionListener::class);
@@ -599,4 +763,36 @@ public function testResetUnclosedSession()
599763
$this->assertEmpty(session_id());
600764
$this->assertSame(\PHP_SESSION_NONE, session_status());
601765
}
766+
767+
private function createListener(Request $request, SessionStorageFactoryInterface $sessionFactory)
768+
{
769+
$requestStack = new RequestStack();
770+
$request = new Request();
771+
$requestStack->push($request);
772+
773+
$sessionFactory = new SessionFactory(
774+
$requestStack,
775+
$sessionFactory,
776+
);
777+
778+
$container = new Container();
779+
$container->set('request_stack', $requestStack);
780+
$container->set('session_factory', $sessionFactory);
781+
782+
$listener = new SessionListener($container);
783+
784+
return new SessionListener($container);
785+
}
786+
787+
private function createValidSessionId(): string
788+
{
789+
session_start();
790+
$sessionId = session_id();
791+
$_SESSION['some'] = 'value';
792+
session_write_close();
793+
$_SESSION = [];
794+
session_abort();
795+
796+
return $sessionId;
797+
}
602798
}

0 commit comments

Comments
 (0)