Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

LegacyPdoSessionHandler.php

Zuletzt modifiziert: 09.10.2024, 12:58 - Dateigröße: 10.01 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of the Symfony package.
 005   *
 006   * (c) Fabien Potencier <fabien@symfony.com>
 007   *
 008   * For the full copyright and license information, please view the LICENSE
 009   * file that was distributed with this source code.
 010   */
 011   
 012  namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
 013   
 014  @trigger_error('The '.__NAMESPACE__.'\LegacyPdoSessionHandler class is deprecated since version 2.6 and will be removed in 3.0. Use the Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler class instead.', E_USER_DEPRECATED);
 015   
 016  /**
 017   * Session handler using a PDO connection to read and write data.
 018   *
 019   * Session data is a binary string that can contain non-printable characters like the null byte.
 020   * For this reason this handler base64 encodes the data to be able to save it in a character column.
 021   *
 022   * This version of the PdoSessionHandler does NOT implement locking. So concurrent requests to the
 023   * same session can result in data loss due to race conditions.
 024   *
 025   * @author Fabien Potencier <fabien@symfony.com>
 026   * @author Michael Williams <michael.williams@funsational.com>
 027   * @author Tobias Schultze <http://tobion.de>
 028   *
 029   * @deprecated since version 2.6, to be removed in 3.0. Use
 030   *             {@link PdoSessionHandler} instead.
 031   */
 032  class LegacyPdoSessionHandler implements \SessionHandlerInterface
 033  {
 034      /**
 035       * @var \PDO PDO instance
 036       */
 037      private $pdo;
 038   
 039      /**
 040       * @var string Table name
 041       */
 042      private $table;
 043   
 044      /**
 045       * @var string Column for session id
 046       */
 047      private $idCol;
 048   
 049      /**
 050       * @var string Column for session data
 051       */
 052      private $dataCol;
 053   
 054      /**
 055       * @var string Column for timestamp
 056       */
 057      private $timeCol;
 058   
 059      /**
 060       * Constructor.
 061       *
 062       * List of available options:
 063       *  * db_table: The name of the table [required]
 064       *  * db_id_col: The column where to store the session id [default: sess_id]
 065       *  * db_data_col: The column where to store the session data [default: sess_data]
 066       *  * db_time_col: The column where to store the timestamp [default: sess_time]
 067       *
 068       * @param \PDO  $pdo       A \PDO instance
 069       * @param array $dbOptions An associative array of DB options
 070       *
 071       * @throws \InvalidArgumentException When "db_table" option is not provided
 072       */
 073      public function __construct(\PDO $pdo, array $dbOptions = array())
 074      {
 075          if (!array_key_exists('db_table', $dbOptions)) {
 076              throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
 077          }
 078          if (\PDO::ERRMODE_EXCEPTION !== $pdo->getAttribute(\PDO::ATTR_ERRMODE)) {
 079              throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION))', __CLASS__));
 080          }
 081   
 082          $this->pdo = $pdo;
 083          $dbOptions = array_merge(array(
 084              'db_id_col' => 'sess_id',
 085              'db_data_col' => 'sess_data',
 086              'db_time_col' => 'sess_time',
 087          ), $dbOptions);
 088   
 089          $this->table = $dbOptions['db_table'];
 090          $this->idCol = $dbOptions['db_id_col'];
 091          $this->dataCol = $dbOptions['db_data_col'];
 092          $this->timeCol = $dbOptions['db_time_col'];
 093      }
 094   
 095      /**
 096       * {@inheritdoc}
 097       */
 098      public function open($savePath, $sessionName)
 099      {
 100          return true;
 101      }
 102   
 103      /**
 104       * {@inheritdoc}
 105       */
 106      public function close()
 107      {
 108          return true;
 109      }
 110   
 111      /**
 112       * {@inheritdoc}
 113       */
 114      public function destroy($sessionId)
 115      {
 116          // delete the record associated with this id
 117          $sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
 118   
 119          try {
 120              $stmt = $this->pdo->prepare($sql);
 121              $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
 122              $stmt->execute();
 123          } catch (\PDOException $e) {
 124              throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
 125          }
 126   
 127          return true;
 128      }
 129   
 130      /**
 131       * {@inheritdoc}
 132       */
 133      public function gc($maxlifetime)
 134      {
 135          // delete the session records that have expired
 136          $sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
 137   
 138          try {
 139              $stmt = $this->pdo->prepare($sql);
 140              $stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT);
 141              $stmt->execute();
 142          } catch (\PDOException $e) {
 143              throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
 144          }
 145   
 146          return true;
 147      }
 148   
 149      /**
 150       * {@inheritdoc}
 151       */
 152      public function read($sessionId)
 153      {
 154          $sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
 155   
 156          try {
 157              $stmt = $this->pdo->prepare($sql);
 158              $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
 159              $stmt->execute();
 160   
 161              // We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
 162              $sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM);
 163   
 164              if ($sessionRows) {
 165                  return base64_decode($sessionRows[0][0]);
 166              }
 167   
 168              return '';
 169          } catch (\PDOException $e) {
 170              throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
 171          }
 172      }
 173   
 174      /**
 175       * {@inheritdoc}
 176       */
 177      public function write($sessionId, $data)
 178      {
 179          $encoded = base64_encode($data);
 180   
 181          try {
 182              // We use a single MERGE SQL query when supported by the database.
 183              $mergeSql = $this->getMergeSql();
 184   
 185              if (null !== $mergeSql) {
 186                  $mergeStmt = $this->pdo->prepare($mergeSql);
 187                  $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
 188                  $mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
 189                  $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
 190                  $mergeStmt->execute();
 191   
 192                  return true;
 193              }
 194   
 195              $updateStmt = $this->pdo->prepare(
 196                  "UPDATE $this->table SET $this->dataCol = :data, $this->timeCol = :time WHERE $this->idCol = :id"
 197              );
 198              $updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
 199              $updateStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
 200              $updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
 201              $updateStmt->execute();
 202   
 203              // When MERGE is not supported, like in Postgres, we have to use this approach that can result in
 204              // duplicate key errors when the same session is written simultaneously. We can just catch such an
 205              // error and re-execute the update. This is similar to a serializable transaction with retry logic
 206              // on serialization failures but without the overhead and without possible false positives due to
 207              // longer gap locking.
 208              if (!$updateStmt->rowCount()) {
 209                  try {
 210                      $insertStmt = $this->pdo->prepare(
 211                          "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
 212                      );
 213                      $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
 214                      $insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
 215                      $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
 216                      $insertStmt->execute();
 217                  } catch (\PDOException $e) {
 218                      // Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
 219                      if (0 === strpos($e->getCode(), '23')) {
 220                          $updateStmt->execute();
 221                      } else {
 222                          throw $e;
 223                      }
 224                  }
 225              }
 226          } catch (\PDOException $e) {
 227              throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
 228          }
 229   
 230          return true;
 231      }
 232   
 233      /**
 234       * Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database.
 235       *
 236       * @return string|null The SQL string or null when not supported
 237       */
 238      private function getMergeSql()
 239      {
 240          $driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
 241   
 242          switch ($driver) {
 243              case 'mysql':
 244                  return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
 245                  "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)";
 246              case 'oci':
 247                  // DUAL is Oracle specific dummy table
 248                  return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ".
 249                  "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
 250                  "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time";
 251              case 'sqlsrv' === $driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
 252                  // MERGE is only available since SQL Server 2008 and must be terminated by semicolon
 253                  // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
 254                  return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ".
 255                  "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
 256                  "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time;";
 257              case 'sqlite':
 258                  return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)";
 259          }
 260      }
 261   
 262      /**
 263       * Return a PDO instance.
 264       *
 265       * @return \PDO
 266       */
 267      protected function getConnection()
 268      {
 269          return $this->pdo;
 270      }
 271  }
 272