You are here

class MongodbSessionHandler in MongoDB 8

Hierarchy

Expanded class hierarchy of MongodbSessionHandler

1 string reference to 'MongodbSessionHandler'
mongodb_user.services.yml in mongodb_user/mongodb_user.services.yml
mongodb_user/mongodb_user.services.yml
1 service uses MongodbSessionHandler
mongodb.session_handler.storage in mongodb_user/mongodb_user.services.yml
Drupal\mongodb_user\MongodbSessionHandler

File

mongodb_user/src/MongodbSessionHandler.php, line 19
Contains \Drupal\mongodb_user\MongodbSessionHandler.

Namespace

Drupal\mongodb_user
View source
class MongodbSessionHandler extends SessionHandler implements \SessionHandlerInterface {

  /**
   * @var \Drupal\mongodb\MongoCollectionFactory
   */
  protected $mongo;

  /**
   * @param RequestStack $request_stack
   * @param MongoCollectionFactory $mongo
   */
  public function __construct(RequestStack $request_stack, MongoCollectionFactory $mongo) {
    $this->requestStack = $request_stack;
    $this->mongo = $mongo;
    $this->connection = new FakeConnection([]);
  }

  /**
   * {@inheritdoc}
   */
  public function read($sid) {
    global $_session_user;

    // Handle the case of first time visitors and clients that don't store
    // cookies (eg. web crawlers).
    $cookies = $this->requestStack
      ->getCurrentRequest()->cookies;
    if (empty($sid) || !$cookies
      ->has($this
      ->getName())) {
      $_session_user = new UserSession();
      return '';
    }

    // Try to load a session using the non-HTTPS session id.
    $values = $this
      ->findOne([
      'sid' => Crypt::hashBase64($sid),
    ]);

    // We found the client's session record and they are an authenticated,
    // active user.
    if ($values && $values['uid'] > 0 && $values['status'] == 1) {
      $values['roles'][] = DRUPAL_AUTHENTICATED_RID;
      $_session_user = new UserSession($values);
    }
    elseif ($values) {

      // The user is anonymous or blocked. Only preserve two fields from the
      // {sessions} table.
      $_session_user = new UserSession(array(
        'session' => $values['session'],
        'access' => $values['access'],
      ));
    }
    else {

      // The session has expired.
      $_session_user = new UserSession();
    }
    return $_session_user->session;
  }

  /**
   * Tries to find a session and an according user.
   *
   * @param $conditions
   * @return array|mixed|null
   */
  protected function findOne($conditions) {
    $session = $this
      ->mongoCollection()
      ->findOne($conditions);
    if ($session) {
      $query['values.default_langcode.value'] = 1;
      $query['_id'] = $session['uid'];
      if ($user_record = $this->mongo
        ->get('entity.user')
        ->findOne($query, [
        'session',
      ])) {
        $session += $user_record['session'];
      }
      else {
        $session = FALSE;
      }
    }
    return $session;
  }

  /**
   * {@inheritdoc}
   */
  public function write($sid, $value) {
    $user = \Drupal::currentUser();

    // The exception handler is not active at this point, so we need to do it
    // manually.
    try {

      // sid will be added from $key below.
      $fields = array(
        'uid' => $user
          ->id(),
        'hostname' => $this->requestStack
          ->getCurrentRequest()
          ->getClientIP(),
        'session' => $value,
        'timestamp' => REQUEST_TIME,
      );
      $key = array(
        'sid' => Crypt::hashBase64($sid),
      );
      $this
        ->mongoCollection()
        ->update($key, $key + $fields, array(
        'upsert' => TRUE,
      ));

      // Remove obsolete sessions.
      $this
        ->cleanupObsoleteSessions();

      // Likewise, do not update access time more than once per 180 seconds.
      if ($user
        ->isAuthenticated() && REQUEST_TIME - $user
        ->getLastAccessedTime() > Settings::get('session_write_interval', 180)) {

        /** @var \Drupal\user\UserStorageInterface $storage */
        $storage = \Drupal::entityManager()
          ->getStorage('user');
        $storage
          ->updateLastAccessTimestamp($user, REQUEST_TIME);
      }
      return TRUE;
    } catch (\Exception $exception) {
      require_once DRUPAL_ROOT . '/core/includes/errors.inc';

      // If we are displaying errors, then do so with no possibility of a
      // further uncaught exception being thrown.
      if (error_displayable()) {
        print '<h1>Uncaught exception thrown in session handler.</h1>';
        print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
      }
      return FALSE;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function close() {
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function destroy($sid) {
    $this
      ->removeSession($sid);
    return parent::destroy($sid);
  }

  /**
   * {@inheritdoc}
   */
  public function gc($lifetime) {

    // Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
    // value. For example, if you want user sessions to stay in your database
    // for three weeks before deleting them, you need to set gc_maxlifetime
    // to '1814400'. At that value, only after a user doesn't log in after
    // three weeks (1814400 seconds) will his/her session be removed.
    $condition['timestamp']['$lt'] = REQUEST_TIME - $lifetime;
    $this
      ->mongoCollection()
      ->remove($condition);
    return TRUE;
  }

  /**
   * Remove a session from the database.
   */
  protected function removeSession($sid) {
    $this
      ->mongoCollection()
      ->remove([
      'sid' => Crypt::hashBase64($sid),
    ]);
  }

  /**
   * Remove sessions marked for garbage collection.
   */
  protected function cleanupObsoleteSessions() {
    array_walk($this->obsoleteSessionIds, [
      $this,
      'removeSession',
    ]);
  }

  /**
   * return \MongoCollection
   */
  protected function mongoCollection() {
    return $this->mongo
      ->get('sessions');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
MongodbSessionHandler::$mongo protected property
MongodbSessionHandler::cleanupObsoleteSessions protected function Remove sessions marked for garbage collection.
MongodbSessionHandler::close public function Overrides SessionHandler::close
MongodbSessionHandler::destroy public function Overrides SessionHandler::destroy
MongodbSessionHandler::findOne protected function Tries to find a session and an according user.
MongodbSessionHandler::gc public function Overrides SessionHandler::gc
MongodbSessionHandler::mongoCollection protected function return \MongoCollection
MongodbSessionHandler::read public function Overrides SessionHandler::read
MongodbSessionHandler::removeSession protected function Remove a session from the database.
MongodbSessionHandler::write public function Overrides SessionHandler::write
MongodbSessionHandler::__construct public function Overrides SessionHandler::__construct
SessionHandler::$connection protected property The database connection.
SessionHandler::$requestStack protected property The request stack.
SessionHandler::open public function