Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Sign up
Appearance settings

Commitb3e4f66

Browse files
alexander-schranzfabpot
authored andcommitted
[HttpKernel] Add session cookie handling in cli context
1 parentf638ea5 commitb3e4f66

File tree

10 files changed

+179
-13
lines changed

10 files changed

+179
-13
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ public function load(array $configs, ContainerBuilder $container)
325325
$this->sessionConfigEnabled =true;
326326
$this->registerSessionConfiguration($config['session'],$container,$loader);
327327
if (!empty($config['test'])) {
328-
$container->getDefinition('test.session.listener')->setArgument(1,'%session.storage.options%');
328+
$container->getDefinition('test.session.listener')->setArgument(2,'%session.storage.options%');
329329
}
330330
}
331331

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/session.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,10 @@
153153
'session_collector' =>service('data_collector.request.session_collector')->ignoreOnInvalid(),
154154
]),
155155
param('kernel.debug'),
156+
param('session.storage.options'),
156157
])
157158
->tag('kernel.event_subscriber')
159+
->tag('kernel.reset', ['method' =>'reset'])
158160

159161
// for BC
160162
->alias('session.storage.filesystem','session.storage.mock_file')

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/test.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
useSymfony\Component\BrowserKit\CookieJar;
1717
useSymfony\Component\BrowserKit\History;
1818
useSymfony\Component\DependencyInjection\ServiceLocator;
19-
useSymfony\Component\HttpKernel\EventListener\TestSessionListener;
19+
useSymfony\Component\HttpKernel\EventListener\SessionListener;
2020

2121
returnstaticfunction (ContainerConfigurator$container) {
2222
$container->parameters()->set('test.client.parameters', []);
@@ -35,11 +35,13 @@
3535
->set('test.client.history', History::class)->share(false)
3636
->set('test.client.cookiejar', CookieJar::class)->share(false)
3737

38-
->set('test.session.listener',TestSessionListener::class)
38+
->set('test.session.listener',SessionListener::class)
3939
->args([
4040
service_locator([
4141
'session' =>service('.session.do-not-use')->ignoreOnInvalid(),
4242
]),
43+
param('kernel.debug'),
44+
param('session.storage.options'),
4345
])
4446
->tag('kernel.event_subscriber')
4547

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class Request
186186
protected$format;
187187

188188
/**
189-
* @var SessionInterface|callable
189+
* @var SessionInterface|callable(): SessionInterface
190190
*/
191191
protected$session;
192192

@@ -775,6 +775,8 @@ public function setSession(SessionInterface $session)
775775

776776
/**
777777
* @internal
778+
*
779+
* @param callable(): SessionInterface $factory
778780
*/
779781
publicfunctionsetSessionFactory(callable$factory)
780782
{

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

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313

1414
usePsr\Container\ContainerInterface;
1515
useSymfony\Component\EventDispatcher\EventSubscriberInterface;
16+
useSymfony\Component\HttpFoundation\Cookie;
1617
useSymfony\Component\HttpFoundation\Session\Session;
1718
useSymfony\Component\HttpFoundation\Session\SessionInterface;
19+
useSymfony\Component\HttpFoundation\Session\SessionUtils;
1820
useSymfony\Component\HttpKernel\Event\FinishRequestEvent;
1921
useSymfony\Component\HttpKernel\Event\RequestEvent;
2022
useSymfony\Component\HttpKernel\Event\ResponseEvent;
2123
useSymfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException;
2224
useSymfony\Component\HttpKernel\KernelEvents;
25+
useSymfony\Contracts\Service\ResetInterface;
2326

2427
/**
2528
* Sets the session onto the request on the "kernel.request" event and saves
@@ -36,18 +39,24 @@
3639
*
3740
* @internal
3841
*/
39-
abstractclass AbstractSessionListenerimplements EventSubscriberInterface
42+
abstractclass AbstractSessionListenerimplements EventSubscriberInterface, ResetInterface
4043
{
4144
publicconstNO_AUTO_CACHE_CONTROL_HEADER ='Symfony-Session-NoAutoCacheControl';
4245

4346
protected$container;
4447
private$sessionUsageStack = [];
4548
private$debug;
4649

47-
publicfunction__construct(ContainerInterface$container =null,bool$debug =false)
50+
/**
51+
* @var array<string, mixed>
52+
*/
53+
private$sessionOptions;
54+
55+
publicfunction__construct(ContainerInterface$container =null,bool$debug =false,array$sessionOptions = [])
4856
{
4957
$this->container =$container;
5058
$this->debug =$debug;
59+
$this->sessionOptions =$sessionOptions;
5160
}
5261

5362
publicfunctiononKernelRequest(RequestEvent$event)
@@ -60,7 +69,22 @@ public function onKernelRequest(RequestEvent $event)
6069
if (!$request->hasSession()) {
6170
// This variable prevents calling `$this->getSession()` twice in case the Request (and the below factory) is cloned
6271
$sess =null;
63-
$request->setSessionFactory(function ()use (&$sess) {return$sess ??$sess =$this->getSession(); });
72+
$request->setSessionFactory(function ()use (&$sess,$request) {
73+
if (!$sess) {
74+
$sess =$this->getSession();
75+
}
76+
77+
/*
78+
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
79+
* cookie need read from the cookie bag and set on the session storage.
80+
*/
81+
if ($sess && !$sess->isStarted()) {
82+
$sessionId =$request->cookies->get($sess->getName(),'');
83+
$sess->setId($sessionId);
84+
}
85+
86+
return$sess;
87+
});
6488
}
6589

6690
$session =$this->container &&$this->container->has('initialized_session') ?$this->container->get('initialized_session') :null;
@@ -109,6 +133,54 @@ public function onKernelResponse(ResponseEvent $event)
109133
* it is saved will just restart it.
110134
*/
111135
$session->save();
136+
137+
/*
138+
* For supporting sessions in php runtime with runners like roadrunner or swoole the session
139+
* cookie need to be written on the response object and should not be written by PHP itself.
140+
*/
141+
$sessionName =$session->getName();
142+
$sessionId =$session->getId();
143+
$sessionCookiePath =$this->sessionOptions['cookie_path'] ??'/';
144+
$sessionCookieDomain =$this->sessionOptions['cookie_domain'] ??null;
145+
$sessionCookieSecure =$this->sessionOptions['cookie_secure'] ??false;
146+
$sessionCookieHttpOnly =$this->sessionOptions['cookie_httponly'] ??true;
147+
$sessionCookieSameSite =$this->sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
148+
149+
SessionUtils::popSessionCookie($sessionName,$sessionCookiePath);
150+
151+
$request =$event->getRequest();
152+
$requestSessionCookieId =$request->cookies->get($sessionName);
153+
154+
if ($requestSessionCookieId &&$session->isEmpty()) {
155+
$response->headers->clearCookie(
156+
$sessionName,
157+
$sessionCookiePath,
158+
$sessionCookieDomain,
159+
$sessionCookieSecure,
160+
$sessionCookieHttpOnly,
161+
$sessionCookieSameSite
162+
);
163+
}elseif ($sessionId !==$requestSessionCookieId) {
164+
$expire =0;
165+
$lifetime =$this->sessionOptions['cookie_lifetime'] ??null;
166+
if ($lifetime) {
167+
$expire =time() +$lifetime;
168+
}
169+
170+
$response->headers->setCookie(
171+
Cookie::create(
172+
$sessionName,
173+
$sessionId,
174+
$expire,
175+
$sessionCookiePath,
176+
$sessionCookieDomain,
177+
$sessionCookieSecure,
178+
$sessionCookieHttpOnly,
179+
false,
180+
$sessionCookieSameSite
181+
)
182+
);
183+
}
112184
}
113185

114186
if ($sessioninstanceof Session ?$session->getUsageIndex() ===end($this->sessionUsageStack) : !$session->isStarted()) {
@@ -188,6 +260,20 @@ public static function getSubscribedEvents(): array
188260
];
189261
}
190262

263+
publicfunctionreset():void
264+
{
265+
if (\PHP_SESSION_ACTIVE ===session_status()) {
266+
session_abort();
267+
}
268+
269+
session_unset();
270+
$_SESSION = [];
271+
272+
if (!headers_sent()) {// session id can only be reset when no headers were so we check for headers_sent first
273+
session_id('');
274+
}
275+
}
276+
191277
/**
192278
* Gets the session object.
193279
*

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
* @author Fabien Potencier <fabien@symfony.com>
2929
*
3030
* @internal
31+
*
32+
* @deprecated the TestSessionListener use the default SessionListener instead
3133
*/
3234
abstractclass AbstractTestSessionListenerimplements EventSubscriberInterface
3335
{
@@ -37,6 +39,8 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
3739
publicfunction__construct(array$sessionOptions = [])
3840
{
3941
$this->sessionOptions =$sessionOptions;
42+
43+
trigger_deprecation('symfony/http-kernel','5.4','The %s is deprecated use the %s instead.',__CLASS__, AbstractSessionListener::class);
4044
}
4145

4246
publicfunctiononKernelRequest(RequestEvent$event)

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespaceSymfony\Component\HttpKernel\EventListener;
1313

14-
usePsr\Container\ContainerInterface;
1514
useSymfony\Component\HttpFoundation\Session\SessionInterface;
1615
useSymfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
1716
useSymfony\Component\HttpKernel\Event\RequestEvent;
@@ -29,11 +28,6 @@
2928
*/
3029
class SessionListenerextends AbstractSessionListener
3130
{
32-
publicfunction__construct(ContainerInterface$container,bool$debug =false)
33-
{
34-
parent::__construct($container,$debug);
35-
}
36-
3731
publicfunctiononKernelRequest(RequestEvent$event)
3832
{
3933
parent::onKernelRequest($event);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* @author Fabien Potencier <fabien@symfony.com>
2121
*
2222
* @final
23+
*
24+
* @deprecated the TestSessionListener use the default SessionListener instead
2325
*/
2426
class TestSessionListenerextends AbstractTestSessionListener
2527
{

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function testOnlyTriggeredOnMainRequest()
4747
publicfunctiontestSessionIsSet()
4848
{
4949
$session =$this->createMock(Session::class);
50+
$session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
5051

5152
$requestStack =$this->createMock(RequestStack::class);
5253
$requestStack->expects($this->once())->method('getMainRequest')->willReturn(null);
@@ -73,6 +74,7 @@ public function testSessionIsSet()
7374
publicfunctiontestSessionUsesFactory()
7475
{
7576
$session =$this->createMock(Session::class);
77+
$session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
7678
$sessionFactory =$this->createMock(SessionFactory::class);
7779
$sessionFactory->expects($this->once())->method('createSession')->willReturn($session);
7880

@@ -142,6 +144,32 @@ public function testResponseIsStillPublicIfSessionStartedAndHeaderPresent()
142144
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
143145
}
144146

147+
publicfunctiontestSessionSaveAndResponseHasSessionCookie()
148+
{
149+
$session =$this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
150+
$session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0,1));
151+
$session->expects($this->exactly(1))->method('getId')->willReturn('123456');
152+
$session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
153+
$session->expects($this->exactly(1))->method('save');
154+
$session->expects($this->exactly(1))->method('isStarted')->willReturn(true);
155+
156+
$container =newContainer();
157+
$container->set('initialized_session',$session);
158+
159+
$listener =newSessionListener($container);
160+
$kernel =$this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
161+
162+
$request =newRequest();
163+
$listener->onKernelRequest(newRequestEvent($kernel,$request, HttpKernelInterface::MASTER_REQUEST));
164+
165+
$response =newResponse();
166+
$listener->onKernelResponse(newResponseEvent($kernel,newRequest(), HttpKernelInterface::MASTER_REQUEST,$response));
167+
168+
$cookies =$response->headers->getCookies();
169+
$this->assertSame('PHPSESSID',$cookies[0]->getName());
170+
$this->assertSame('123456',$cookies[0]->getValue());
171+
}
172+
145173
publicfunctiontestUninitializedSession()
146174
{
147175
$kernel =$this->createMock(HttpKernelInterface::class);
@@ -166,6 +194,7 @@ public function testUninitializedSession()
166194
publicfunctiontestSurrogateMainRequestIsPublic()
167195
{
168196
$session =$this->createMock(Session::class);
197+
$session->expects($this->exactly(2))->method('getName')->willReturn('PHPSESSID');
169198
$session->expects($this->exactly(4))->method('getUsageIndex')->will($this->onConsecutiveCalls(0,1,1,1));
170199

171200
$container =newContainer();
@@ -205,6 +234,7 @@ public function testSurrogateMainRequestIsPublic()
205234
publicfunctiontestGetSessionIsCalledOnce()
206235
{
207236
$session =$this->createMock(Session::class);
237+
$session->expects($this->exactly(2))->method('getName')->willReturn('PHPSESSID');
208238
$sessionStorage =$this->createMock(NativeSessionStorage::class);
209239
$kernel =$this->createMock(KernelInterface::class);
210240

@@ -282,6 +312,7 @@ public function testSessionUsageLogIfStatelessAndSessionUsed()
282312
publicfunctiontestSessionIsSavedWhenUnexpectedSessionExceptionThrown()
283313
{
284314
$session =$this->createMock(Session::class);
315+
$session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
285316
$session->method('isStarted')->willReturn(true);
286317
$session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0,1));
287318
$session->expects($this->exactly(1))->method('save');
@@ -368,4 +399,46 @@ public function testSessionUsageCallbackWhenNoStateless()
368399

369400
(newSessionListener($container,true))->onSessionUsage();
370401
}
402+
403+
/**
404+
* @runInSeparateProcess
405+
*/
406+
publicfunctiontestReset()
407+
{
408+
session_start();
409+
$_SESSION['test'] = ['test'];
410+
session_write_close();
411+
412+
$this->assertNotEmpty($_SESSION);
413+
$this->assertNotEmpty(session_id());
414+
415+
$container =newContainer();
416+
417+
(newSessionListener($container,true))->reset();
418+
419+
$this->assertEmpty($_SESSION);
420+
$this->assertEmpty(session_id());
421+
$this->assertSame(\PHP_SESSION_NONE,session_status());
422+
}
423+
424+
/**
425+
* @runInSeparateProcess
426+
*/
427+
publicfunctiontestResetUnclosedSession()
428+
{
429+
session_start();
430+
$_SESSION['test'] = ['test'];
431+
432+
$this->assertNotEmpty($_SESSION);
433+
$this->assertNotEmpty(session_id());
434+
$this->assertSame(\PHP_SESSION_ACTIVE,session_status());
435+
436+
$container =newContainer();
437+
438+
(newSessionListener($container,true))->reset();
439+
440+
$this->assertEmpty($_SESSION);
441+
$this->assertEmpty(session_id());
442+
$this->assertSame(\PHP_SESSION_NONE,session_status());
443+
}
371444
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* Tests SessionListener.
2929
*
3030
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
31+
* @group legacy
3132
*/
3233
class TestSessionListenerTestextends TestCase
3334
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp