You are here

class NativeSessionStorage in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage

This provides a base class for session attribute storage.

@author Drak <drak@zikula.org>

Hierarchy

Expanded class hierarchy of NativeSessionStorage

5 files declare their use of NativeSessionStorage
NativeFileSessionHandlerTest.php in vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php
NativeSessionStorageTest.php in vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php
NullSessionHandlerTest.php in vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php
Session.php in vendor/symfony/http-foundation/Session/Session.php
SessionManager.php in core/lib/Drupal/Core/Session/SessionManager.php
Contains \Drupal\Core\Session\SessionManager.

File

vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php, line 25

Namespace

Symfony\Component\HttpFoundation\Session\Storage
View source
class NativeSessionStorage implements SessionStorageInterface {

  /**
   * Array of SessionBagInterface.
   *
   * @var SessionBagInterface[]
   */
  protected $bags;

  /**
   * @var bool
   */
  protected $started = false;

  /**
   * @var bool
   */
  protected $closed = false;

  /**
   * @var AbstractProxy
   */
  protected $saveHandler;

  /**
   * @var MetadataBag
   */
  protected $metadataBag;

  /**
   * Constructor.
   *
   * Depending on how you want the storage driver to behave you probably
   * want to override this constructor entirely.
   *
   * List of options for $options array with their defaults.
   *
   * @see http://php.net/session.configuration for options
   * but we omit 'session.' from the beginning of the keys for convenience.
   *
   * ("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).
   *
   * cache_limiter, "" (use "0" to prevent headers from being sent entirely).
   * 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="
   *
   * @param array                                                            $options Session configuration options.
   * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $handler
   * @param MetadataBag                                                      $metaBag MetadataBag.
   */
  public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null) {
    session_cache_limiter('');

    // disable by default because it's managed by HeaderBag (if used)
    ini_set('session.use_cookies', 1);
    if (PHP_VERSION_ID >= 50400) {
      session_register_shutdown();
    }
    else {
      register_shutdown_function('session_write_close');
    }
    $this
      ->setMetadataBag($metaBag);
    $this
      ->setOptions($options);
    $this
      ->setSaveHandler($handler);
  }

  /**
   * Gets the save handler instance.
   *
   * @return AbstractProxy
   */
  public function getSaveHandler() {
    return $this->saveHandler;
  }

  /**
   * {@inheritdoc}
   */
  public function start() {
    if ($this->started) {
      return true;
    }
    if (PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE === session_status()) {
      throw new \RuntimeException('Failed to start the session: already started by PHP.');
    }
    if (PHP_VERSION_ID < 50400 && !$this->closed && 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).');
    }
    if (ini_get('session.use_cookies') && headers_sent($file, $line)) {
      throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
    }

    // ok to try and start the session
    if (!session_start()) {
      throw new \RuntimeException('Failed to start the session');
    }
    $this
      ->loadSession();
    if (!$this->saveHandler
      ->isWrapper() && !$this->saveHandler
      ->isSessionHandlerInterface()) {

      // This condition matches only PHP 5.3 with internal save handlers
      $this->saveHandler
        ->setActive(true);
    }
    return true;
  }

  /**
   * {@inheritdoc}
   */
  public function getId() {
    return $this->saveHandler
      ->getId();
  }

  /**
   * {@inheritdoc}
   */
  public function setId($id) {
    $this->saveHandler
      ->setId($id);
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return $this->saveHandler
      ->getName();
  }

  /**
   * {@inheritdoc}
   */
  public function setName($name) {
    $this->saveHandler
      ->setName($name);
  }

  /**
   * {@inheritdoc}
   */
  public function regenerate($destroy = false, $lifetime = null) {

    // Cannot regenerate the session ID for non-active sessions.
    if (PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE !== session_status()) {
      return false;
    }

    // Check if session ID exists in PHP 5.3
    if (PHP_VERSION_ID < 50400 && '' === session_id()) {
      return false;
    }
    if (null !== $lifetime) {
      ini_set('session.cookie_lifetime', $lifetime);
    }
    if ($destroy) {
      $this->metadataBag
        ->stampNew();
    }
    $isRegenerated = session_regenerate_id($destroy);

    // The reference to $_SESSION in session bags is lost in PHP7 and we need to re-create it.
    // @see https://bugs.php.net/bug.php?id=70013
    $this
      ->loadSession();
    return $isRegenerated;
  }

  /**
   * {@inheritdoc}
   */
  public function save() {
    session_write_close();
    if (!$this->saveHandler
      ->isWrapper() && !$this->saveHandler
      ->isSessionHandlerInterface()) {

      // This condition matches only PHP 5.3 with internal save handlers
      $this->saveHandler
        ->setActive(false);
    }
    $this->closed = true;
    $this->started = false;
  }

  /**
   * {@inheritdoc}
   */
  public function clear() {

    // clear out the bags
    foreach ($this->bags as $bag) {
      $bag
        ->clear();
    }

    // clear out the session
    $_SESSION = array();

    // reconnect the bags to the session
    $this
      ->loadSession();
  }

  /**
   * {@inheritdoc}
   */
  public function registerBag(SessionBagInterface $bag) {
    $this->bags[$bag
      ->getName()] = $bag;
  }

  /**
   * {@inheritdoc}
   */
  public function getBag($name) {
    if (!isset($this->bags[$name])) {
      throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
    }
    if ($this->saveHandler
      ->isActive() && !$this->started) {
      $this
        ->loadSession();
    }
    elseif (!$this->started) {
      $this
        ->start();
    }
    return $this->bags[$name];
  }

  /**
   * Sets the MetadataBag.
   *
   * @param MetadataBag $metaBag
   */
  public function setMetadataBag(MetadataBag $metaBag = null) {
    if (null === $metaBag) {
      $metaBag = new MetadataBag();
    }
    $this->metadataBag = $metaBag;
  }

  /**
   * Gets the MetadataBag.
   *
   * @return MetadataBag
   */
  public function getMetadataBag() {
    return $this->metadataBag;
  }

  /**
   * {@inheritdoc}
   */
  public function isStarted() {
    return $this->started;
  }

  /**
   * Sets session.* ini variables.
   *
   * For convenience we omit 'session.' from the beginning of the keys.
   * Explicitly ignores other ini keys.
   *
   * @param array $options Session ini directives array(key => value).
   *
   * @see http://php.net/session.configuration
   */
  public function setOptions(array $options) {
    $validOptions = array_flip(array(
      'cache_limiter',
      'cookie_domain',
      'cookie_httponly',
      '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',
      'upload_progress.freq',
      'upload_progress.min-freq',
      'url_rewriter.tags',
    ));
    foreach ($options as $key => $value) {
      if (isset($validOptions[$key])) {
        ini_set('session.' . $key, $value);
      }
    }
  }

  /**
   * Registers session save handler as a PHP session handler.
   *
   * To use internal PHP session save handlers, override this method using ini_set with
   * session.save_handler and session.save_path e.g.
   *
   *     ini_set('session.save_handler', 'files');
   *     ini_set('session.save_path', /tmp');
   *
   * 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
   *
   * @see http://php.net/session-set-save-handler
   * @see http://php.net/sessionhandlerinterface
   * @see http://php.net/sessionhandler
   * @see http://github.com/drak/NativeSession
   *
   * @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $saveHandler
   *
   * @throws \InvalidArgumentException
   */
  public function setSaveHandler($saveHandler = null) {
    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
    if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
      $saveHandler = new SessionHandlerProxy($saveHandler);
    }
    elseif (!$saveHandler instanceof AbstractProxy) {
      $saveHandler = PHP_VERSION_ID >= 50400 ? new SessionHandlerProxy(new \SessionHandler()) : new NativeProxy();
    }
    $this->saveHandler = $saveHandler;
    if ($this->saveHandler instanceof \SessionHandlerInterface) {
      if (PHP_VERSION_ID >= 50400) {
        session_set_save_handler($this->saveHandler, false);
      }
      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',
        ));
      }
    }
  }

  /**
   * Load the session with attributes.
   *
   * After starting the session, PHP retrieves the session from whatever handlers
   * 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
   * and populates $_SESSION with the result automatically.
   *
   * @param array|null $session
   */
  protected function loadSession(array &$session = null) {
    if (null === $session) {
      $session =& $_SESSION;
    }
    $bags = array_merge($this->bags, array(
      $this->metadataBag,
    ));
    foreach ($bags as $bag) {
      $key = $bag
        ->getStorageKey();
      $session[$key] = isset($session[$key]) ? $session[$key] : array();
      $bag
        ->initialize($session[$key]);
    }
    $this->started = true;
    $this->closed = false;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
NativeSessionStorage::$bags protected property Array of SessionBagInterface.
NativeSessionStorage::$closed protected property
NativeSessionStorage::$metadataBag protected property
NativeSessionStorage::$saveHandler protected property
NativeSessionStorage::$started protected property
NativeSessionStorage::clear public function Clear all session data in memory. Overrides SessionStorageInterface::clear 1
NativeSessionStorage::getBag public function Gets a SessionBagInterface by name. Overrides SessionStorageInterface::getBag
NativeSessionStorage::getId public function Returns the session ID. Overrides SessionStorageInterface::getId
NativeSessionStorage::getMetadataBag public function Gets the MetadataBag. Overrides SessionStorageInterface::getMetadataBag
NativeSessionStorage::getName public function Returns the session name. Overrides SessionStorageInterface::getName
NativeSessionStorage::getSaveHandler public function Gets the save handler instance.
NativeSessionStorage::isStarted public function Checks if the session is started. Overrides SessionStorageInterface::isStarted
NativeSessionStorage::loadSession protected function Load the session with attributes.
NativeSessionStorage::regenerate public function Regenerates id that represents this storage. Overrides SessionStorageInterface::regenerate 1
NativeSessionStorage::registerBag public function Registers a SessionBagInterface for use. Overrides SessionStorageInterface::registerBag
NativeSessionStorage::save public function Force the session to be saved and closed. Overrides SessionStorageInterface::save 1
NativeSessionStorage::setId public function Sets the session ID. Overrides SessionStorageInterface::setId
NativeSessionStorage::setMetadataBag public function Sets the MetadataBag.
NativeSessionStorage::setName public function Sets the session name. Overrides SessionStorageInterface::setName
NativeSessionStorage::setOptions public function Sets session.* ini variables.
NativeSessionStorage::setSaveHandler public function Registers session save handler as a PHP session handler.
NativeSessionStorage::start public function Starts the session. Overrides SessionStorageInterface::start 2
NativeSessionStorage::__construct public function Constructor. 2