Skip to content

Commit cadbf10

Browse files
committed
[HttpFoundation] Add RedisSessionHandler
1 parent 782dc94 commit cadbf10

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
13+
14+
/**
15+
* Redis based session storage handler based on the Redis class
16+
* provided by the PHP redis extension.
17+
*
18+
* Direct port of MemcachedSessionHandler to Redis.
19+
*
20+
* @see http://php.net/redis
21+
*
22+
* @author Drak <drak@zikula.org>
23+
* @author Dalibor Karlović <dkarlovi@gmail.com>
24+
*/
25+
class RedisSessionHandler extends AbstractSessionHandler
26+
{
27+
/**
28+
* @var \Redis
29+
*/
30+
private $redis;
31+
32+
/**
33+
* @var int Time to live in seconds
34+
*/
35+
private $ttl;
36+
37+
/**
38+
* @var string Key prefix for shared environments
39+
*/
40+
private $prefix;
41+
42+
/**
43+
* List of available options:
44+
* * prefix: The prefix to use for the Redis keys in order to avoid collision
45+
* * expiretime: The time to live in seconds.
46+
*
47+
* @param \Redis $redis A \Redis instance
48+
* @param array $options An associative array of Redis options
49+
*
50+
* @throws \InvalidArgumentException When unsupported options are passed
51+
*/
52+
public function __construct(\Redis $redis, array $options = null)
53+
{
54+
$this->redis = $redis;
55+
56+
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
57+
throw new \InvalidArgumentException(sprintf(
58+
'The following options are not supported "%s"', implode(', ', $diff)
59+
));
60+
}
61+
62+
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
63+
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
protected function doRead($sessionId)
70+
{
71+
return $this->redis->get($this->prefix.$sessionId) ?: '';
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
protected function doWrite($sessionId, $data)
78+
{
79+
return $this->redis->set($this->prefix.$sessionId, $data, $this->ttl);
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
protected function doDestroy($sessionId)
86+
{
87+
// number of deleted items
88+
$count = $this->redis->del($this->prefix.$sessionId);
89+
90+
return 1 === $count;
91+
}
92+
93+
/**
94+
* {@inheritdoc}
95+
*/
96+
public function close()
97+
{
98+
return true;
99+
}
100+
101+
/**
102+
* {@inheritdoc}
103+
*/
104+
public function gc($maxlifetime)
105+
{
106+
return true;
107+
}
108+
109+
/**
110+
* {@inheritdoc}
111+
*/
112+
public function updateTimestamp($sessionId, $data)
113+
{
114+
return $this->redis->expire($this->prefix.$sessionId, $this->ttl);
115+
}
116+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler;
16+
17+
/**
18+
* @requires extension redis
19+
* @group time-sensitive
20+
*/
21+
class RedisSessionHandlerTest extends TestCase
22+
{
23+
const PREFIX = 'prefix_';
24+
const TTL = 1000;
25+
26+
/**
27+
* @var RedisSessionHandler
28+
*/
29+
protected $storage;
30+
31+
/** @var \PHPUnit_Framework_MockObject_MockObject|\Redis $redis */
32+
protected $redis;
33+
34+
protected function setUp()
35+
{
36+
parent::setUp();
37+
38+
$this->redis = $this->getMockBuilder('Redis')->getMock();
39+
$this->storage = new RedisSessionHandler(
40+
$this->redis,
41+
array('prefix' => self::PREFIX, 'expiretime' => self::TTL)
42+
);
43+
}
44+
45+
protected function tearDown()
46+
{
47+
$this->redis = null;
48+
$this->storage = null;
49+
parent::tearDown();
50+
}
51+
52+
public function testOpenSession()
53+
{
54+
$this->assertTrue($this->storage->open('', ''));
55+
}
56+
57+
public function testCloseSession()
58+
{
59+
$this->assertTrue($this->storage->close());
60+
}
61+
62+
public function testReadSession()
63+
{
64+
$this->redis
65+
->expects($this->once())
66+
->method('get')
67+
->with(self::PREFIX.'id')
68+
;
69+
70+
$this->assertEquals('', $this->storage->read('id'));
71+
}
72+
73+
public function testWriteSession()
74+
{
75+
$this->redis
76+
->expects($this->once())
77+
->method('set')
78+
->with(self::PREFIX.'id', 'data', self::TTL)
79+
->will($this->returnValue(true))
80+
;
81+
82+
$this->assertTrue($this->storage->write('id', 'data'));
83+
}
84+
85+
public function testDestroySession()
86+
{
87+
$this->redis
88+
->expects($this->once())
89+
->method('del')
90+
->with(self::PREFIX.'id')
91+
->will($this->returnValue(1))
92+
;
93+
94+
$this->assertTrue($this->storage->destroy('id'));
95+
}
96+
97+
public function testGcSession()
98+
{
99+
$this->assertTrue($this->storage->gc(123));
100+
}
101+
102+
/**
103+
* @dataProvider getOptionFixtures
104+
*/
105+
public function testSupportedOptions(array $options, $supported)
106+
{
107+
try {
108+
new RedisSessionHandler($this->redis, $options);
109+
$this->assertTrue($supported);
110+
} catch (\InvalidArgumentException $e) {
111+
$this->assertFalse($supported);
112+
}
113+
}
114+
115+
public function getOptionFixtures()
116+
{
117+
return array(
118+
array(array('prefix' => 'session'), true),
119+
array(array('expiretime' => 100), true),
120+
array(array('prefix' => 'session', 'expiretime' => 200), true),
121+
array(array('expiretime' => 100, 'foo' => 'bar'), false),
122+
);
123+
}
124+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy