From 99ef77b84c775488fe442a71ae62c59f09b7042f Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 6 Oct 2014 00:36:25 +0200 Subject: [PATCH 1/5] Fix PdoSessionHandler to work properly with streams --- .../Storage/Handler/PdoSessionHandler.php | 16 +++- .../Storage/Handler/PdoSessionHandlerTest.php | 93 +++++++++++++++++++ 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 26c5f8bc0ee77..891499c271c4c 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -498,6 +498,8 @@ private function rollback() * @param string $sessionId Session ID * * @return string The session data + * + * @throws \PDOException */ private function doRead($sessionId) { @@ -521,11 +523,13 @@ private function doRead($sessionId) return ''; } - return $sessionRows[0][0]; + return is_resource($sessionRows[0][0]) + ? stream_get_contents($sessionRows[0][0]) + : $sessionRows[0][0]; } if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { - // Exlusive-reading of non-existent rows does not block, so we need to do an insert to block + // 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->pdo->prepare( @@ -546,7 +550,13 @@ private function doRead($sessionId) $selectStmt->execute(); $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); - return $sessionRows ? $sessionRows[0][0] : ''; + if ($sessionRows) { + return is_resource($sessionRows[0][0]) + ? stream_get_contents($sessionRows[0][0]) + : $sessionRows[0][0]; + } + + return ''; } throw $e; diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index e4b8d76778d1c..9cc5e39f42910 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -135,6 +135,53 @@ public function testReadWriteReadWithNullByte() $this->assertSame($sessionData, $readData, 'Written value can be read back correctly'); } + public function testReadConvertsStreamToString() + { + $pdo = new MockPdo('pgsql'); + $pdo->prepareResult = $this->getMock('PDOStatement'); + + $content = 'foobar'; + $stream = $this->createStream($content); + + $pdo->prepareResult->expects($this->once())->method('fetchAll') + ->will($this->returnValue(array(array($stream, 42, time())))); + + $storage = new PdoSessionHandler($pdo); + $result = $storage->read('foo'); + + $this->assertSame($content, $result); + } + + public function testReadLockedConvertsStreamToString() + { + $pdo = new MockPdo('pgsql'); + $selectStmt = $this->getMock('PDOStatement'); + $insertStmt = $this->getMock('PDOStatement'); + + $pdo->prepareResult = function ($statement) use ($selectStmt, $insertStmt) { + return 0 === strpos($statement, 'INSERT') ? $insertStmt : $selectStmt; + }; + + $content = 'foobar'; + $stream = $this->createStream($content); + $exception = null; + + $selectStmt->expects($this->atLeast(2))->method('fetchAll') + ->will($this->returnCallback(function () use (&$exception, $stream) { + return $exception ? array(array($stream, 42, time())) : array(); + })); + + $insertStmt->expects($this->once())->method('execute') + ->will($this->returnCallback(function() use (&$exception) { + throw $exception = new \PDOException('', '23'); + })); + + $storage = new PdoSessionHandler($pdo); + $result = $storage->read('foo'); + + $this->assertSame($content, $result); + } + public function testReadingRequiresExactlySameId() { $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); @@ -263,4 +310,50 @@ public function testGetConnectionConnectsIfNeeded() $this->assertInstanceOf('\PDO', $method->invoke($storage)); } + + private function createStream($content) + { + $stream = tmpfile(); + fwrite($stream, $content); + fseek($stream, 0); + + return $stream; + } +} + +class MockPdo extends \PDO +{ + public $driverName; + public $errorMode; + public $prepareResult; + + public function __construct($driverName = null, $errorMode = null) + { + $this->driverName = $driverName; + $this->errorMode = null !== $errorMode ?: \PDO::ERRMODE_EXCEPTION; + } + + public function getAttribute($attribute) + { + if (\PDO::ATTR_ERRMODE === $attribute) { + return $this->errorMode; + } + + if (\PDO::ATTR_DRIVER_NAME === $attribute) { + return $this->driverName; + } + + return parent::getAttribute($attribute); + } + + public function prepare($statement, $driverOptions = array()) + { + return is_callable($this->prepareResult) + ? call_user_func($this->prepareResult, $statement, $driverOptions) + : $this->prepareResult; + } + + public function beginTransaction() + { + } } From a3814cc8f2c0c10a20b6cc48f2133385d005e96c Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 6 Oct 2014 09:58:21 +0200 Subject: [PATCH 2/5] Fix CS --- .../Tests/Session/Storage/Handler/PdoSessionHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 9cc5e39f42910..9097ca754d3de 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -172,7 +172,7 @@ public function testReadLockedConvertsStreamToString() })); $insertStmt->expects($this->once())->method('execute') - ->will($this->returnCallback(function() use (&$exception) { + ->will($this->returnCallback(function () use (&$exception) { throw $exception = new \PDOException('', '23'); })); From d55974d31cf541038104c35bcccc3e44297a2fc5 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 6 Oct 2014 11:02:54 +0200 Subject: [PATCH 3/5] Tweak PHPDoc --- .../Session/Storage/Handler/PdoSessionHandler.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 891499c271c4c..4cde3e13992df 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -498,8 +498,6 @@ private function rollback() * @param string $sessionId Session ID * * @return string The session data - * - * @throws \PDOException */ private function doRead($sessionId) { From fa5dbb9465dc44d3a0a5d5f0a4b487f9905698bd Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 6 Oct 2014 13:43:33 +0200 Subject: [PATCH 4/5] Fix CS --- .../Session/Storage/Handler/PdoSessionHandler.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 4cde3e13992df..32b73968db686 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -521,9 +521,7 @@ private function doRead($sessionId) return ''; } - return is_resource($sessionRows[0][0]) - ? stream_get_contents($sessionRows[0][0]) - : $sessionRows[0][0]; + return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; } if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { @@ -549,9 +547,7 @@ private function doRead($sessionId) $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); if ($sessionRows) { - return is_resource($sessionRows[0][0]) - ? stream_get_contents($sessionRows[0][0]) - : $sessionRows[0][0]; + return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; } return ''; From ec2e84b9286c68e02b09f247add6654620fdb969 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 6 Oct 2014 14:19:27 +0200 Subject: [PATCH 5/5] Change visibility of some properties in MockPdo --- .../Tests/Session/Storage/Handler/PdoSessionHandlerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 9097ca754d3de..ba06fccff9103 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -323,9 +323,9 @@ private function createStream($content) class MockPdo extends \PDO { - public $driverName; - public $errorMode; public $prepareResult; + private $driverName; + private $errorMode; public function __construct($driverName = null, $errorMode = null) {