Skip to content

Commit 063d271

Browse files
Merge branch '5.4' into 6.0
* 5.4: (21 commits) [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 [Console] fix restoring stty mode on CTRL+C fix merge (bis) fix merge [Process] Avoid calling fclose on an already closed resource [GHA] test tty group [DI] Fix tests on PHP 7.1 ...
2 parents 2c05809 + eaa0b1a commit 063d271

File tree

2 files changed

+192
-5
lines changed

2 files changed

+192
-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: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
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\PhpBridgeSessionStorage;
2526
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
2627
use Symfony\Component\HttpKernel\Event\RequestEvent;
2728
use Symfony\Component\HttpKernel\Event\ResponseEvent;
@@ -124,6 +125,189 @@ public function provideSessionOptions(): \Generator
124125
];
125126
}
126127

128+
/**
129+
* @runInSeparateProcess
130+
*/
131+
public function testPhpBridgeAlreadyStartedSession()
132+
{
133+
session_start();
134+
$sessionId = session_id();
135+
136+
$requestStack = new RequestStack();
137+
$request = new Request();
138+
$requestStack->push($request);
139+
140+
$session = new Session();
141+
$sessionStorage = new PhpBridgeSessionStorage();
142+
143+
$container = new Container();
144+
$container->set('request_stack', $requestStack);
145+
$container->set('session', $session);
146+
$container->set('session_storage', $sessionStorage);
147+
148+
$request = new Request();
149+
$listener = new SessionListener($container);
150+
151+
$event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST);
152+
153+
$listener->onKernelRequest($event);
154+
155+
$this->assertTrue($request->hasSession());
156+
$this->assertSame($sessionId, $request->getSession()->getId());
157+
}
158+
159+
/**
160+
* @runInSeparateProcess
161+
*/
162+
public function testSessionCookieWrittenNoCookieGiven()
163+
{
164+
$session = new Session();
165+
$session->set('hello', 'world');
166+
167+
$container = new Container();
168+
$container->set('initialized_session', $session);
169+
170+
$listener = new SessionListener($container);
171+
$kernel = $this->createMock(HttpKernelInterface::class);
172+
173+
$request = new Request();
174+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
175+
176+
$response = new Response();
177+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
178+
179+
$cookies = $response->headers->getCookies();
180+
$this->assertCount(1, $cookies);
181+
$sessionCookie = $cookies[0];
182+
183+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
184+
$this->assertNotEmpty($sessionCookie->getValue());
185+
$this->assertFalse($sessionCookie->isCleared());
186+
}
187+
188+
/**
189+
* @runInSeparateProcess
190+
*/
191+
public function testSessionCookieNotWrittenCookieGiven()
192+
{
193+
$session = new Session();
194+
$session->set('hello', 'world');
195+
$sessionId = $session->getId();
196+
197+
$container = new Container();
198+
$container->set('initialized_session', $session);
199+
200+
$listener = new SessionListener($container);
201+
$kernel = $this->createMock(HttpKernelInterface::class);
202+
203+
$request = new Request();
204+
$request->cookies->set('PHPSESSID', $sessionId);
205+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
206+
207+
$response = new Response();
208+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
209+
210+
$cookies = $response->headers->getCookies();
211+
$this->assertCount(0, $cookies);
212+
}
213+
214+
/**
215+
* @runInSeparateProcess
216+
*/
217+
public function testSessionCookieClearedWhenInvalidated()
218+
{
219+
$session = new Session();
220+
221+
$container = new Container();
222+
$container->set('initialized_session', $session);
223+
224+
$listener = new SessionListener($container);
225+
$kernel = $this->createMock(HttpKernelInterface::class);
226+
227+
$request = new Request();
228+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
229+
230+
$session->start();
231+
$sessionId = $session->getId();
232+
$this->assertNotEmpty($sessionId);
233+
$request->cookies->set($session->getName(), $sessionId);
234+
$_SESSION['hello'] = 'world'; // check compatibility to php session bridge
235+
236+
$session->invalidate();
237+
238+
$response = new Response();
239+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
240+
241+
$cookies = $response->headers->getCookies();
242+
$this->assertCount(1, $cookies);
243+
$sessionCookie = $cookies[0];
244+
245+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
246+
$this->assertTrue($sessionCookie->isCleared());
247+
}
248+
249+
/**
250+
* @runInSeparateProcess
251+
*/
252+
public function testSessionCookieNotClearedWhenOtherVariablesSet()
253+
{
254+
$session = new Session();
255+
256+
$container = new Container();
257+
$container->set('initialized_session', $session);
258+
259+
$listener = new SessionListener($container);
260+
$kernel = $this->createMock(HttpKernelInterface::class);
261+
262+
$request = new Request();
263+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
264+
265+
$session->start();
266+
$sessionId = $session->getId();
267+
$this->assertNotEmpty($sessionId);
268+
$request->cookies->set($session->getName(), $sessionId);
269+
$_SESSION['hello'] = 'world';
270+
271+
$response = new Response();
272+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
273+
274+
$cookies = $response->headers->getCookies();
275+
$this->assertCount(0, $cookies);
276+
}
277+
278+
/**
279+
* @runInSeparateProcess
280+
*/
281+
public function testSessionCookieSetWhenOtherNativeVariablesSet()
282+
{
283+
$session = new Session();
284+
285+
$container = new Container();
286+
$container->set('initialized_session', $session);
287+
288+
$listener = new SessionListener($container);
289+
$kernel = $this->createMock(HttpKernelInterface::class);
290+
291+
$request = new Request();
292+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
293+
294+
$session->start();
295+
$sessionId = $session->getId();
296+
$this->assertNotEmpty($sessionId);
297+
$_SESSION['hello'] = 'world';
298+
299+
$response = new Response();
300+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));
301+
302+
$cookies = $response->headers->getCookies();
303+
$this->assertCount(1, $cookies);
304+
$sessionCookie = $cookies[0];
305+
306+
$this->assertSame('PHPSESSID', $sessionCookie->getName());
307+
$this->assertNotEmpty($sessionCookie->getValue());
308+
$this->assertFalse($sessionCookie->isCleared());
309+
}
310+
127311
public function testOnlyTriggeredOnMainRequest()
128312
{
129313
$listener = $this->getMockForAbstractClass(AbstractSessionListener::class);

0 commit comments

Comments
 (0)