Overview

Namespaces

  • Evenement
  • None
  • PHP
  • Psr
    • Http
      • Message
  • Ratchet
    • Http
    • RFC6455
      • Handshake
      • Messaging
    • Server
    • Session
      • Serialize
      • Storage
        • Proxy
    • Wamp
    • WebSocket
  • React
    • EventLoop
      • Tick
      • Timer
    • Socket
    • Stream
  • Symfony
    • Component
      • HttpFoundation
        • Session
          • Attribute
          • Flash
          • Storage
            • Handler
            • Proxy
      • Routing
        • Annotation
        • Exception
        • Generator
          • Dumper
        • Loader
          • DependencyInjection
        • Matcher
          • Dumper
        • Tests
          • Annotation
          • Fixtures
            • AnnotatedClasses
            • OtherAnnotatedClasses
          • Generator
            • Dumper
          • Loader
          • Matcher
            • Dumper

Classes

  • MetadataBag
  • MockArraySessionStorage
  • MockFileSessionStorage
  • NativeSessionStorage
  • PhpBridgeSessionStorage

Interfaces

  • SessionStorageInterface
  • Overview
  • Namespace
  • Class
  • Tree
  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\HttpFoundation\Session\Storage;
 13: 
 14: use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
 15: use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
 16: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
 17: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
 18: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
 19: 
 20: /**
 21:  * This provides a base class for session attribute storage.
 22:  *
 23:  * @author Drak <[email protected]>
 24:  */
 25: class NativeSessionStorage implements SessionStorageInterface
 26: {
 27:     /**
 28:      * Array of SessionBagInterface.
 29:      *
 30:      * @var SessionBagInterface[]
 31:      */
 32:     protected $bags;
 33: 
 34:     /**
 35:      * @var bool
 36:      */
 37:     protected $started = false;
 38: 
 39:     /**
 40:      * @var bool
 41:      */
 42:     protected $closed = false;
 43: 
 44:     /**
 45:      * @var AbstractProxy
 46:      */
 47:     protected $saveHandler;
 48: 
 49:     /**
 50:      * @var MetadataBag
 51:      */
 52:     protected $metadataBag;
 53: 
 54:     /**
 55:      * Constructor.
 56:      *
 57:      * Depending on how you want the storage driver to behave you probably
 58:      * want to override this constructor entirely.
 59:      *
 60:      * List of options for $options array with their defaults.
 61:      *
 62:      * @see http://php.net/session.configuration for options
 63:      * but we omit 'session.' from the beginning of the keys for convenience.
 64:      *
 65:      * ("auto_start", is not supported as it tells PHP to start a session before
 66:      * PHP starts to execute user-land code. Setting during runtime has no effect).
 67:      *
 68:      * cache_limiter, "" (use "0" to prevent headers from being sent entirely).
 69:      * cookie_domain, ""
 70:      * cookie_httponly, ""
 71:      * cookie_lifetime, "0"
 72:      * cookie_path, "/"
 73:      * cookie_secure, ""
 74:      * entropy_file, ""
 75:      * entropy_length, "0"
 76:      * gc_divisor, "100"
 77:      * gc_maxlifetime, "1440"
 78:      * gc_probability, "1"
 79:      * hash_bits_per_character, "4"
 80:      * hash_function, "0"
 81:      * name, "PHPSESSID"
 82:      * referer_check, ""
 83:      * serialize_handler, "php"
 84:      * use_strict_mode, "0"
 85:      * use_cookies, "1"
 86:      * use_only_cookies, "1"
 87:      * use_trans_sid, "0"
 88:      * upload_progress.enabled, "1"
 89:      * upload_progress.cleanup, "1"
 90:      * upload_progress.prefix, "upload_progress_"
 91:      * upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS"
 92:      * upload_progress.freq, "1%"
 93:      * upload_progress.min-freq, "1"
 94:      * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
 95:      * sid_length, "32"
 96:      * sid_bits_per_character, "5"
 97:      * trans_sid_hosts, $_SERVER['HTTP_HOST']
 98:      * trans_sid_tags, "a=href,area=href,frame=src,form="
 99:      *
100:      * @param array                                                            $options Session configuration options
101:      * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $handler
102:      * @param MetadataBag                                                      $metaBag MetadataBag
103:      */
104:     public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
105:     {
106:         session_cache_limiter(''); // disable by default because it's managed by HeaderBag (if used)
107:         ini_set('session.use_cookies', 1);
108: 
109:         session_register_shutdown();
110: 
111:         $this->setMetadataBag($metaBag);
112:         $this->setOptions($options);
113:         $this->setSaveHandler($handler);
114:     }
115: 
116:     /**
117:      * Gets the save handler instance.
118:      *
119:      * @return AbstractProxy
120:      */
121:     public function getSaveHandler()
122:     {
123:         return $this->saveHandler;
124:     }
125: 
126:     /**
127:      * {@inheritdoc}
128:      */
129:     public function start()
130:     {
131:         if ($this->started) {
132:             return true;
133:         }
134: 
135:         if (\PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE === session_status()) {
136:             throw new \RuntimeException('Failed to start the session: already started by PHP.');
137:         }
138: 
139:         if (\PHP_VERSION_ID < 50400 && !$this->closed && isset($_SESSION) && session_id()) {
140:             // not 100% fool-proof, but is the most reliable way to determine if a session is active in PHP 5.3
141:             throw new \RuntimeException('Failed to start the session: already started by PHP ($_SESSION is set).');
142:         }
143: 
144:         if (ini_get('session.use_cookies') && headers_sent($file, $line)) {
145:             throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
146:         }
147: 
148:         // ok to try and start the session
149:         if (!session_start()) {
150:             throw new \RuntimeException('Failed to start the session');
151:         }
152: 
153:         $this->loadSession();
154:         if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
155:             // This condition matches only PHP 5.3 with internal save handlers
156:             $this->saveHandler->setActive(true);
157:         }
158: 
159:         return true;
160:     }
161: 
162:     /**
163:      * {@inheritdoc}
164:      */
165:     public function getId()
166:     {
167:         return $this->saveHandler->getId();
168:     }
169: 
170:     /**
171:      * {@inheritdoc}
172:      */
173:     public function setId($id)
174:     {
175:         $this->saveHandler->setId($id);
176:     }
177: 
178:     /**
179:      * {@inheritdoc}
180:      */
181:     public function getName()
182:     {
183:         return $this->saveHandler->getName();
184:     }
185: 
186:     /**
187:      * {@inheritdoc}
188:      */
189:     public function setName($name)
190:     {
191:         $this->saveHandler->setName($name);
192:     }
193: 
194:     /**
195:      * {@inheritdoc}
196:      */
197:     public function regenerate($destroy = false, $lifetime = null)
198:     {
199:         // Cannot regenerate the session ID for non-active sessions.
200:         if (\PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE !== session_status()) {
201:             return false;
202:         }
203: 
204:         // Check if session ID exists in PHP 5.3
205:         if (\PHP_VERSION_ID < 50400 && '' === session_id()) {
206:             return false;
207:         }
208: 
209:         if (null !== $lifetime) {
210:             ini_set('session.cookie_lifetime', $lifetime);
211:         }
212: 
213:         if ($destroy) {
214:             $this->metadataBag->stampNew();
215:         }
216: 
217:         $isRegenerated = session_regenerate_id($destroy);
218: 
219:         // The reference to $_SESSION in session bags is lost in PHP7 and we need to re-create it.
220:         // @see https://bugs.php.net/bug.php?id=70013
221:         $this->loadSession();
222: 
223:         return $isRegenerated;
224:     }
225: 
226:     /**
227:      * {@inheritdoc}
228:      */
229:     public function save()
230:     {
231:         session_write_close();
232: 
233:         if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
234:             // This condition matches only PHP 5.3 with internal save handlers
235:             $this->saveHandler->setActive(false);
236:         }
237: 
238:         $this->closed = true;
239:         $this->started = false;
240:     }
241: 
242:     /**
243:      * {@inheritdoc}
244:      */
245:     public function clear()
246:     {
247:         // clear out the bags
248:         foreach ($this->bags as $bag) {
249:             $bag->clear();
250:         }
251: 
252:         // clear out the session
253:         $_SESSION = array();
254: 
255:         // reconnect the bags to the session
256:         $this->loadSession();
257:     }
258: 
259:     /**
260:      * {@inheritdoc}
261:      */
262:     public function registerBag(SessionBagInterface $bag)
263:     {
264:         if ($this->started) {
265:             throw new \LogicException('Cannot register a bag when the session is already started.');
266:         }
267: 
268:         $this->bags[$bag->getName()] = $bag;
269:     }
270: 
271:     /**
272:      * {@inheritdoc}
273:      */
274:     public function getBag($name)
275:     {
276:         if (!isset($this->bags[$name])) {
277:             throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
278:         }
279: 
280:         if ($this->saveHandler->isActive() && !$this->started) {
281:             $this->loadSession();
282:         } elseif (!$this->started) {
283:             $this->start();
284:         }
285: 
286:         return $this->bags[$name];
287:     }
288: 
289:     /**
290:      * Sets the MetadataBag.
291:      *
292:      * @param MetadataBag $metaBag
293:      */
294:     public function setMetadataBag(MetadataBag $metaBag = null)
295:     {
296:         if (null === $metaBag) {
297:             $metaBag = new MetadataBag();
298:         }
299: 
300:         $this->metadataBag = $metaBag;
301:     }
302: 
303:     /**
304:      * Gets the MetadataBag.
305:      *
306:      * @return MetadataBag
307:      */
308:     public function getMetadataBag()
309:     {
310:         return $this->metadataBag;
311:     }
312: 
313:     /**
314:      * {@inheritdoc}
315:      */
316:     public function isStarted()
317:     {
318:         return $this->started;
319:     }
320: 
321:     /**
322:      * Sets session.* ini variables.
323:      *
324:      * For convenience we omit 'session.' from the beginning of the keys.
325:      * Explicitly ignores other ini keys.
326:      *
327:      * @param array $options Session ini directives array(key => value)
328:      *
329:      * @see http://php.net/session.configuration
330:      */
331:     public function setOptions(array $options)
332:     {
333:         $validOptions = array_flip(array(
334:             'cache_limiter', 'cookie_domain', 'cookie_httponly',
335:             'cookie_lifetime', 'cookie_path', 'cookie_secure',
336:             'entropy_file', 'entropy_length', 'gc_divisor',
337:             'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
338:             'hash_function', 'name', 'referer_check',
339:             'serialize_handler', 'use_strict_mode', 'use_cookies',
340:             'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
341:             'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
342:             'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags',
343:             'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags',
344:         ));
345: 
346:         foreach ($options as $key => $value) {
347:             if (isset($validOptions[$key])) {
348:                 ini_set('session.'.$key, $value);
349:             }
350:         }
351:     }
352: 
353:     /**
354:      * Registers session save handler as a PHP session handler.
355:      *
356:      * To use internal PHP session save handlers, override this method using ini_set with
357:      * session.save_handler and session.save_path e.g.
358:      *
359:      *     ini_set('session.save_handler', 'files');
360:      *     ini_set('session.save_path', '/tmp');
361:      *
362:      * or pass in a NativeSessionHandler instance which configures session.save_handler in the
363:      * constructor, for a template see NativeFileSessionHandler or use handlers in
364:      * composer package drak/native-session
365:      *
366:      * @see http://php.net/session-set-save-handler
367:      * @see http://php.net/sessionhandlerinterface
368:      * @see http://php.net/sessionhandler
369:      * @see http://github.com/drak/NativeSession
370:      *
371:      * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $saveHandler
372:      *
373:      * @throws \InvalidArgumentException
374:      */
375:     public function setSaveHandler($saveHandler = null)
376:     {
377:         if (!$saveHandler instanceof AbstractProxy &&
378:             !$saveHandler instanceof NativeSessionHandler &&
379:             !$saveHandler instanceof \SessionHandlerInterface &&
380:             null !== $saveHandler) {
381:             throw new \InvalidArgumentException('Must be instance of AbstractProxy or NativeSessionHandler; implement \SessionHandlerInterface; or be null.');
382:         }
383: 
384:         // Wrap $saveHandler in proxy and prevent double wrapping of proxy
385:         if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
386:             $saveHandler = new SessionHandlerProxy($saveHandler);
387:         } elseif (!$saveHandler instanceof AbstractProxy) {
388:             $saveHandler = \PHP_VERSION_ID >= 50400 ?
389:                 new SessionHandlerProxy(new \SessionHandler()) : new NativeProxy();
390:         }
391:         $this->saveHandler = $saveHandler;
392: 
393:         if ($this->saveHandler instanceof \SessionHandlerInterface) {
394:             if (\PHP_VERSION_ID >= 50400) {
395:                 session_set_save_handler($this->saveHandler, false);
396:             } else {
397:                 session_set_save_handler(
398:                     array($this->saveHandler, 'open'),
399:                     array($this->saveHandler, 'close'),
400:                     array($this->saveHandler, 'read'),
401:                     array($this->saveHandler, 'write'),
402:                     array($this->saveHandler, 'destroy'),
403:                     array($this->saveHandler, 'gc')
404:                 );
405:             }
406:         }
407:     }
408: 
409:     /**
410:      * Load the session with attributes.
411:      *
412:      * After starting the session, PHP retrieves the session from whatever handlers
413:      * are set to (either PHP's internal, or a custom save handler set with session_set_save_handler()).
414:      * PHP takes the return value from the read() handler, unserializes it
415:      * and populates $_SESSION with the result automatically.
416:      *
417:      * @param array|null $session
418:      */
419:     protected function loadSession(array &$session = null)
420:     {
421:         if (null === $session) {
422:             $session = &$_SESSION;
423:         }
424: 
425:         $bags = array_merge($this->bags, array($this->metadataBag));
426: 
427:         foreach ($bags as $bag) {
428:             $key = $bag->getStorageKey();
429:             $session[$key] = isset($session[$key]) ? $session[$key] : array();
430:             $bag->initialize($session[$key]);
431:         }
432: 
433:         $this->started = true;
434:         $this->closed = false;
435:     }
436: }
437: 
Ratchet API documentation generated by ApiGen 2.8.0