Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
Yii Framework 2 mongodb extension Change Log
============================================

2.1.10 under development
2.2.0 under development
------------------------

- Bug #308: Fix `yii\mongodb\file\Upload::addFile()` error when uploading file with readonly permissions (sparchatus)
- Enh #319: Added support for the 'session.use_strict_mode' ini directive in `yii\web\Session` (rhertogh)


2.1.9 November 19, 2019
Expand Down
46 changes: 43 additions & 3 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,47 @@ if you want to upgrade from version A to version C and there is
version B between A and C, you need to following the instructions
for both A and B.

Upgrade from Yii 2.0.5
Upgrade from 2.1.9
----------------------

* `yii\mongodb\Session` now respects the 'session.use_strict_mode' ini directive.
In case you use a custom `Session` class and have overwritten the `Session::openSession()` and/or
`Session::writeSession()` functions changes might be required:
* When in strict mode the `openSession()` function should check if the requested session id exists
(and mark it for forced regeneration if not).
For example, the `yii\mongodb\Session` does this at the beginning of the function as follows:
```php
if ($this->getUseStrictMode()) {
$id = $this->getId();
$collection = $this->db->getCollection($this->sessionCollection);
$condition = [
'id' => $id,
'expire' => ['$gt' => time()],
];
if (!$collection->documentExists($condition)) {
//This session id does not exist, mark it for forced regeneration
$this->_forceRegenerateId = $id;
}
}
// ... normal function continues ...
```
* When in strict mode the `writeSession()` function should ignore writing the session under the old id.
For example, the `yii\mongodb\Session` does this at the beginning of the function as follows:
```php
if ($this->getUseStrictMode() && $id === $this->_forceRegenerateId) {
//Ignore write when forceRegenerate is active for this id
return true;
}
// ... normal function continues ...
```
> Note: In case your custom functions call their `parent` functions, there are probably no changes needed to your
code if those parents implement the `useStrictMode` checks.

> Warning: in case `openSession()` and/or `writeSession()` functions do not implement the `useStrictMode` code
the session could be stored under the forced id without warning even if `useStrictMode` is enabled.


Upgrade from 2.0.5
----------------------

* PHP [mongodb](http://php.net/manual/en/set.mongodb.php) extension is now used instead of [mongo](http://php.net/manual/en/book.mongo.php).
Expand Down Expand Up @@ -38,13 +78,13 @@ Upgrade from Yii 2.0.5
* Cursor composed via `yii\mongodb\file\Collection::find()` now returns result in the same format as `yii\mongodb\file\Query::one()`.
If you wish to perform file manipulations on returned row you should use `file` key instead of direct method invocations.

Upgrade from Yii 2.0.1
Upgrade from 2.0.1
----------------------

* MongoDB PHP extension min version raised up to 1.5.0. You should upgrade your environment in case you are
using older version.

Upgrade from Yii 2.0.0
Upgrade from 2.0.0
----------------------

* MongoDB PHP extension min version raised up to 1.4.0. You should upgrade your environment in case you are
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
"email": "[email protected]"
}
],
"minimum-stability": "dev",
"require": {
"yiisoft/yii2": "~2.0.14",
"yiisoft/yii2": "~2.0.39",
"ext-mongodb": ">=1.0.0"
},
"require-dev": {
Expand Down
11 changes: 11 additions & 0 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ public function findOne($condition = [], $fields = [], $options = [])
return empty($rows) ? null : current($rows);
}

/**
* Returns if a document exists.
* @param array $condition Query condition.
* @return bool
* @since 2.0.39
*/
public function documentExists($condition = [])
{
return static::findOne($condition, ['_id' => 1]) !== null;
}

/**
* Updates a document and returns it.
* @param array $condition query condition
Expand Down
32 changes: 31 additions & 1 deletion src/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ public function init()
$this->db = Instance::ensure($this->db, Connection::className());
}

/**
* Session open handler.
* @internal Do not call this method directly.
* @param string $savePath session save path
* @param string $sessionName session name
* @return bool whether session is opened successfully
*/
public function openSession($savePath, $sessionName)
{
if ($this->getUseStrictMode()) {
$id = $this->getId();
$collection = $this->db->getCollection($this->sessionCollection);
$condition = [
'id' => $id,
'expire' => ['$gt' => time()],
];
if (!$collection->documentExists($condition)) {
//This session id does not exist, mark it for forced regeneration
$this->_forceRegenerateId = $id;
}
}

return parent::openSession($savePath, $sessionName);
}

/**
* Updates the current session ID with a newly generated one.
* Please refer to <http://php.net/session_regenerate_id> for more details.
Expand Down Expand Up @@ -142,6 +167,11 @@ public function readSession($id)
*/
public function writeSession($id, $data)
{
if ($this->getUseStrictMode() && $id === $this->_forceRegenerateId) {
//Ignore write when forceRegenerate is active for this id
return true;
}

// exception must be caught in session write handler
// http://us.php.net/manual/en/function.session-set-save-handler.php
try {
Expand Down Expand Up @@ -211,4 +241,4 @@ public function gcSession($maxLifetime)

return true;
}
}
}
18 changes: 18 additions & 0 deletions tests/CollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,4 +560,22 @@ public function testDistinct()
$this->assertFalse($rows === false);
$this->assertCount(1, $rows);
}

/**
* @depends testInsert
* @depends testFindOne
*/
public function testDocumentExists()
{
$name = uniqid('customer_', true);
$collection = $this->getConnection()->getCollection('customer');
$data = [
'name' => $name,
'address' => 'test address',
];
$collection->insert($data);

$this->assertTrue($collection->documentExists(['name' => $name]));
$this->assertFalse($collection->documentExists(['name' => 'non-existing']));
}
}
52 changes: 48 additions & 4 deletions tests/SessionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use yii\mongodb\Session;
use Yii;
use yii\helpers\ArrayHelper;

class SessionTest extends TestCase
{
Expand All @@ -22,13 +23,13 @@ protected function tearDown()
* Creates test session instance.
* @return Session session instance.
*/
protected function createSession()
protected function createSession($config = [])
{
return Yii::createObject([
return Yii::createObject(ArrayHelper::merge([
'class' => Session::className(),
'db' => $this->getConnection(),
'sessionCollection' => static::$sessionCollection,
]);
], $config));
}

// Tests:
Expand Down Expand Up @@ -157,4 +158,47 @@ public function testWriteCustomField()
$this->assertEquals('session data', $rows[0]['data']);
$this->assertEquals(15, $rows[0]['user_id']);
}
}

/**
* @depends testWriteSession
* @runInSeparateProcess
*/
public function testStrictMode()
{
//non-strict-mode test
$nonStrictSession = $this->createSession([
'useStrictMode' => false,
]);
$nonStrictSession->close();
$nonStrictSession->destroySession('non-existing-non-strict');
$nonStrictSession->setId('non-existing-non-strict');
$nonStrictSession->open();
$this->assertEquals('non-existing-non-strict', $nonStrictSession->getId());
$nonStrictSession->close();

//strict-mode test
$strictSession = $this->createSession([
'useStrictMode' => true,
]);
$strictSession->close();
$strictSession->destroySession('non-existing-strict');
$strictSession->setId('non-existing-strict');
$strictSession->open();
$id = $strictSession->getId();
$this->assertNotEquals('non-existing-strict', $id);
$strictSession->set('strict_mode_test', 'session data');
$strictSession->close();
//Ensure session was not stored under forced id
$strictSession->setId('non-existing-strict');
$strictSession->open();
$this->assertNotEquals('session data', $strictSession->get('strict_mode_test'));
$strictSession->close();
//Ensure session can be accessed with the new (and thus existing) id.
$strictSession->setId($id);
$strictSession->open();
$this->assertNotEmpty($id);
$this->assertEquals($id, $strictSession->getId());
$this->assertEquals('session data', $strictSession->get('strict_mode_test'));
$strictSession->close();
}
}