2011-11-29 04:35:09 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2012-02-08 23:15:47 +00:00
namespace Symfony\Component\HttpFoundation\Session\Storage ;
2011-11-29 04:35:09 +00:00
2012-02-08 23:15:47 +00:00
use Symfony\Component\HttpFoundation\Session\SessionBagInterface ;
2013-04-05 12:57:01 +01:00
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler ;
2012-03-31 04:15:05 +01:00
use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag ;
2012-03-03 02:54:20 +00:00
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy ;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy ;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy ;
2011-11-29 04:35:09 +00:00
/**
* This provides a base class for session attribute storage .
*
* @ author Drak < drak @ zikula . org >
*/
2012-03-14 15:14:09 +00:00
class NativeSessionStorage implements SessionStorageInterface
2011-11-29 04:35:09 +00:00
{
/**
2012-02-08 09:46:38 +00:00
* Array of SessionBagInterface
*
2012-11-01 15:08:59 +00:00
* @ var SessionBagInterface []
2011-11-29 04:35:09 +00:00
*/
2012-02-08 09:46:38 +00:00
protected $bags ;
2011-11-29 04:35:09 +00:00
/**
2012-11-01 15:08:59 +00:00
* @ var Boolean
2011-11-29 04:35:09 +00:00
*/
protected $started = false ;
/**
2012-11-01 15:08:59 +00:00
* @ var Boolean
2011-11-29 04:35:09 +00:00
*/
protected $closed = false ;
2012-03-03 02:54:20 +00:00
/**
* @ var AbstractProxy
*/
protected $saveHandler ;
2012-03-29 12:30:37 +01:00
/**
2012-03-31 04:15:05 +01:00
* @ var MetadataBag
2012-03-29 12:30:37 +01:00
*/
2012-03-31 04:15:05 +01:00
protected $metadataBag ;
2012-03-29 12:30:37 +01:00
2011-11-29 04:35:09 +00:00
/**
* Constructor .
*
* Depending on how you want the storage driver to behave you probably
2012-11-12 13:58:31 +00:00
* want to override this constructor entirely .
2011-11-29 04:35:09 +00:00
*
* List of options for $options array with their defaults .
2012-02-22 18:05:55 +00:00
* @ see http :// php . net / session . configuration for options
2013-04-18 06:30:58 +01:00
* but we omit 'session.' from the beginning of the keys for convenience .
2011-11-29 04:35:09 +00:00
*
2012-06-29 18:05:14 +01:00
* ( " auto_start " , is not supported as it tells PHP to start a session before
* PHP starts to execute user - land code . Setting during runtime has no effect ) .
*
2012-02-22 18:05:55 +00:00
* cache_limiter , " nocache " ( use " 0 " to prevent headers from being sent entirely ) .
2011-11-29 04:35:09 +00:00
* cookie_domain , " "
* cookie_httponly , " "
* cookie_lifetime , " 0 "
* cookie_path , " / "
* cookie_secure , " "
* entropy_file , " "
* entropy_length , " 0 "
* gc_divisor , " 100 "
* gc_maxlifetime , " 1440 "
* gc_probability , " 1 "
* hash_bits_per_character , " 4 "
* hash_function , " 0 "
* name , " PHPSESSID "
* referer_check , " "
* serialize_handler , " php "
* use_cookies , " 1 "
* use_only_cookies , " 1 "
* use_trans_sid , " 0 "
* upload_progress . enabled , " 1 "
* upload_progress . cleanup , " 1 "
* upload_progress . prefix , " upload_progress_ "
* upload_progress . name , " PHP_SESSION_UPLOAD_PROGRESS "
* upload_progress . freq , " 1% "
* upload_progress . min - freq , " 1 "
* url_rewriter . tags , " a=href,area=href,frame=src,form=,fieldset= "
*
2013-04-18 06:30:58 +01:00
* @ param array $options Session configuration options .
2013-04-05 12:57:01 +01:00
* @ param AbstractProxy | NativeSessionHandler | \SessionHandlerInterface | null $handler
2013-04-18 06:30:58 +01:00
* @ param MetadataBag $metaBag MetadataBag .
2011-11-29 04:35:09 +00:00
*/
2013-04-18 06:30:58 +01:00
public function __construct ( array $options = array (), $handler = null , MetadataBag $metaBag = null )
2011-11-29 04:35:09 +00:00
{
2012-03-08 09:26:10 +00:00
ini_set ( 'session.cache_limiter' , '' ); // disable by default because it's managed by HeaderBag (if used)
ini_set ( 'session.use_cookies' , 1 );
2012-03-14 11:53:34 +00:00
if ( version_compare ( phpversion (), '5.4.0' , '>=' )) {
session_register_shutdown ();
} else {
register_shutdown_function ( 'session_write_close' );
}
2012-03-31 04:15:05 +01:00
$this -> setMetadataBag ( $metaBag );
2011-11-29 04:35:09 +00:00
$this -> setOptions ( $options );
2012-03-03 02:54:20 +00:00
$this -> setSaveHandler ( $handler );
}
/**
* Gets the save handler instance .
*
* @ return AbstractProxy
*/
public function getSaveHandler ()
{
return $this -> saveHandler ;
2011-11-29 04:35:09 +00:00
}
/**
* { @ inheritdoc }
*/
public function start ()
{
if ( $this -> started && ! $this -> closed ) {
return true ;
}
2013-04-05 12:57:01 +01:00
if ( version_compare ( phpversion (), '5.4.0' , '>=' ) && \PHP_SESSION_ACTIVE === session_status ()) {
throw new \RuntimeException ( 'Failed to start the session: already started by PHP.' );
}
2012-03-08 09:26:10 +00:00
2013-04-05 12:57:01 +01:00
if ( version_compare ( phpversion (), '5.4.0' , '<' ) && isset ( $_SESSION ) && session_id ()) {
// not 100% fool-proof, but is the most reliable way to determine if a session is active in PHP 5.3
throw new \RuntimeException ( 'Failed to start the session: already started by PHP ($_SESSION is set).' );
2012-03-08 09:26:10 +00:00
}
2013-04-20 10:51:05 +01:00
if ( ini_get ( 'session.use_cookies' ) && headers_sent ( $headers_sent_file , $headers_sent_line_number )) {
throw new \RuntimeException ( 'Failed to start the session because headers have already been sent by ' . $headers_sent_file . ':' . $headers_sent_line_number . '.' );
2012-01-02 15:32:41 +00:00
}
2013-04-05 12:57:01 +01:00
// ok to try and start the session
2011-11-29 04:35:09 +00:00
if ( ! session_start ()) {
2013-04-18 06:30:58 +01:00
throw new \RuntimeException ( 'Failed to start the session' );
2011-11-29 04:35:09 +00:00
}
$this -> loadSession ();
2012-03-03 02:54:20 +00:00
if ( ! $this -> saveHandler -> isWrapper () && ! $this -> saveHandler -> isSessionHandlerInterface ()) {
2013-04-05 12:57:01 +01:00
// This condition matches only PHP 5.3 with internal save handlers
$this -> saveHandler -> setActive ( true );
2012-03-03 02:54:20 +00:00
}
2011-11-29 04:35:09 +00:00
return true ;
}
/**
* { @ inheritdoc }
*/
public function getId ()
{
if ( ! $this -> started ) {
return '' ; // returning empty is consistent with session_id() behaviour
}
2012-03-14 11:53:34 +00:00
return $this -> saveHandler -> getId ();
}
/**
* { @ inheritdoc }
*/
public function setId ( $id )
{
2012-07-28 23:02:29 +01:00
$this -> saveHandler -> setId ( $id );
2012-03-14 11:53:34 +00:00
}
/**
* { @ inheritdoc }
*/
public function getName ()
{
return $this -> saveHandler -> getName ();
}
/**
* { @ inheritdoc }
*/
public function setName ( $name )
{
$this -> saveHandler -> setName ( $name );
2011-11-29 04:35:09 +00:00
}
/**
2012-02-12 00:54:16 +00:00
* { @ inheritdoc }
2011-11-29 04:35:09 +00:00
*/
2012-03-30 18:02:35 +01:00
public function regenerate ( $destroy = false , $lifetime = null )
2011-11-29 04:35:09 +00:00
{
2012-03-30 18:02:35 +01:00
if ( null !== $lifetime ) {
ini_set ( 'session.cookie_lifetime' , $lifetime );
}
2012-03-29 12:30:37 +01:00
if ( $destroy ) {
2012-03-31 04:15:05 +01:00
$this -> metadataBag -> stampNew ();
2012-03-29 12:30:37 +01:00
}
2011-11-29 04:35:09 +00:00
return session_regenerate_id ( $destroy );
}
/**
* { @ inheritdoc }
*/
public function save ()
{
session_write_close ();
2012-03-03 02:54:20 +00:00
2013-04-05 12:57:01 +01:00
if ( ! $this -> saveHandler -> isWrapper () && ! $this -> saveHandler -> isSessionHandlerInterface ()) {
// This condition matches only PHP 5.3 with internal save handlers
2012-03-03 02:54:20 +00:00
$this -> saveHandler -> setActive ( false );
}
2011-11-29 04:35:09 +00:00
$this -> closed = true ;
}
/**
* { @ inheritdoc }
*/
public function clear ()
{
// clear out the bags
2012-02-08 09:46:38 +00:00
foreach ( $this -> bags as $bag ) {
$bag -> clear ();
}
2011-11-29 04:35:09 +00:00
// clear out the session
$_SESSION = array ();
// reconnect the bags to the session
$this -> loadSession ();
}
2012-02-08 09:46:38 +00:00
/**
2012-02-12 00:54:16 +00:00
* { @ inheritdoc }
2012-02-08 09:46:38 +00:00
*/
public function registerBag ( SessionBagInterface $bag )
{
$this -> bags [ $bag -> getName ()] = $bag ;
}
/**
2012-02-12 00:54:16 +00:00
* { @ inheritdoc }
2012-02-08 09:46:38 +00:00
*/
public function getBag ( $name )
{
if ( ! isset ( $this -> bags [ $name ])) {
throw new \InvalidArgumentException ( sprintf ( 'The SessionBagInterface %s is not registered.' , $name ));
}
2013-04-18 06:30:58 +01:00
if ( $this -> saveHandler -> isActive () && ! $this -> started ) {
$this -> loadSession ();
} elseif ( ! $this -> started ) {
2012-06-29 18:05:14 +01:00
$this -> start ();
2012-02-08 09:46:38 +00:00
}
return $this -> bags [ $name ];
}
2012-03-29 12:30:37 +01:00
/**
2012-03-31 04:15:05 +01:00
* Sets the MetadataBag .
2012-03-29 12:30:37 +01:00
*
2012-03-31 04:15:05 +01:00
* @ param MetadataBag $metaBag
2012-03-29 12:30:37 +01:00
*/
2012-03-31 04:15:05 +01:00
public function setMetadataBag ( MetadataBag $metaBag = null )
2012-03-29 12:30:37 +01:00
{
if ( null === $metaBag ) {
2012-03-31 04:15:05 +01:00
$metaBag = new MetadataBag ();
2012-03-29 12:30:37 +01:00
}
2012-03-31 04:15:05 +01:00
$this -> metadataBag = $metaBag ;
2012-03-29 12:30:37 +01:00
}
/**
2012-03-31 04:15:05 +01:00
* Gets the MetadataBag .
2012-03-29 12:30:37 +01:00
*
2012-03-31 04:15:05 +01:00
* @ return MetadataBag
2012-03-29 12:30:37 +01:00
*/
2012-03-31 04:15:05 +01:00
public function getMetadataBag ()
2012-03-29 12:30:37 +01:00
{
2012-03-31 04:15:05 +01:00
return $this -> metadataBag ;
2012-03-29 12:30:37 +01:00
}
2012-06-09 20:45:38 +01:00
/**
2012-07-01 22:21:53 +01:00
* { @ inheritdoc }
2012-06-09 20:45:38 +01:00
*/
public function isStarted ()
{
return $this -> started ;
}
2011-11-29 04:35:09 +00:00
/**
* Sets session .* ini variables .
*
* For convenience we omit 'session.' from the beginning of the keys .
* Explicitly ignores other ini keys .
*
2013-04-18 06:30:58 +01:00
* @ param array $options Session ini directives array ( key => value ) .
2011-11-29 04:35:09 +00:00
*
2012-02-22 18:05:55 +00:00
* @ see http :// php . net / session . configuration
2011-11-29 04:35:09 +00:00
*/
2012-03-04 11:04:40 +00:00
public function setOptions ( array $options )
2011-11-29 04:35:09 +00:00
{
2012-03-30 12:56:58 +01:00
$validOptions = array_flip ( array (
2012-06-29 18:05:14 +01:00
'cache_limiter' , 'cookie_domain' , 'cookie_httponly' ,
2012-03-30 12:37:48 +01:00
'cookie_lifetime' , 'cookie_path' , 'cookie_secure' ,
'entropy_file' , 'entropy_length' , 'gc_divisor' ,
'gc_maxlifetime' , 'gc_probability' , 'hash_bits_per_character' ,
'hash_function' , 'name' , 'referer_check' ,
'serialize_handler' , 'use_cookies' ,
'use_only_cookies' , 'use_trans_sid' , 'upload_progress.enabled' ,
'upload_progress.cleanup' , 'upload_progress.prefix' , 'upload_progress.name' ,
2012-03-30 12:56:58 +01:00
'upload_progress.freq' , 'upload_progress.min-freq' , 'url_rewriter.tags' ,
));
2012-03-30 12:37:48 +01:00
2012-03-08 09:26:10 +00:00
foreach ( $options as $key => $value ) {
2012-03-30 12:56:58 +01:00
if ( isset ( $validOptions [ $key ])) {
2011-11-29 04:35:09 +00:00
ini_set ( 'session.' . $key , $value );
}
}
}
/**
2013-04-05 12:57:01 +01:00
* Registers session save handler as a PHP session handler .
2011-11-29 04:35:09 +00:00
*
2012-02-22 18:05:55 +00:00
* To use internal PHP session save handlers , override this method using ini_set with
2013-01-30 21:05:56 +00:00
* session . save_handler and session . save_path e . g .
2011-11-29 04:35:09 +00:00
*
2013-01-30 21:05:56 +00:00
* ini_set ( 'session.save_handler' , 'files' );
2011-11-29 04:35:09 +00:00
* ini_set ( 'session.save_path' , / tmp ' );
*
2013-04-05 12:57:01 +01:00
* or pass in a NativeSessionHandler instance which configures session . save_handler in the
* constructor , for a template see NativeFileSessionHandler or use handlers in
* composer package drak / native - session
*
2012-02-22 18:05:55 +00:00
* @ see http :// php . net / session - set - save - handler
* @ see http :// php . net / sessionhandlerinterface
2012-03-03 02:54:20 +00:00
* @ see http :// php . net / sessionhandler
2013-04-05 12:57:01 +01:00
* @ see http :// github . com / drak / NativeSession
*
* @ param AbstractProxy | NativeSessionHandler | \SessionHandlerInterface | null $saveHandler
2012-03-03 02:54:20 +00:00
*
2013-04-05 12:57:01 +01:00
* @ throws \InvalidArgumentException
2011-11-29 04:35:09 +00:00
*/
2012-03-04 11:04:40 +00:00
public function setSaveHandler ( $saveHandler = null )
2011-11-29 04:35:09 +00:00
{
2013-04-05 12:57:01 +01:00
if ( ! $saveHandler instanceof AbstractProxy &&
! $saveHandler instanceof NativeSessionHandler &&
! $saveHandler instanceof \SessionHandlerInterface &&
null !== $saveHandler ) {
throw new \InvalidArgumentException ( 'Must be instance of AbstractProxy or NativeSessionHandler; implement \SessionHandlerInterface; or be null.' );
}
// Wrap $saveHandler in proxy and prevent double wrapping of proxy
2012-03-03 02:54:20 +00:00
if ( ! $saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface ) {
$saveHandler = new SessionHandlerProxy ( $saveHandler );
2012-03-04 11:04:40 +00:00
} elseif ( ! $saveHandler instanceof AbstractProxy ) {
2013-04-05 12:57:01 +01:00
$saveHandler = version_compare ( phpversion (), '5.4.0' , '>=' ) ?
new SessionHandlerProxy ( new \SessionHandler ()) : new NativeProxy ();
2011-11-29 04:35:09 +00:00
}
2012-03-03 02:54:20 +00:00
$this -> saveHandler = $saveHandler ;
if ( $this -> saveHandler instanceof \SessionHandlerInterface ) {
if ( version_compare ( phpversion (), '5.4.0' , '>=' )) {
2012-03-14 11:53:34 +00:00
session_set_save_handler ( $this -> saveHandler , false );
2012-03-03 02:54:20 +00:00
} else {
session_set_save_handler (
array ( $this -> saveHandler , 'open' ),
array ( $this -> saveHandler , 'close' ),
array ( $this -> saveHandler , 'read' ),
array ( $this -> saveHandler , 'write' ),
array ( $this -> saveHandler , 'destroy' ),
array ( $this -> saveHandler , 'gc' )
);
}
}
2011-11-29 04:35:09 +00:00
}
/**
* Load the session with attributes .
*
* After starting the session , PHP retrieves the session from whatever handlers
2012-02-22 18:05:55 +00:00
* are set to ( either PHP ' s internal , or a custom save handler set with session_set_save_handler ()) .
* PHP takes the return value from the read () handler , unserializes it
2011-11-29 04:35:09 +00:00
* and populates $_SESSION with the result automatically .
2012-02-12 00:54:16 +00:00
*
* @ param array | null $session
2011-11-29 04:35:09 +00:00
*/
2012-02-08 09:46:38 +00:00
protected function loadSession ( array & $session = null )
2011-11-29 04:35:09 +00:00
{
2012-02-08 09:46:38 +00:00
if ( null === $session ) {
$session = & $_SESSION ;
}
2011-11-29 04:35:09 +00:00
2012-03-31 04:15:05 +01:00
$bags = array_merge ( $this -> bags , array ( $this -> metadataBag ));
2012-03-29 12:30:37 +01:00
foreach ( $bags as $bag ) {
2012-02-08 09:46:38 +00:00
$key = $bag -> getStorageKey ();
$session [ $key ] = isset ( $session [ $key ]) ? $session [ $key ] : array ();
$bag -> initialize ( $session [ $key ]);
}
2012-03-08 09:26:10 +00:00
$this -> started = true ;
$this -> closed = false ;
2011-11-29 04:35:09 +00:00
}
}