Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 52cb779

Browse filesBrowse files
author
Benjamin Zikarsky
committed
Session expiry date is now defined on session-write
1 parent 3f6372d commit 52cb779
Copy full SHA for 52cb779

File tree

Expand file treeCollapse file tree

2 files changed

+35
-103
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+35
-103
lines changed

‎src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php
+24-31Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
4242
* * id_field: The field name for storing the session id [default: _id]
4343
* * data_field: The field name for storing the session data [default: data]
4444
* * time_field: The field name for storing the timestamp [default: time]
45+
* * expiry_field: The field name for storing the expiry-timestamp [default: expires_at]
46+
*
47+
* It is strongly recommended to put an index on the `expiry_field` for
48+
* garbage-collection. Alternatively it's possible to automatically expire
49+
* the sessions in the database as described below:
50+
*
51+
* A TTL collections can be used on MongoDB 2.2+ to cleanup expired sessions
52+
* automatically. Such an index can for example look like this:
53+
*
54+
* db.<session-collection>.ensureIndex(
55+
* { "<expiry-field>": 1 },
56+
* { "expireAfterSeconds": 0 }
57+
* )
58+
*
59+
* More details on: http://docs.mongodb.org/manual/tutorial/expire-data/
60+
*
61+
* If you use such an index, you can drop `gc_probability` to 0 since
62+
* no garbage-collection is required.
4563
*
4664
* @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance
4765
* @param array $options An associative array of field options
@@ -65,7 +83,7 @@ public function __construct($mongo, array $options)
6583
'id_field' => '_id',
6684
'data_field' => 'data',
6785
'time_field' => 'time',
68-
'expiry_field' => false,
86+
'expiry_field' => 'expires_at',
6987
), $options);
7088
}
7189

@@ -102,21 +120,8 @@ public function destroy($sessionId)
102120
*/
103121
public function gc($maxlifetime)
104122
{
105-
/* Note: MongoDB 2.2+ supports TTL collections, which may be used in
106-
* place of this method by indexing the "time_field" field with an
107-
* "expireAfterSeconds" option. Regardless of whether TTL collections
108-
* are used, consider indexing this field to make the remove query more
109-
* efficient.
110-
*
111-
* See: http://docs.mongodb.org/manual/tutorial/expire-data/
112-
*/
113-
if (false !== $this->options['expiry_field']) {
114-
return true;
115-
}
116-
$time = new \MongoDate(time() - $maxlifetime);
117-
118123
$this->getCollection()->remove(array(
119-
$this->options['time_field'] => array('$lt' => $time),
124+
$this->options['expiry_field'] => array('$lt' => new \MongoDate()),
120125
));
121126

122127
return true;
@@ -127,24 +132,14 @@ public function gc($maxlifetime)
127132
*/
128133
public function write($sessionId, $data)
129134
{
135+
$expiry = new \MongoDate(time() + (int) ini_get('session.gc_maxlifetime'));
136+
130137
$fields = array(
131138
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
132139
$this->options['time_field'] => new \MongoDate(),
140+
$this->options['expiry_field'] => $expiry
133141
);
134142

135-
/* Note: As discussed in the gc method of this class. You can utilise
136-
* TTL collections in MongoDB 2.2+
137-
* We are setting the "expiry_field" as part of the write operation here
138-
* You will need to create the index on your collection that expires documents
139-
* at that time
140-
* e.g.
141-
* db.MySessionCollection.ensureIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )
142-
*/
143-
if (false !== $this->options['expiry_field']) {
144-
$expiry = new \MongoDate(time() + (int) ini_get('session.gc_maxlifetime'));
145-
$fields[$this->options['expiry_field']] = $expiry;
146-
}
147-
148143
$this->getCollection()->update(
149144
array($this->options['id_field'] => $sessionId),
150145
array('$set' => $fields),
@@ -159,11 +154,9 @@ public function write($sessionId, $data)
159154
*/
160155
public function read($sessionId)
161156
{
162-
$timeoutThreshold = new \MongoDate(time() - (int) ini_get('session.gc_maxlifetime'));
163-
164157
$dbData = $this->getCollection()->findOne(array(
165158
$this->options['id_field'] => $sessionId,
166-
$this->options['time_field'] => array('$gt' => $timeoutThreshold),
159+
$this->options['expiry_field'] => array('$gte' => new \MongoDate()),
167160
));
168161

169162
return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin;

‎src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php
+11-72Lines changed: 11 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ protected function setUp()
4040
'id_field' => '_id',
4141
'data_field' => 'data',
4242
'time_field' => 'time',
43+
'expiry_field' => 'expires_at',
4344
'database' => 'sf2-test',
4445
'collection' => 'session-test',
4546
);
@@ -86,18 +87,18 @@ public function testRead()
8687

8788
// defining the timeout before the actual method call
8889
// allows to test for "greater than" values in the $criteria
89-
$testTimeout = time() - (int) ini_get('session.gc_maxlifetime');
90+
$testTimeout = time();
9091

9192
$collection->expects($this->once())
9293
->method('findOne')
9394
->will($this->returnCallback(function ($criteria) use ($that, $testTimeout) {
9495
$that->assertArrayHasKey($that->options['id_field'], $criteria);
9596
$that->assertEquals($criteria[$that->options['id_field']], 'foo');
9697

97-
$that->assertArrayHasKey($that->options['time_field'], $criteria);
98-
$that->assertArrayHasKey('$gt', $criteria[$that->options['time_field']]);
99-
$that->assertInstanceOf('MongoDate', $criteria[$that->options['time_field']]['$gt']);
100-
$that->assertGreaterThanOrEqual($criteria[$that->options['time_field']]['$gt']->sec, $testTimeout);
98+
$that->assertArrayHasKey($that->options['expiry_field'], $criteria);
99+
$that->assertArrayHasKey('$gte', $criteria[$that->options['expiry_field']]);
100+
$that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$gte']);
101+
$that->assertGreaterThanOrEqual($criteria[$that->options['expiry_field']]['$gte']->sec, $testTimeout);
101102

102103
return array(
103104
$that->options['id_field'] => 'foo',
@@ -130,49 +131,13 @@ public function testWrite()
130131
$data = $updateData['$set'];
131132
}));
132133

134+
$expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime');
133135
$this->assertTrue($this->storage->write('foo', 'bar'));
134136

135137
$this->assertEquals('bar', $data[$this->options['data_field']]->bin);
136138
$that->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
137-
}
138-
139-
public function testWriteWhenUsingExpiresField()
140-
{
141-
$this->options = array(
142-
'id_field' => '_id',
143-
'data_field' => 'data',
144-
'time_field' => 'time',
145-
'database' => 'sf2-test',
146-
'collection' => 'session-test',
147-
'expiry_field' => 'expiresAt',
148-
);
149-
150-
$this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
151-
152-
$collection = $this->createMongoCollectionMock();
153-
154-
$this->mongo->expects($this->once())
155-
->method('selectCollection')
156-
->with($this->options['database'], $this->options['collection'])
157-
->will($this->returnValue($collection));
158-
159-
$that = $this;
160-
$data = array();
161-
162-
$collection->expects($this->once())
163-
->method('update')
164-
->will($this->returnCallback(function ($criteria, $updateData, $options) use ($that, &$data) {
165-
$that->assertEquals(array($that->options['id_field'] => 'foo'), $criteria);
166-
$that->assertEquals(array('upsert' => true, 'multiple' => false), $options);
167-
168-
$data = $updateData['$set'];
169-
}));
170-
171-
$this->assertTrue($this->storage->write('foo', 'bar'));
172-
173-
$this->assertEquals('bar', $data[$this->options['data_field']]->bin);
174-
$that->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
175-
$that->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]);
139+
$this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]);
140+
$this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec);
176141
}
177142

178143
public function testReplaceSessionData()
@@ -228,39 +193,13 @@ public function testGc()
228193
$collection->expects($this->once())
229194
->method('remove')
230195
->will($this->returnCallback(function ($criteria) use ($that) {
231-
$that->assertInstanceOf('MongoDate', $criteria[$that->options['time_field']]['$lt']);
232-
$that->assertGreaterThanOrEqual(time() - 1, $criteria[$that->options['time_field']]['$lt']->sec);
196+
$that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$lt']);
197+
$that->assertGreaterThanOrEqual(time() - 1, $criteria[$that->options['expiry_field']]['$lt']->sec);
233198
}));
234199

235200
$this->assertTrue($this->storage->gc(1));
236201
}
237202

238-
public function testGcWhenUsingExpiresField()
239-
{
240-
$this->options = array(
241-
'id_field' => '_id',
242-
'data_field' => 'data',
243-
'time_field' => 'time',
244-
'database' => 'sf2-test',
245-
'collection' => 'session-test',
246-
'expiry_field' => 'expiresAt',
247-
);
248-
249-
$this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
250-
251-
$collection = $this->createMongoCollectionMock();
252-
253-
$this->mongo->expects($this->never())
254-
->method('selectCollection');
255-
256-
$that = $this;
257-
258-
$collection->expects($this->never())
259-
->method('remove');
260-
261-
$this->assertTrue($this->storage->gc(1));
262-
}
263-
264203
public function testGetConnection()
265204
{
266205
$method = new \ReflectionMethod($this->storage, 'getMongo');

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.