|
12 | 12 | namespace Symfony\Component\HttpFoundation\Session\Storage;
|
13 | 13 |
|
14 | 14 | use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
|
| 15 | +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler; |
15 | 16 | use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
|
16 | 17 | use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
|
17 | 18 | use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
|
@@ -91,9 +92,9 @@ class NativeSessionStorage implements SessionStorageInterface
|
91 | 92 | * upload_progress.min-freq, "1"
|
92 | 93 | * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
|
93 | 94 | *
|
94 |
| - * @param array $options Session configuration options. |
95 |
| - * @param object $handler SessionHandlerInterface. |
96 |
| - * @param MetadataBag $metaBag MetadataBag. |
| 95 | + * @param array $options Session configuration options. |
| 96 | + * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $handler |
| 97 | + * @param MetadataBag $metaBag MetadataBag. |
97 | 98 | */
|
98 | 99 | public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
|
99 | 100 | {
|
@@ -130,27 +131,28 @@ public function start()
|
130 | 131 | return true;
|
131 | 132 | }
|
132 | 133 |
|
133 |
| - // catch condition where session was started automatically by PHP |
134 |
| - if (!$this->started && !$this->closed && $this->saveHandler->isActive() |
135 |
| - && $this->saveHandler->isSessionHandlerInterface()) { |
136 |
| - $this->loadSession(); |
| 134 | + if (version_compare(phpversion(), '5.4.0', '>=') && \PHP_SESSION_ACTIVE === session_status()) { |
| 135 | + throw new \RuntimeException('Failed to start the session: already started by PHP.'); |
| 136 | + } |
137 | 137 |
|
138 |
| - return true; |
| 138 | + if (version_compare(phpversion(), '5.4.0', '<') && isset($_SESSION) && session_id()) { |
| 139 | + // not 100% fool-proof, but is the most reliable way to determine if a session is active in PHP 5.3 |
| 140 | + throw new \RuntimeException('Failed to start the session: already started by PHP ($_SESSION is set).'); |
139 | 141 | }
|
140 | 142 |
|
141 | 143 | if (ini_get('session.use_cookies') && headers_sent()) {
|
142 | 144 | throw new \RuntimeException('Failed to start the session because headers have already been sent.');
|
143 | 145 | }
|
144 | 146 |
|
145 |
| - // start the session |
| 147 | + // ok to try and start the session |
146 | 148 | if (!session_start()) {
|
147 | 149 | throw new \RuntimeException('Failed to start the session');
|
148 | 150 | }
|
149 | 151 |
|
150 | 152 | $this->loadSession();
|
151 |
| - |
152 | 153 | if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
|
153 |
| - $this->saveHandler->setActive(false); |
| 154 | + // This condition matches only PHP 5.3 with internal save handlers |
| 155 | + $this->saveHandler->setActive(true); |
154 | 156 | }
|
155 | 157 |
|
156 | 158 | return true;
|
@@ -215,7 +217,8 @@ public function save()
|
215 | 217 | {
|
216 | 218 | session_write_close();
|
217 | 219 |
|
218 |
| - if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { |
| 220 | + if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { |
| 221 | + // This condition matches only PHP 5.3 with internal save handlers |
219 | 222 | $this->saveHandler->setActive(false);
|
220 | 223 | }
|
221 | 224 |
|
@@ -329,29 +332,43 @@ public function setOptions(array $options)
|
329 | 332 | }
|
330 | 333 |
|
331 | 334 | /**
|
332 |
| - * Registers save handler as a PHP session handler. |
| 335 | + * Registers session save handler as a PHP session handler. |
333 | 336 | *
|
334 | 337 | * To use internal PHP session save handlers, override this method using ini_set with
|
335 | 338 | * session.save_handler and session.save_path e.g.
|
336 | 339 | *
|
337 | 340 | * ini_set('session.save_handler', 'files');
|
338 | 341 | * ini_set('session.save_path', /tmp');
|
339 | 342 | *
|
| 343 | + * or pass in a NativeSessionHandler instance which configures session.save_handler in the |
| 344 | + * constructor, for a template see NativeFileSessionHandler or use handlers in |
| 345 | + * composer package drak/native-session |
| 346 | + * |
340 | 347 | * @see http://php.net/session-set-save-handler
|
341 | 348 | * @see http://php.net/sessionhandlerinterface
|
342 | 349 | * @see http://php.net/sessionhandler
|
| 350 | + * @see http://github.com/drak/NativeSession |
| 351 | + * |
| 352 | + * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $saveHandler |
343 | 353 | *
|
344 |
| - * @param object $saveHandler Default null means NativeProxy. |
| 354 | + * @throws \InvalidArgumentException |
345 | 355 | */
|
346 | 356 | public function setSaveHandler($saveHandler = null)
|
347 | 357 | {
|
348 |
| - // Wrap $saveHandler in proxy |
| 358 | + if (!$saveHandler instanceof AbstractProxy && |
| 359 | + !$saveHandler instanceof NativeSessionHandler && |
| 360 | + !$saveHandler instanceof \SessionHandlerInterface && |
| 361 | + null !== $saveHandler) { |
| 362 | + throw new \InvalidArgumentException('Must be instance of AbstractProxy or NativeSessionHandler; implement \SessionHandlerInterface; or be null.'); |
| 363 | + } |
| 364 | + |
| 365 | + // Wrap $saveHandler in proxy and prevent double wrapping of proxy |
349 | 366 | if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
|
350 | 367 | $saveHandler = new SessionHandlerProxy($saveHandler);
|
351 | 368 | } elseif (!$saveHandler instanceof AbstractProxy) {
|
352 |
| - $saveHandler = new NativeProxy(); |
| 369 | + $saveHandler = version_compare(phpversion(), '5.4.0', '>=') ? |
| 370 | + new SessionHandlerProxy(new \SessionHandler()) : new NativeProxy(); |
353 | 371 | }
|
354 |
| - |
355 | 372 | $this->saveHandler = $saveHandler;
|
356 | 373 |
|
357 | 374 | if ($this->saveHandler instanceof \SessionHandlerInterface) {
|
|
0 commit comments