Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. PdoSessionHandler.php

function PdoSessionHandler::doRead

Reads the session data in respect to the different locking strategies.

We need to make sure we do not return session data that is already considered garbage according to the session.gc_maxlifetime setting because gc() is called after read() and only sometimes.

Overrides AbstractSessionHandler::doRead

File

vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php, line 617

Class

PdoSessionHandler
Session handler using a PDO connection to read and write data.

Namespace

Symfony\Component\HttpFoundation\Session\Storage\Handler

Code

protected function doRead(string $sessionId) : string {
    if (self::LOCK_ADVISORY === $this->lockMode) {
        $this->unlockStatements[] = $this->doAdvisoryLock($sessionId);
    }
    $selectSql = $this->getSelectSql();
    $selectStmt = $this->pdo
        ->prepare($selectSql);
    $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
    $insertStmt = null;
    while (true) {
        $selectStmt->execute();
        $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
        if ($sessionRows) {
            $expiry = (int) $sessionRows[0][1];
            if ($expiry < time()) {
                $this->sessionExpired = true;
                return '';
            }
            return \is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
        }
        if (null !== $insertStmt) {
            $this->rollback();
            throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.');
        }
        if (!filter_var(\ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOL) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
            // In strict mode, session fixation is not possible: new sessions always start with a unique
            // random id, so that concurrency is not possible and this code path can be skipped.
            // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
            // until other connections to the session are committed.
            try {
                $insertStmt = $this->getInsertStatement($sessionId, '', 0);
                $insertStmt->execute();
            } catch (\PDOException $e) {
                // Catch duplicate key error because other connection created the session already.
                // It would only not be the case when the other connection destroyed the session.
                if (str_starts_with($e->getCode(), '23')) {
                    // Retrieve finished session data written by concurrent connection by restarting the loop.
                    // We have to start a new transaction as a failed query will mark the current transaction as
                    // aborted in PostgreSQL and disallow further queries within it.
                    $this->rollback();
                    $this->beginTransaction();
                    continue;
                }
                throw $e;
            }
        }
        return '';
    }
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal