Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9c1e468

Browse files
committed
bug #12341 [Kernel] ensure session is saved before sending response (Tobion)
This PR was merged into the 2.3 branch. Discussion ---------- [Kernel] ensure session is saved before sending response | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #6417, #7885 | License | MIT | Doc PR | n/a Saves the session, in case it is still open, before sending the response. This ensures several things in case the developer did not save the session explicitly: - If a session save handler without locking is used, it ensures the data is available on the next request, e.g. after a redirect. PHPs auto-save at script end via session_register_shutdown is executed after fastcgi_finish_request. So in this case the data could be missing the next request because it might not be saved the moment the new request is processed. - A locking save handler (e.g. the native 'files') circumvents concurrency problems like the one above. By saving the session before long-running things in the terminate event, we ensure the session is not blocked longer than needed. - When regenerating the session ID no locking is involved in PHPs session design. See https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must be saved anyway before sending the headers with the new session ID. Otherwise session data could get lost again for concurrent requests with the new ID. One result could be that you get logged out after just logging in. This listener should be executed as one of the last listeners, so that previous listeners can still operate on the open session. This prevents the overhead of restarting it. Listeners after closing the session can still work with the session as usual because Symfonys session implementation starts the session on demand. So writing to it after it is saved will just restart it. Commits ------- b7bfef0 [Kernel] ensure session is saved before sending response
2 parents 495cba6 + b7bfef0 commit 9c1e468

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
<argument type="service" id="service_container" />
4949
</service>
5050

51+
<service id="session.save_listener" class="Symfony\Component\HttpKernel\EventListener\SaveSessionListener">
52+
<tag name="kernel.event_subscriber" />
53+
</service>
54+
5155
<!-- for BC -->
5256
<service id="session.storage.filesystem" alias="session.storage.mock_file" />
5357
</services>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel\EventListener;
13+
14+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
16+
use Symfony\Component\HttpKernel\HttpKernelInterface;
17+
use Symfony\Component\HttpKernel\KernelEvents;
18+
19+
/**
20+
* Saves the session, in case it is still open, before sending the response/headers.
21+
*
22+
* This ensures several things in case the developer did not save the session explicitly:
23+
*
24+
* * If a session save handler without locking is used, it ensures the data is available
25+
* on the next request, e.g. after a redirect. PHPs auto-save at script end via
26+
* session_register_shutdown is executed after fastcgi_finish_request. So in this case
27+
* the data could be missing the next request because it might not be saved the moment
28+
* the new request is processed.
29+
* * A locking save handler (e.g. the native 'files') circumvents concurrency problems like
30+
* the one above. But by saving the session before long-running things in the terminate event,
31+
* we ensure the session is not blocked longer than needed.
32+
* * When regenerating the session ID no locking is involved in PHPs session design. See
33+
* https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must
34+
* be saved anyway before sending the headers with the new session ID. Otherwise session
35+
* data could get lost again for concurrent requests with the new ID. One result could be
36+
* that you get logged out after just logging in.
37+
*
38+
* This listener should be executed as one of the last listeners, so that previous listeners
39+
* can still operate on the open session. This prevents the overhead of restarting it.
40+
* Listeners after closing the session can still work with the session as usual because
41+
* Symfonys session implementation starts the session on demand. So writing to it after
42+
* it is saved will just restart it.
43+
*
44+
* @author Tobias Schultze <http://tobion.de>
45+
*/
46+
class SaveSessionListener implements EventSubscriberInterface
47+
{
48+
public function onKernelResponse(FilterResponseEvent $event)
49+
{
50+
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
51+
return;
52+
}
53+
54+
$session = $event->getRequest()->getSession();
55+
if ($session && $session->isStarted()) {
56+
$session->save();
57+
}
58+
}
59+
60+
public static function getSubscribedEvents()
61+
{
62+
return array(
63+
// low priority but higher than StreamedResponseListener
64+
KernelEvents::RESPONSE => array(array('onKernelResponse', -1000)),
65+
);
66+
}
67+
}

0 commit comments

Comments
 (0)