Skip to content

Commit

Permalink
[HttpFoundation] Fix PdoSessionHandler to work properly with streams
Browse files Browse the repository at this point in the history
  • Loading branch information
rybakit authored and fabpot committed Oct 7, 2014
1 parent a7d52fd commit 9531a2b
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 3 deletions.
Expand Up @@ -521,11 +521,11 @@ 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(
Expand All @@ -546,7 +546,11 @@ 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;
Expand Down
Expand Up @@ -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());
Expand Down Expand Up @@ -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 $prepareResult;
private $driverName;
private $errorMode;

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()
{
}
}

0 comments on commit 9531a2b

Please sign in to comment.