From ccdfbe6628eb279c5bad457017550c688b9ffc83 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 16 Apr 2014 16:52:07 +0200 Subject: [PATCH 1/2] [Doctrine Bridge] fix DbalSessionHandler for high concurrency, interface compliance, compatibility with all drivers (oci8, mysqli, pdo with mysql, sqlsrv, sqlite) --- .../HttpFoundation/DbalSessionHandler.php | 201 ++++++++++++------ 1 file changed, 135 insertions(+), 66 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php index f2ad6fcfeb..0c1436fa9c 100644 --- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php +++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php @@ -11,37 +11,65 @@ namespace Symfony\Bridge\Doctrine\HttpFoundation; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\Mysqli\MysqliConnection; +use Doctrine\DBAL\Driver\OCI8\OCI8Connection; +use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\Driver\SQLSrv\SQLSrvConnection; use Doctrine\DBAL\Platforms\MySqlPlatform; -use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; /** * DBAL based session storage. * + * This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + * but uses the Doctrine driver connection interface for non-PDO-based drivers like mysqli or OCI8. + * It is recommended to use the wrapper Doctrine\DBAL\Connection for lazy connections and optimized database-specific queries. + * * @author Fabien Potencier * @author Johannes M. Schmitt + * @author Tobias Schultze */ class DbalSessionHandler implements \SessionHandlerInterface { /** - * @var Connection + * @var DriverConnection */ private $con; /** * @var string */ - private $tableName; + private $table; + + /** + * @var string Column for session id + */ + private $idCol = 'sess_id'; + + /** + * @var string Column for session data + */ + private $dataCol = 'sess_data'; + + /** + * @var string Column for timestamp + */ + private $timeCol = 'sess_time'; /** * Constructor. * - * @param Connection $con An instance of Connection. - * @param string $tableName Table name. + * @param DriverConnection $con A driver connection, preferably a wrapper Doctrine\DBAL\Connection + * @param string $tableName Table name */ - public function __construct(Connection $con, $tableName = 'sessions') + public function __construct(DriverConnection $con, $tableName = 'sessions') { $this->con = $con; - $this->tableName = $tableName; + $this->table = $tableName; } /** @@ -57,7 +85,6 @@ class DbalSessionHandler implements \SessionHandlerInterface */ public function close() { - // do nothing return true; } @@ -66,12 +93,15 @@ class DbalSessionHandler implements \SessionHandlerInterface */ public function destroy($id) { + // delete the record associated with this id + $sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; + try { - $this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_id = :id", array( - 'id' => $id, - )); - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e); + $stmt = $this->con->prepare($sql); + $stmt->bindParam(':id', $id, \PDO::PARAM_STR); + $stmt->execute(); + } catch (\Exception $e) { + throw new \RuntimeException(sprintf('Exception was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e); } return true; @@ -82,12 +112,15 @@ class DbalSessionHandler implements \SessionHandlerInterface */ public function gc($lifetime) { + // delete the session records that have expired + $sql = "DELETE FROM $this->table WHERE $this->timeCol < :time"; + try { - $this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_time < :time", array( - 'time' => time() - $lifetime, - )); - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e); + $stmt = $this->con->prepare($sql); + $stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT); + $stmt->execute(); + } catch (\Exception $e) { + throw new \RuntimeException(sprintf('Exception was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e); } return true; @@ -98,21 +131,23 @@ class DbalSessionHandler implements \SessionHandlerInterface */ public function read($id) { - try { - $data = $this->con->executeQuery("SELECT sess_data FROM {$this->tableName} WHERE sess_id = :id", array( - 'id' => $id, - ))->fetchColumn(); + $sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id"; - if (false !== $data) { - return base64_decode($data); + try { + $stmt = $this->con->prepare($sql); + $stmt->bindParam(':id', $id, \PDO::PARAM_STR); + $stmt->execute(); + + // We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed + $sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM); + + if ($sessionRows) { + return base64_decode($sessionRows[0][0]); } - // session does not exist, create it - $this->createNewSession($id); - return ''; - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e); + } catch (\Exception $e) { + throw new \RuntimeException(sprintf('Exception was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e); } } @@ -121,54 +156,88 @@ class DbalSessionHandler implements \SessionHandlerInterface */ public function write($id, $data) { - $platform = $this->con->getDatabasePlatform(); + // Session data can contain non binary safe characters so we need to encode it. + $encoded = base64_encode($data); - // this should maybe be abstracted in Doctrine DBAL - if ($platform instanceof MySqlPlatform) { - $sql = "INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (%1\$s, %2\$s, %3\$d) " - ."ON DUPLICATE KEY UPDATE sess_data = VALUES(sess_data), sess_time = CASE WHEN sess_time = %3\$d THEN (VALUES(sess_time) + 1) ELSE VALUES(sess_time) END"; - } else { - $sql = "UPDATE {$this->tableName} SET sess_data = %2\$s, sess_time = %3\$d WHERE sess_id = %1\$s"; - } + // We use a MERGE SQL query when supported by the database. + // Otherwise we have to use a transactional DELETE followed by INSERT to prevent duplicate entries under high concurrency. try { - $rowCount = $this->con->exec(sprintf( - $sql, - $this->con->quote($id), - //session data can contain non binary safe characters so we need to encode it - $this->con->quote(base64_encode($data)), - time() - )); + $mergeSql = $this->getMergeSql(); - if (!$rowCount) { - // No session exists in the database to update. This happens when we have called - // session_regenerate_id() - $this->createNewSession($id, $data); + if (null !== $mergeSql) { + $mergeStmt = $this->con->prepare($mergeSql); + $mergeStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); + $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); + $mergeStmt->execute(); + + return true; } - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e); + + $this->con->beginTransaction(); + + try { + $deleteStmt = $this->con->prepare( + "DELETE FROM $this->table WHERE $this->idCol = :id" + ); + $deleteStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $deleteStmt->execute(); + + $insertStmt = $this->con->prepare( + "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)" + ); + $insertStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); + $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); + $insertStmt->execute(); + + $this->con->commit(); + } catch (\Exception $e) { + $this->con->rollback(); + + throw $e; + } + } catch (\Exception $e) { + throw new \RuntimeException(sprintf('Exception was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e); } return true; } - /** - * Creates a new session with the given $id and $data - * - * @param string $id - * @param string $data - * - * @return bool - */ - private function createNewSession($id, $data = '') + /** + * Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database. + * + * @return string|null The SQL string or null when not supported + */ + private function getMergeSql() { - $this->con->exec(sprintf("INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (%s, %s, %d)", - $this->con->quote($id), - //session data can contain non binary safe characters so we need to encode it - $this->con->quote(base64_encode($data)), - time() - )); + $platform = $pdoDriver = null; - return true; + if ($this->con instanceof Connection) { + $platform = $this->con->getDatabasePlatform(); + } elseif ($this->con instanceof PDOConnection) { + $pdoDriver = $this->con->getAttribute(\PDO::ATTR_DRIVER_NAME); + } + + switch (true) { + case $this->con instanceof MysqliConnection || $platform instanceof MySqlPlatform || 'mysql' === $pdoDriver: + return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . + "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)"; + case $this->con instanceof OCI8Connection || $platform instanceof OraclePlatform || 'oci' === $pdoDriver: + // DUAL is Oracle specific dummy table + return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) " . + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . + "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data"; + case $this->con instanceof SQLSrvConnection || $platform instanceof SQLServerPlatform || 'sqlsrv' === $pdoDriver: + // MS SQL Server requires MERGE be terminated by semicolon + return "MERGE INTO $this->table USING (SELECT 'x' AS dummy) AS src ON ($this->idCol = :id) " . + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " . + "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data;"; + case $platform instanceof SqlitePlatform || 'sqlite' === $pdoDriver: + return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"; + } + + return null; } } From 524bf846db6164549cde09f8352e56e52b418040 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 16 Apr 2014 17:18:22 +0200 Subject: [PATCH 2/2] [HttpFoundation] update phpdoc of SessionHandlerInterface and unify parameters of all handlers according to interface --- .../HttpFoundation/DbalSessionHandler.php | 5 +- .../stubs/SessionHandlerInterface.php | 52 ++++++++----------- .../Handler/MemcacheSessionHandler.php | 2 +- .../Handler/MemcachedSessionHandler.php | 2 +- .../Storage/Handler/MongoDbSessionHandler.php | 4 +- .../Storage/Handler/NullSessionHandler.php | 2 +- .../Storage/Handler/PdoSessionHandler.php | 22 ++++---- .../Storage/Proxy/SessionHandlerProxy.php | 12 ++--- .../Storage/NativeSessionStorageTest.php | 42 +++------------ 9 files changed, 53 insertions(+), 90 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php index 0c1436fa9c..1e7d96ecf5 100644 --- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php +++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php @@ -26,8 +26,7 @@ use Doctrine\DBAL\Platforms\SQLServerPlatform; * DBAL based session storage. * * This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler - * but uses the Doctrine driver connection interface for non-PDO-based drivers like mysqli or OCI8. - * It is recommended to use the wrapper Doctrine\DBAL\Connection for lazy connections and optimized database-specific queries. + * but uses the Doctrine driver connection interface and thus also works with non-PDO-based drivers like mysqli and OCI8. * * @author Fabien Potencier * @author Johannes M. Schmitt @@ -63,7 +62,7 @@ class DbalSessionHandler implements \SessionHandlerInterface /** * Constructor. * - * @param DriverConnection $con A driver connection, preferably a wrapper Doctrine\DBAL\Connection + * @param DriverConnection $con A driver connection, preferably a wrapper Doctrine\DBAL\Connection for lazy connections * @param string $tableName Table name */ public function __construct(DriverConnection $con, $tableName = 'sessions') diff --git a/src/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php b/src/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php index 0e78a7cf11..24280e38fc 100644 --- a/src/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php +++ b/src/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php @@ -10,9 +10,7 @@ */ /** - * SessionHandlerInterface - * - * Provides forward compatibility with PHP 5.4 + * SessionHandlerInterface for PHP < 5.4 * * Extensive documentation can be found at php.net, see links: * @@ -25,76 +23,68 @@ interface SessionHandlerInterface { /** - * Open session. + * Re-initializes existing session, or creates a new one. * * @see http://php.net/sessionhandlerinterface.open * - * @param string $savePath Save path. - * @param string $sessionName Session Name. + * @param string $savePath Save path + * @param string $sessionName Session name, see http://php.net/function.session-name.php * - * @throws \RuntimeException If something goes wrong starting the session. - * - * @return bool + * @return bool true on success, false on failure */ public function open($savePath, $sessionName); /** - * Close session. + * Closes the current session. * * @see http://php.net/sessionhandlerinterface.close * - * @return bool + * @return bool true on success, false on failure */ public function close(); /** - * Read session. - * - * @param string $sessionId + * Reads the session data. * * @see http://php.net/sessionhandlerinterface.read * - * @throws \RuntimeException On fatal error but not "record not found". + * @param string $sessionId Session ID, see http://php.net/function.session-id * - * @return string String as stored in persistent storage or empty string in all other cases. + * @return string Same session data as passed in write() or empty string when non-existent or on failure */ public function read($sessionId); /** - * Commit session to storage. + * Writes the session data to the storage. * * @see http://php.net/sessionhandlerinterface.write * - * @param string $sessionId Session ID. - * @param string $data Session serialized data to save. + * @param string $sessionId Session ID , see http://php.net/function.session-id + * @param string $data Serialized session data to save * - * @return bool + * @return bool true on success, false on failure */ public function write($sessionId, $data); /** - * Destroys this session. + * Destroys a session. * * @see http://php.net/sessionhandlerinterface.destroy * - * @param string $sessionId Session ID. + * @param string $sessionId Session ID, see http://php.net/function.session-id * - * @throws \RuntimeException On fatal error. - * - * @return bool + * @return bool true on success, false on failure */ public function destroy($sessionId); /** - * Garbage collection for storage. + * Cleans up expired sessions (garbage collection). * * @see http://php.net/sessionhandlerinterface.gc * - * @param int $lifetime Max lifetime in seconds to keep sessions stored. + * @param string|int $maxlifetime Sessions that have not updated for the last maxlifetime seconds will be removed * - * @throws \RuntimeException On fatal error. - * - * @return bool + * @return bool true on success, false on failure */ - public function gc($lifetime); + public function gc($maxlifetime); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php index bf707054c2..cec1d312b8 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php @@ -101,7 +101,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function gc($lifetime) + public function gc($maxlifetime) { // not required here because memcache will auto expire the records anyhow. return true; diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php index ba183f22b1..30da22d35e 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -107,7 +107,7 @@ class MemcachedSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function gc($lifetime) + public function gc($maxlifetime) { // not required here because memcached will auto expire the records anyhow. return true; diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php index 1b7bf7cab4..87aa7fb4f7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -99,7 +99,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function gc($lifetime) + public function gc($maxlifetime) { /* Note: MongoDB 2.2+ supports TTL collections, which may be used in * place of this method by indexing the "time_field" field with an @@ -109,7 +109,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface * * See: http://docs.mongodb.org/manual/tutorial/expire-data/ */ - $time = new \MongoDate(time() - $lifetime); + $time = new \MongoDate(time() - $maxlifetime); $this->getCollection()->remove(array( $this->options['time_field'] => array('$lt' => $time), diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php index 62068aff1b..d88ce895b7 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php @@ -65,7 +65,7 @@ class NullSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function gc($lifetime) + public function gc($maxlifetime) { return true; } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index c5586f05a7..65ff039f1b 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -83,7 +83,7 @@ class PdoSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function open($path, $name) + public function open($savePath, $sessionName) { return true; } @@ -99,14 +99,14 @@ class PdoSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function destroy($id) + public function destroy($sessionId) { // delete the record associated with this id $sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; try { $stmt = $this->pdo->prepare($sql); - $stmt->bindParam(':id', $id, \PDO::PARAM_STR); + $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->execute(); } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e); @@ -118,14 +118,14 @@ class PdoSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function gc($lifetime) + public function gc($maxlifetime) { // delete the session records that have expired $sql = "DELETE FROM $this->table WHERE $this->timeCol < :time"; try { $stmt = $this->pdo->prepare($sql); - $stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT); + $stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT); $stmt->execute(); } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e); @@ -137,13 +137,13 @@ class PdoSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function read($id) + public function read($sessionId) { $sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id"; try { $stmt = $this->pdo->prepare($sql); - $stmt->bindParam(':id', $id, \PDO::PARAM_STR); + $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->execute(); // We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed @@ -162,7 +162,7 @@ class PdoSessionHandler implements \SessionHandlerInterface /** * {@inheritdoc} */ - public function write($id, $data) + public function write($sessionId, $data) { // Session data can contain non binary safe characters so we need to encode it. $encoded = base64_encode($data); @@ -175,7 +175,7 @@ class PdoSessionHandler implements \SessionHandlerInterface if (null !== $mergeSql) { $mergeStmt = $this->pdo->prepare($mergeSql); - $mergeStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); $mergeStmt->execute(); @@ -189,13 +189,13 @@ class PdoSessionHandler implements \SessionHandlerInterface $deleteStmt = $this->pdo->prepare( "DELETE FROM $this->table WHERE $this->idCol = :id" ); - $deleteStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $deleteStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $deleteStmt->execute(); $insertStmt = $this->pdo->prepare( "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)" ); - $insertStmt->bindParam(':id', $id, \PDO::PARAM_STR); + $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); $insertStmt->execute(); diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index e1f4fff1fa..81643c74b4 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -64,25 +64,25 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf /** * {@inheritdoc} */ - public function read($id) + public function read($sessionId) { - return (string) $this->handler->read($id); + return (string) $this->handler->read($sessionId); } /** * {@inheritdoc} */ - public function write($id, $data) + public function write($sessionId, $data) { - return (bool) $this->handler->write($id, $data); + return (bool) $this->handler->write($sessionId, $data); } /** * {@inheritdoc} */ - public function destroy($id) + public function destroy($sessionId) { - return (bool) $this->handler->destroy($id); + return (bool) $this->handler->destroy($sessionId); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php index b91ddee4c4..4870115caa 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php @@ -11,10 +11,11 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; +use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; @@ -175,9 +176,9 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler()); $storage->setSaveHandler(new NativeSessionHandler()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandlerProxy(new SessionHandler())); + $storage->setSaveHandler(new SessionHandlerProxy(new NullSessionHandler())); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandler()); + $storage->setSaveHandler(new NullSessionHandler()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); $storage->setSaveHandler(new NativeProxy()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler()); @@ -199,9 +200,9 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); $storage->setSaveHandler(new NativeSessionHandler()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandlerProxy(new SessionHandler())); + $storage->setSaveHandler(new SessionHandlerProxy(new NullSessionHandler())); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandler()); + $storage->setSaveHandler(new NullSessionHandler()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); } @@ -254,30 +255,3 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase $storage->start(); } } - -class SessionHandler implements \SessionHandlerInterface -{ - public function open($savePath, $sessionName) - { - } - - public function close() - { - } - - public function read($id) - { - } - - public function write($id, $data) - { - } - - public function destroy($id) - { - } - - public function gc($maxlifetime) - { - } -}