Source of file SessionManager.php
Size: 12,007 Bytes - Last Modified: 2014-03-12T23:21:18+01:00
/home/theseer/Downloads/ZendFramework-2.3.0/library/Zend/Session/SessionManager.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 | <?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Session; use Zend\EventManager\EventManagerInterface; /** * Session ManagerInterface implementation utilizing ext/session */ class SessionManager extends AbstractManager { /** * Default options when a call to {@link destroy()} is made * - send_expire_cookie: whether or not to send a cookie expiring the current session cookie * - clear_storage: whether or not to empty the storage object of any stored values * @var array */ protected $defaultDestroyOptions = array( 'send_expire_cookie' => true, 'clear_storage' => false, ); /** * @var string value returned by session_name() */ protected $name; /** * @var EventManagerInterface Validation chain to determine if session is valid */ protected $validatorChain; /** * Constructor * * @param Config\ConfigInterface|null $config * @param Storage\StorageInterface|null $storage * @param SaveHandler\SaveHandlerInterface|null $saveHandler * @throws Exception\RuntimeException */ public function __construct(Config\ConfigInterface $config = null, Storage\StorageInterface $storage = null, SaveHandler\SaveHandlerInterface $saveHandler = null) { parent::__construct($config, $storage, $saveHandler); register_shutdown_function(array($this, 'writeClose')); } /** * Does a session exist and is it currently active? * * @return bool */ public function sessionExists() { $sid = defined('SID') ? constant('SID') : false; if ($sid !== false && $this->getId()) { return true; } if (headers_sent()) { return true; } return false; } /** * Start session * * if No session currently exists, attempt to start it. Calls * {@link isValid()} once session_start() is called, and raises an * exception if validation fails. * * @param bool $preserveStorage If set to true, current session storage will not be overwritten by the * contents of $_SESSION. * @return void * @throws Exception\RuntimeException */ public function start($preserveStorage = false) { if ($this->sessionExists()) { return; } $saveHandler = $this->getSaveHandler(); if ($saveHandler instanceof SaveHandler\SaveHandlerInterface) { // register the session handler with ext/session $this->registerSaveHandler($saveHandler); } session_start(); $storage = $this->getStorage(); // Since session is starting, we need to potentially repopulate our // session storage if ($storage instanceof Storage\SessionStorage && $_SESSION !== $storage) { if (!$preserveStorage) { $storage->fromArray($_SESSION); } $_SESSION = $storage; } elseif ($storage instanceof Storage\StorageInitializationInterface) { $storage->init($_SESSION); } if (!$this->isValid()) { throw new Exception\RuntimeException('Session validation failed'); } } /** * Destroy/end a session * * @param array $options See {@link $defaultDestroyOptions} * @return void */ public function destroy(array $options = null) { if (!$this->sessionExists()) { return; } if (null === $options) { $options = $this->defaultDestroyOptions; } else { $options = array_merge($this->defaultDestroyOptions, $options); } session_destroy(); if ($options['send_expire_cookie']) { $this->expireSessionCookie(); } if ($options['clear_storage']) { $this->getStorage()->clear(); } } /** * Write session to save handler and close * * Once done, the Storage object will be marked as isImmutable. * * @return void */ public function writeClose() { // The assumption is that we're using PHP's ext/session. // session_write_close() will actually overwrite $_SESSION with an // empty array on completion -- which leads to a mismatch between what // is in the storage object and $_SESSION. To get around this, we // temporarily reset $_SESSION to an array, and then re-link it to // the storage object. // // Additionally, while you _can_ write to $_SESSION following a // session_write_close() operation, no changes made to it will be // flushed to the session handler. As such, we now mark the storage // object isImmutable. $storage = $this->getStorage(); if (!$storage->isImmutable()) { $_SESSION = $storage->toArray(true); session_write_close(); $storage->fromArray($_SESSION); $storage->markImmutable(); } } /** * Attempt to set the session name * * If the session has already been started, or if the name provided fails * validation, an exception will be raised. * * @param string $name * @return SessionManager * @throws Exception\InvalidArgumentException */ public function setName($name) { if ($this->sessionExists()) { throw new Exception\InvalidArgumentException( 'Cannot set session name after a session has already started' ); } if (!preg_match('/^[a-zA-Z0-9]+$/', $name)) { throw new Exception\InvalidArgumentException( 'Name provided contains invalid characters; must be alphanumeric only' ); } $this->name = $name; session_name($name); return $this; } /** * Get session name * * Proxies to {@link session_name()}. * * @return string */ public function getName() { if (null === $this->name) { // If we're grabbing via session_name(), we don't need our // validation routine; additionally, calling setName() after // session_start() can lead to issues, and often we just need the name // in order to do things such as setting cookies. $this->name = session_name(); } return $this->name; } /** * Set session ID * * Can safely be called in the middle of a session. * * @param string $id * @return SessionManager */ public function setId($id) { if ($this->sessionExists()) { throw new Exception\RuntimeException('Session has already been started, to change the session ID call regenerateId()'); } session_id($id); return $this; } /** * Get session ID * * Proxies to {@link session_id()} * * @return string */ public function getId() { return session_id(); } /** * Regenerate id * * Regenerate the session ID, using session save handler's * native ID generation Can safely be called in the middle of a session. * * @param bool $deleteOldSession * @return SessionManager */ public function regenerateId($deleteOldSession = true) { session_regenerate_id((bool) $deleteOldSession); return $this; } /** * Set the TTL (in seconds) for the session cookie expiry * * Can safely be called in the middle of a session. * * @param null|int $ttl * @return SessionManager */ public function rememberMe($ttl = null) { if (null === $ttl) { $ttl = $this->getConfig()->getRememberMeSeconds(); } $this->setSessionCookieLifetime($ttl); return $this; } /** * Set a 0s TTL for the session cookie * * Can safely be called in the middle of a session. * * @return SessionManager */ public function forgetMe() { $this->setSessionCookieLifetime(0); return $this; } /** * Set the validator chain to use when validating a session * * In most cases, you should use an instance of {@link ValidatorChain}. * * @param EventManagerInterface $chain * @return SessionManager */ public function setValidatorChain(EventManagerInterface $chain) { $this->validatorChain = $chain; return $this; } /** * Get the validator chain to use when validating a session * * By default, uses an instance of {@link ValidatorChain}. * * @return EventManagerInterface */ public function getValidatorChain() { if (null === $this->validatorChain) { $this->setValidatorChain(new ValidatorChain($this->getStorage())); } return $this->validatorChain; } /** * Is this session valid? * * Notifies the Validator Chain until either all validators have returned * true or one has failed. * * @return bool */ public function isValid() { $validator = $this->getValidatorChain(); $responses = $validator->triggerUntil('session.validate', $this, array($this), function ($test) { return !$test; }); if ($responses->stopped()) { // If execution was halted, validation failed return false; } // Otherwise, we're good to go return true; } /** * Expire the session cookie * * Sends a session cookie with no value, and with an expiry in the past. * * @return void */ public function expireSessionCookie() { $config = $this->getConfig(); if (!$config->getUseCookies()) { return; } setcookie( $this->getName(), // session name '', // value $_SERVER['REQUEST_TIME'] - 42000, // TTL for cookie $config->getCookiePath(), $config->getCookieDomain(), $config->getCookieSecure(), $config->getCookieHttpOnly() ); } /** * Set the session cookie lifetime * * If a session already exists, destroys it (without sending an expiration * cookie), regenerates the session ID, and restarts the session. * * @param int $ttl * @return void */ protected function setSessionCookieLifetime($ttl) { $config = $this->getConfig(); if (!$config->getUseCookies()) { return; } // Set new cookie TTL $config->setCookieLifetime($ttl); if ($this->sessionExists()) { // There is a running session so we'll regenerate id to send a new cookie $this->regenerateId(); } } /** * Register Save Handler with ext/session * * Since ext/session is coupled to this particular session manager * register the save handler with ext/session. * * @param SaveHandler\SaveHandlerInterface $saveHandler * @return bool */ protected function registerSaveHandler(SaveHandler\SaveHandlerInterface $saveHandler) { return session_set_save_handler( array($saveHandler, 'open'), array($saveHandler, 'close'), array($saveHandler, 'read'), array($saveHandler, 'write'), array($saveHandler, 'destroy'), array($saveHandler, 'gc') ); } } |