Skip to content

Commit 28d045e

Browse files
committed
merged branch vicb/session_nnhandlers (PR #4227)
Commits ------- 12e22c0 [Session] Memcache/d cleanup, test improvements 788adfb [Session] Pdo Handler cleanup 0216e05 [HttpFoundation][Session] Assume that memcache(d) instances are already configured 72d21c6 [HttpFoundation][Session] change possible replace() & set() for set only() Discussion ---------- [Session] Non-native Session handlers A few item to discuss. Needs @Drak inputs. * 72d21c6 is trivial, * 0216e05 is about memcache(d) handlers * I don't think the handlers should configure the memcache(d) instances. Those instances are injected into the storage so they should already be confidured (this will be done in the CacheBundle when available) * A SW prefix has been added to the memcached handlers so that the same instance of memcached can be shared - you can still set the `Memcached::OPT_PREFIX_KEY` before injecting the memcached instance. * It was not possible to use an expiration > 30days before, see [php.net](http://www.php.net/manual/en/memcached.expiration.php) * 788adfb is trivial (cleanup in the PDO handler) --------------------------------------------------------------------------- by travisbot at 2012-05-08T09:49:03Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1274808) (merged 788adfb into e54f4e4). --------------------------------------------------------------------------- by drak at 2012-05-09T15:20:38Z Overall this PR looks good to me. Since Memcache/d objects are passed by DI anyway, there is no need to provide a way to configure the objects here. However, I am not sure it's consistent to provide internal handling of the prefix/expire if we are saying the objects should be configured and injected - if we hand over all configuration to the injected objects, that's exactly what we should do. In the case of the `Memcache` handler there is no handling for prefix by the Memcache object that is why it's handled internally. Unless there are some other technical consideration I've missed, I would also not expect the same Memcache/d object to be used in all use cases (e.g. session storage and database caching layer). I realise we are trying to unify things in one cache component, but I am not entirely convinced session storage would necessarily have to be part of that nor that "one object fits all" is practical or wise. As far as I am aware, apart from default settings, memcache/memcached instances retain their own settings once configured so it's quite feasible to expect there might be a couple of differently configured instances in a complex system. In summary, I would remove the `$memcachedOptions` config entirely from the `MemcachedHander` along with the associated prefix and time and let it all be configured by the injected `Memcached` instance. --------------------------------------------------------------------------- by travisbot at 2012-05-10T07:32:53Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1293064) (merged 12e22c0 into e54f4e4). --------------------------------------------------------------------------- by vicb at 2012-05-10T07:34:31Z @Drak thanks for your feeback. About the prefix: it might be necessary to avoid collisions when you re-use the same instance of `memcache/d`. This is why the prefix is handled internally and not by `memcached` (it would be global and not serve the purpose then). About the ttl: * `memcache/d` can not handle ttl > 30 days (they would consider the time as an absolute timestamp then) and this is why the PR always convert the ttl to an absolute ts (`time() + $ttl`) * Moreover I think that the ttl should be initialized by the `Session`: there is no reason why the ttl should be different from the `gc_maxlifetime`. I think this is out of the scope of this PR. About sharing `memcache/d ` instances: it will be possible but it does not mean that you have to, you still can use different instances if this suit your needs. The tests have been improved. If you are ok with the latest changes, this PR should be ready to be merged --------------------------------------------------------------------------- by drak at 2012-05-10T09:29:18Z @vicb - I think it's ok to merge now. You are right about the TTL since PHP will pass a maxlifetime not a timestamp, and since memcached varies how it treats $expire, it does need to be normalised in the handler. I'm not necessarily 100% convinced about the prefix, but I don't object. Nice work. /cc @fabpot
2 parents 48099a8 + 12e22c0 commit 28d045e

File tree

5 files changed

+169
-188
lines changed

5 files changed

+169
-188
lines changed

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php

+26-60
Original file line numberDiff line numberDiff line change
@@ -19,121 +19,87 @@
1919
class MemcacheSessionHandler implements \SessionHandlerInterface
2020
{
2121
/**
22-
* Memcache driver.
23-
*
24-
* @var \Memcache
22+
* @var \Memcache Memcache driver.
2523
*/
2624
private $memcache;
2725

2826
/**
29-
* Configuration options.
30-
*
31-
* @var array
27+
* @var integer Time to live in seconds
3228
*/
33-
private $memcacheOptions;
29+
private $ttl;
3430

3531
/**
36-
* Key prefix for shared environments.
37-
*
38-
* @var string
32+
* @var string Key prefix for shared environments.
3933
*/
4034
private $prefix;
4135

4236
/**
4337
* Constructor.
4438
*
45-
* @param \Memcache $memcache A \Memcache instance
46-
* @param array $memcacheOptions An associative array of Memcache options
47-
* @param array $options Session configuration options.
39+
* List of available options:
40+
* * prefix: The prefix to use for the memcache keys in order to avoid collision
41+
* * expiretime: The time to live in seconds
42+
*
43+
* @param \Memcache $memcache A \Memcache instance
44+
* @param array $options An associative array of Memcache options
45+
*
46+
* @throws \InvalidArgumentException When unsupported options are passed
4847
*/
49-
public function __construct(\Memcache $memcache, array $memcacheOptions = array(), array $options = array())
48+
public function __construct(\Memcache $memcache, array $options = array())
5049
{
51-
$this->memcache = $memcache;
52-
53-
// defaults
54-
if (!isset($memcacheOptions['serverpool'])) {
55-
$memcacheOptions['serverpool'] = array(array(
56-
'host' => '127.0.0.1',
57-
'port' => 11211,
58-
'timeout' => 1,
59-
'persistent' => false,
60-
'weight' => 1,
61-
'retry_interval' => 15,
50+
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
51+
throw new \InvalidArgumentException(sprintf(
52+
'The following options are not supported "%s"', implode(', ', $diff)
6253
));
6354
}
6455

65-
$memcacheOptions['expiretime'] = isset($memcacheOptions['expiretime']) ? (int)$memcacheOptions['expiretime'] : 86400;
66-
$this->prefix = isset($memcacheOptions['prefix']) ? $memcacheOptions['prefix'] : 'sf2s';
67-
68-
$this->memcacheOptions = $memcacheOptions;
69-
}
70-
71-
protected function addServer(array $server)
72-
{
73-
if (!array_key_exists('host', $server)) {
74-
throw new \InvalidArgumentException('host key must be set');
75-
}
76-
77-
$server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
78-
$server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
79-
$server['persistent'] = isset($server['persistent']) ? (bool)$server['persistent'] : false;
80-
$server['weight'] = isset($server['weight']) ? (int)$server['weight'] : 1;
81-
$server['retry_interval'] = isset($server['retry_interval']) ? (int)$server['retry_interval'] : 15;
82-
83-
$this->memcache->addserver($server['host'], $server['port'], $server['persistent'],$server['weight'],$server['timeout'],$server['retry_interval']);
84-
56+
$this->memcache = $memcache;
57+
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
58+
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
8559
}
8660

8761
/**
88-
* {@inheritdoc}
62+
* {@inheritDoc}
8963
*/
9064
public function open($savePath, $sessionName)
9165
{
92-
foreach ($this->memcacheOptions['serverpool'] as $server) {
93-
$this->addServer($server);
94-
}
95-
9666
return true;
9767
}
9868

9969
/**
100-
* {@inheritdoc}
70+
* {@inheritDoc}
10171
*/
10272
public function close()
10373
{
10474
return $this->memcache->close();
10575
}
10676

10777
/**
108-
* {@inheritdoc}
78+
* {@inheritDoc}
10979
*/
11080
public function read($sessionId)
11181
{
11282
return $this->memcache->get($this->prefix.$sessionId) ?: '';
11383
}
11484

11585
/**
116-
* {@inheritdoc}
86+
* {@inheritDoc}
11787
*/
11888
public function write($sessionId, $data)
11989
{
120-
if (!$this->memcache->replace($this->prefix.$sessionId, $data, 0, $this->memcacheOptions['expiretime'])) {
121-
return $this->memcache->set($this->prefix.$sessionId, $data, 0, $this->memcacheOptions['expiretime']);
122-
}
123-
124-
return true;
90+
return $this->memcache->set($this->prefix.$sessionId, $data, 0, time() + $this->ttl);
12591
}
12692

12793
/**
128-
* {@inheritdoc}
94+
* {@inheritDoc}
12995
*/
13096
public function destroy($sessionId)
13197
{
13298
return $this->memcache->delete($this->prefix.$sessionId);
13399
}
134100

135101
/**
136-
* {@inheritdoc}
102+
* {@inheritDoc}
137103
*/
138104
public function gc($lifetime)
139105
{

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php

+34-48
Original file line numberDiff line numberDiff line change
@@ -24,107 +24,93 @@
2424
class MemcachedSessionHandler implements \SessionHandlerInterface
2525
{
2626
/**
27-
* Memcached driver.
28-
*
29-
* @var \Memcached
27+
* @var \Memcached Memcached driver.
3028
*/
3129
private $memcached;
3230

3331
/**
34-
* Configuration options.
35-
*
36-
* @var array
32+
* @var integer Time to live in seconds
3733
*/
38-
private $memcachedOptions;
34+
private $ttl;
35+
36+
37+
/**
38+
* @var string Key prefix for shared environments.
39+
*/
40+
private $prefix;
3941

4042
/**
4143
* Constructor.
4244
*
43-
* @param \Memcached $memcached A \Memcached instance
44-
* @param array $memcachedOptions An associative array of Memcached options
45-
* @param array $options Session configuration options.
45+
* List of available options:
46+
* * prefix: The prefix to use for the memcached keys in order to avoid collision
47+
* * expiretime: The time to live in seconds
48+
*
49+
* @param \Memcached $memcached A \Memcached instance
50+
* @param array $options An associative array of Memcached options
51+
*
52+
* @throws \InvalidArgumentException When unsupported options are passed
4653
*/
47-
public function __construct(\Memcached $memcached, array $memcachedOptions = array(), array $options = array())
54+
public function __construct(\Memcached $memcached, array $options = array())
4855
{
4956
$this->memcached = $memcached;
5057

51-
// defaults
52-
if (!isset($memcachedOptions['serverpool'])) {
53-
$memcachedOptions['serverpool'][] = array(
54-
'host' => '127.0.0.1',
55-
'port' => 11211,
56-
'weight' => 1);
58+
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
59+
throw new \InvalidArgumentException(sprintf(
60+
'The following options are not supported "%s"', implode(', ', $diff)
61+
));
5762
}
5863

59-
$memcachedOptions['expiretime'] = isset($memcachedOptions['expiretime']) ? (int)$memcachedOptions['expiretime'] : 86400;
60-
61-
$this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, isset($memcachedOptions['prefix']) ? $memcachedOptions['prefix'] : 'sf2s');
62-
63-
$this->memcachedOptions = $memcachedOptions;
64+
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
65+
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
6466
}
6567

6668
/**
67-
* {@inheritdoc}
69+
* {@inheritDoc}
6870
*/
6971
public function open($savePath, $sessionName)
7072
{
71-
return $this->memcached->addServers($this->memcachedOptions['serverpool']);
73+
return true;
7274
}
7375

7476
/**
75-
* {@inheritdoc}
77+
* {@inheritDoc}
7678
*/
7779
public function close()
7880
{
7981
return true;
8082
}
8183

8284
/**
83-
* {@inheritdoc}
85+
* {@inheritDoc}
8486
*/
8587
public function read($sessionId)
8688
{
87-
return $this->memcached->get($sessionId) ?: '';
89+
return $this->memcached->get($this->prefix.$sessionId) ?: '';
8890
}
8991

9092
/**
91-
* {@inheritdoc}
93+
* {@inheritDoc}
9294
*/
9395
public function write($sessionId, $data)
9496
{
95-
return $this->memcached->set($sessionId, $data, $this->memcachedOptions['expiretime']);
97+
return $this->memcached->set($this->prefix.$sessionId, $data, time() + $this->ttl);
9698
}
9799

98100
/**
99-
* {@inheritdoc}
101+
* {@inheritDoc}
100102
*/
101103
public function destroy($sessionId)
102104
{
103-
return $this->memcached->delete($sessionId);
105+
return $this->memcached->delete($this->prefix.$sessionId);
104106
}
105107

106108
/**
107-
* {@inheritdoc}
109+
* {@inheritDoc}
108110
*/
109111
public function gc($lifetime)
110112
{
111113
// not required here because memcached will auto expire the records anyhow.
112114
return true;
113115
}
114-
115-
/**
116-
* Adds a server to the memcached handler.
117-
*
118-
* @param array $server
119-
*/
120-
protected function addServer(array $server)
121-
{
122-
if (array_key_exists('host', $server)) {
123-
throw new \InvalidArgumentException('host key must be set');
124-
}
125-
$server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
126-
$server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
127-
$server['presistent'] = isset($server['presistent']) ? (bool)$server['presistent'] : false;
128-
$server['weight'] = isset($server['weight']) ? (bool)$server['weight'] : 1;
129-
}
130116
}

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php

+13-14
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,10 @@ class PdoSessionHandler implements \SessionHandlerInterface
3939
*
4040
* @param \PDO $pdo A \PDO instance
4141
* @param array $dbOptions An associative array of DB options
42-
* @param array $options Session configuration options
4342
*
4443
* @throws \InvalidArgumentException When "db_table" option is not provided
4544
*/
46-
public function __construct(\PDO $pdo, array $dbOptions = array(), array $options = array())
45+
public function __construct(\PDO $pdo, array $dbOptions = array())
4746
{
4847
if (!array_key_exists('db_table', $dbOptions)) {
4948
throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
@@ -58,28 +57,28 @@ public function __construct(\PDO $pdo, array $dbOptions = array(), array $option
5857
}
5958

6059
/**
61-
* {@inheritdoc}
60+
* {@inheritDoc}
6261
*/
6362
public function open($path, $name)
6463
{
6564
return true;
6665
}
6766

6867
/**
69-
* {@inheritdoc}
68+
* {@inheritDoc}
7069
*/
7170
public function close()
7271
{
7372
return true;
7473
}
7574

7675
/**
77-
* {@inheritdoc}
76+
* {@inheritDoc}
7877
*/
7978
public function destroy($id)
8079
{
8180
// get table/column
82-
$dbTable = $this->dbOptions['db_table'];
81+
$dbTable = $this->dbOptions['db_table'];
8382
$dbIdCol = $this->dbOptions['db_id_col'];
8483

8584
// delete the record associated with this id
@@ -97,20 +96,20 @@ public function destroy($id)
9796
}
9897

9998
/**
100-
* {@inheritdoc}
99+
* {@inheritDoc}
101100
*/
102101
public function gc($lifetime)
103102
{
104103
// get table/column
105-
$dbTable = $this->dbOptions['db_table'];
104+
$dbTable = $this->dbOptions['db_table'];
106105
$dbTimeCol = $this->dbOptions['db_time_col'];
107106

108107
// delete the session records that have expired
109-
$sql = "DELETE FROM $dbTable WHERE $dbTimeCol < (:time - $lifetime)";
108+
$sql = "DELETE FROM $dbTable WHERE $dbTimeCol < :time";
110109

111110
try {
112111
$stmt = $this->pdo->prepare($sql);
113-
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
112+
$stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT);
114113
$stmt->execute();
115114
} catch (\PDOException $e) {
116115
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
@@ -120,12 +119,12 @@ public function gc($lifetime)
120119
}
121120

122121
/**
123-
* {@inheritdoc}
122+
* {@inheritDoc}
124123
*/
125124
public function read($id)
126125
{
127126
// get table/columns
128-
$dbTable = $this->dbOptions['db_table'];
127+
$dbTable = $this->dbOptions['db_table'];
129128
$dbDataCol = $this->dbOptions['db_data_col'];
130129
$dbIdCol = $this->dbOptions['db_id_col'];
131130

@@ -154,7 +153,7 @@ public function read($id)
154153
}
155154

156155
/**
157-
* {@inheritdoc}
156+
* {@inheritDoc}
158157
*/
159158
public function write($id, $data)
160159
{
@@ -201,7 +200,7 @@ public function write($id, $data)
201200
private function createNewSession($id, $data = '')
202201
{
203202
// get table/column
204-
$dbTable = $this->dbOptions['db_table'];
203+
$dbTable = $this->dbOptions['db_table'];
205204
$dbDataCol = $this->dbOptions['db_data_col'];
206205
$dbIdCol = $this->dbOptions['db_id_col'];
207206
$dbTimeCol = $this->dbOptions['db_time_col'];

0 commit comments

Comments
 (0)