You are here

abstract class SessionProxy_Backend_Base in Session Proxy 7

Hierarchy

Expanded class hierarchy of SessionProxy_Backend_Base

File

lib/SessionProxy/Backend/Base.php, line 3

View source
abstract class SessionProxy_Backend_Base implements SessionProxy_Backend_Interface {

  /**
   * @var bool
   */
  protected $httpsEnabled = FALSE;

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

  /**
   * @var string
   */
  protected $sessionIdentifier;

  /**
   * @var string
   */
  protected $sessionName;

  /**
   * @var string
   */
  protected $sessionNameUnsecure;

  /**
   * @var bool
   */
  protected $userAccessUpdated = FALSE;

  /**
   * Generate new session identifier, set it as PHP session identifier and
   * return it.
   *
   * @return string
   */
  protected function generateSessionIdentifier() {
    $this->sessionIdentifier = drupal_hash_base64(uniqid(mt_rand(), TRUE));

    // Depending on the underlaying implementation, some hash may fail to
    // achieve the session_start() especially if you are using the PHP native
    // one to handle session storage.
    $this->sessionIdentifier = str_replace('_', '-', $this->sessionIdentifier);
    session_id($this->sessionIdentifier);
    return $this->sessionIdentifier;
  }

  /**
   * Get the actual logged in user user identifier if any.
   *
   * @return int
   *   Valid user identifier or NULL.
   */
  protected abstract function getSessionUid();

  /**
   * Refresh global user data following the actual session state.
   */
  protected function updateUser() {
    global $user;
    $uid = $this
      ->getSessionUid();
    if (!empty($uid)) {
      $user = db_query("SELECT u.* FROM {users} u WHERE u.uid = :uid", array(
        ':uid' => $uid,
      ))
        ->fetchObject();
      if (1 == $user->status) {
        $user->data = unserialize($user->data);
        $user->roles = array();
        $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
        $user->roles += db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = :uid", array(
          ':uid' => $user->uid,
        ))
          ->fetchAllKeyed(0, 1);
      }
      else {
        $user = drupal_anonymous_user();
      }
    }
    else {
      $user = drupal_anonymous_user();
    }

    // The 'session' attribute is an insanity and should be removed.
    $user->session = '';
    $user->timestamp = REQUEST_TIME;

    // Avoid some PHP warnings with backends using it (mongodb module does
    // check it). Some backends may set this variable, if they keep it, some
    // other won't.
    if (!isset($user->cache)) {
      $user->cache = 0;
    }

    // Do not update access time more than once per 180 seconds. Also check
    // for an active database connection: actual core will have one, but in
    // the late future we may have session handling without database at all.
    if (!$this->userAccessUpdated && Database::isActiveConnection() && $user->uid && REQUEST_TIME - $user->access > variable_get('session_write_interval', 180)) {
      db_update('users')
        ->fields(array(
        'access' => REQUEST_TIME,
      ))
        ->condition('uid', $user->uid)
        ->execute();
      $this->userAccessUpdated = TRUE;
    }
  }

  /**
   * Refresh various information of the object right after session state
   * change.
   */
  protected function refreshAfterSessionChange() {
    $this
      ->updateUser();

    // FIXME: This should not live in user session, but as a reaction of
    // session creation or regeneration in user module.
    date_default_timezone_set(drupal_get_user_timezone());
  }

  /**
   * Is the current session is empty.
   *
   * @return bool
   */
  protected function sessionIsEmpty() {
    return !isset($_SESSION) || empty($_SESSION) || isset($_SESSION['uid']) && 1 == count($_SESSION);
  }
  public function isStarted() {
    return $this->started;
  }
  public function start() {

    // Command line clients do not support cookies nor sessions.
    if (!$this->started && !drupal_is_cli()) {
      if (!$this
        ->sessionIsEmpty()) {

        // Keep data from already set data, even if the session has not been
        // started yet, some pieces of software may have set $_SESSION super
        // global data before us: this is an artifact of the lazzy session
        // creation feature.
        $currentData = $_SESSION;
        session_start();
        $_SESSION += $currentData;
      }
      else {
        session_start();
      }
      $this->started = TRUE;
    }
  }
  public function handleHttps() {
    return FALSE;
  }
  public function commit() {
    global $user;
    if (!$this
      ->isWriteEnabled()) {
      return;
    }
    if ($user->uid) {

      // Always save logged in user sessions: we will let the underlaying
      // storage engine decide weither or not data should really be saved.
      session_write_close();
    }
    else {
      if (!empty($_SESSION)) {

        // Save session for anonymous only if session data has been se: this
        // is another lazzy session creation feature artifact.
        if (!$this->started) {
          $this
            ->start();
        }
        session_write_close();
      }
      else {

        // Drop anonymous session
        if ($this
          ->isStarted()) {
          $this
            ->destroy();
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function destroy() {
    $this->started = FALSE;
    session_destroy();
    $this
      ->deleteCurrentSessionCookie();
  }

  /**
   * Native implementation is opaque, and cannot allow us to index session: it
   * is impossible to proceed with this cleaning.
   *
   * @see SessionProxy_Backend_Interface::destroyAllForUser()
   */
  public function destroyAllForUser($uid) {
  }
  public function deleteCurrentSessionCookie() {
    SessionProxy_Helper::deleteSessionCookie($this->sessionName);
    if ($this->httpsEnabled) {
      SessionProxy_Helper::deleteSessionCookie($this->sessionNameUnsecure);
    }
  }

  /**
   * Default constructor.
   */
  public function __construct() {
    global $user, $is_https;
    $this->httpsEnabled = $this
      ->handleHttps() && $is_https;
    $this->sessionName = session_name();
    if ($this->httpsEnabled) {
      $this->sessionNameUnsecure = substr(session_name(), 1);
    }
    if (!empty($_COOKIE[$this->sessionName]) || $this->httpsEnabled && !empty($_COOKIE[$this->sessionNameUnsecure])) {

      // If a session cookie exists, initialize the session. Otherwise the
      // session is only started on demand in drupal_session_commit(), making
      // anonymous users not use a session cookie unless something is stored in
      // $_SESSION. This allows HTTP proxies to cache anonymous page views.
      $this
        ->start();
      $this->sessionIdentifier = session_id();
      $this
        ->refreshAfterSessionChange();
      if ($user->uid || !$this
        ->sessionIsEmpty()) {
        drupal_page_is_cacheable(FALSE);
      }
    }
    else {

      // Set a session identifier for this request. This is necessary because
      // we lazily start sessions at the end of this request, and some
      // processes (like drupal_get_token()) needs to know the future
      // session ID in advance.
      $user = drupal_anonymous_user();
      $this
        ->generateSessionIdentifier();
      $this
        ->refreshAfterSessionChange();
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SessionProxy_Backend_Base::$httpsEnabled protected property
SessionProxy_Backend_Base::$sessionIdentifier protected property
SessionProxy_Backend_Base::$sessionName protected property
SessionProxy_Backend_Base::$sessionNameUnsecure protected property
SessionProxy_Backend_Base::$started protected property
SessionProxy_Backend_Base::$userAccessUpdated protected property
SessionProxy_Backend_Base::commit public function Called during shutdown hook time, this allows you to perform additional operations outside of the core PHP session handling at the end of request. Overrides SessionProxy_Backend_Interface::commit
SessionProxy_Backend_Base::deleteCurrentSessionCookie public function Delete current session cookie Overrides SessionProxy_Backend_Interface::deleteCurrentSessionCookie
SessionProxy_Backend_Base::destroy public function Destroy session if any Overrides SessionProxy_Backend_Interface::destroy 1
SessionProxy_Backend_Base::destroyAllForUser public function Native implementation is opaque, and cannot allow us to index session: it is impossible to proceed with this cleaning. Overrides SessionProxy_Backend_Interface::destroyAllForUser 2
SessionProxy_Backend_Base::generateSessionIdentifier protected function Generate new session identifier, set it as PHP session identifier and return it.
SessionProxy_Backend_Base::getSessionUid abstract protected function Get the actual logged in user user identifier if any. 2
SessionProxy_Backend_Base::handleHttps public function Does this instance handle HTTPS diverging session name. Overrides SessionProxy_Backend_Interface::handleHttps 1
SessionProxy_Backend_Base::isStarted public function Is session started. Overrides SessionProxy_Backend_Interface::isStarted
SessionProxy_Backend_Base::refreshAfterSessionChange protected function Refresh various information of the object right after session state change.
SessionProxy_Backend_Base::sessionIsEmpty protected function Is the current session is empty.
SessionProxy_Backend_Base::start public function Start session. Overrides SessionProxy_Backend_Interface::start
SessionProxy_Backend_Base::updateUser protected function Refresh global user data following the actual session state.
SessionProxy_Backend_Base::__construct public function Default constructor. 1
SessionProxy_Backend_Interface::isWriteEnabled public function Is session write enabled. 2
SessionProxy_Backend_Interface::regenerate public function Regenerate the current session. 2
SessionProxy_Backend_Interface::writeDisable public function Enable session writing explicitely. 2
SessionProxy_Backend_Interface::writeEnable public function Disable session writing explicitely. 2