Skip to content

Commit ddc436d

Browse files
authored
Session lazy psr16 (#197)
new psr-16 SessionHandler implemented PHP 7.0's `SessionUpdateTimestampHandlerInterface` with a new `AbstractSessionHandler` base class
1 parent 5874420 commit ddc436d

File tree

8 files changed

+561
-52
lines changed

8 files changed

+561
-52
lines changed

AbstractSessionHandler.php

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-cache organization.
5+
*
6+
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Cache\SessionHandler;
13+
14+
/**
15+
* @author Daniel Bannert <[email protected]>
16+
*
17+
* ported from https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php
18+
*/
19+
abstract class AbstractSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
20+
{
21+
/**
22+
* @type string|null
23+
*/
24+
private $sessionName;
25+
26+
/**
27+
* @type string|null
28+
*/
29+
private $prefetchId;
30+
31+
/**
32+
* @type string|null
33+
*/
34+
private $prefetchData;
35+
36+
/**
37+
* @type string|null
38+
*/
39+
private $newSessionId;
40+
41+
/**
42+
* @type string|null
43+
*/
44+
private $igbinaryEmptyData;
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
public function open($savePath, $sessionName)
50+
{
51+
$this->sessionName = $sessionName;
52+
53+
return true;
54+
}
55+
56+
/**
57+
* {@inheritdoc}
58+
*/
59+
public function validateId($sessionId)
60+
{
61+
$this->prefetchData = $this->read($sessionId);
62+
$this->prefetchId = $sessionId;
63+
64+
return $this->prefetchData !== '';
65+
}
66+
67+
/**
68+
* {@inheritdoc}
69+
*/
70+
public function read($sessionId)
71+
{
72+
if ($this->prefetchId !== null) {
73+
$prefetchId = $this->prefetchId;
74+
$prefetchData = $this->prefetchData;
75+
76+
$this->prefetchId = $this->prefetchData = null;
77+
78+
if ($prefetchId === $sessionId || '' === $prefetchData) {
79+
$this->newSessionId = '' === $prefetchData ? $sessionId : null;
80+
81+
return $prefetchData;
82+
}
83+
}
84+
85+
$data = $this->doRead($sessionId);
86+
$this->newSessionId = '' === $data ? $sessionId : null;
87+
88+
if (\PHP_VERSION_ID < 70000) {
89+
$this->prefetchData = $data;
90+
}
91+
92+
return $data;
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
public function write($sessionId, $data)
99+
{
100+
if (\PHP_VERSION_ID < 70000 && $this->prefetchData) {
101+
$readData = $this->prefetchData;
102+
$this->prefetchData = null;
103+
104+
if ($readData === $data) {
105+
return $this->updateTimestamp($sessionId, $data);
106+
}
107+
}
108+
109+
if ($this->igbinaryEmptyData === null) {
110+
// see igbinary/igbinary/issues/146
111+
$this->igbinaryEmptyData = \function_exists('igbinary_serialize') ? igbinary_serialize([]) : '';
112+
}
113+
114+
if ($data === '' || $this->igbinaryEmptyData === $data) {
115+
return $this->destroy($sessionId);
116+
}
117+
118+
$this->newSessionId = null;
119+
120+
return $this->doWrite($sessionId, $data);
121+
}
122+
123+
/**
124+
* {@inheritdoc}
125+
*/
126+
public function destroy($sessionId)
127+
{
128+
if (\PHP_VERSION_ID < 70000) {
129+
$this->prefetchData = null;
130+
}
131+
132+
return $this->newSessionId === $sessionId || $this->doDestroy($sessionId);
133+
}
134+
135+
/**
136+
* {@inheritdoc}
137+
*/
138+
public function close()
139+
{
140+
return true;
141+
}
142+
143+
/**
144+
* {@inheritdoc}
145+
*/
146+
public function gc($lifetime)
147+
{
148+
// not required here because cache will auto expire the records anyhow.
149+
return true;
150+
}
151+
152+
/**
153+
* @param string $sessionId
154+
*
155+
* @return string
156+
*/
157+
abstract protected function doRead($sessionId);
158+
159+
/**
160+
* @param string $sessionId
161+
* @param string $data
162+
*
163+
* @return bool
164+
*/
165+
abstract protected function doWrite($sessionId, $data);
166+
167+
/**
168+
* @param string $sessionId
169+
*
170+
* @return bool
171+
*/
172+
abstract protected function doDestroy($sessionId);
173+
}

Changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" betwee
44

55
## UNRELEASED
66

7+
## 1.1.0
8+
9+
### Added
10+
11+
* new psr-16 SessionHandler
12+
* implemented PHP 7.0's `SessionUpdateTimestampHandlerInterface` with a new
13+
`AbstractSessionHandler` base class
14+
715
## 1.0.0
816

917
* No changes since 0.2.1

Psr16SessionHandler.php

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-cache organization.
5+
*
6+
* (c) 2015 Aaron Scherer <[email protected]>, Tobias Nyholm <[email protected]>
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Cache\SessionHandler;
13+
14+
use Psr\SimpleCache\CacheInterface;
15+
16+
/**
17+
* @author Daniel Bannert <[email protected]>
18+
*/
19+
class Psr16SessionHandler extends AbstractSessionHandler
20+
{
21+
/**
22+
* @type CacheInterface
23+
*/
24+
private $cache;
25+
26+
/**
27+
* @type int Time to live in seconds
28+
*/
29+
private $ttl;
30+
31+
/**
32+
* @type string Key prefix for shared environments.
33+
*/
34+
private $prefix;
35+
36+
/**
37+
* @param CacheInterface $cache
38+
* @param array $options {
39+
* @type int $ttl The time to live in seconds
40+
* @type string $prefix The prefix to use for the cache keys in order to avoid collision
41+
* }
42+
*
43+
* @throws \InvalidArgumentException
44+
*/
45+
public function __construct(CacheInterface $cache, array $options = [])
46+
{
47+
$this->cache = $cache;
48+
49+
if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) {
50+
throw new \InvalidArgumentException(sprintf(
51+
'The following options are not supported "%s"', implode(', ', $diff)
52+
));
53+
}
54+
55+
$this->ttl = isset($options['ttl']) ? (int) $options['ttl'] : 86400;
56+
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'psr16ses_';
57+
}
58+
59+
/**
60+
* {@inheritdoc}
61+
*/
62+
public function updateTimestamp($sessionId, $data)
63+
{
64+
$value = $this->cache->get($this->prefix.$sessionId);
65+
66+
if ($value === null) {
67+
return false;
68+
}
69+
70+
return $this->cache->set(
71+
$this->prefix.$sessionId,
72+
$value,
73+
\DateTime::createFromFormat('U', \time() + $this->ttl)
74+
);
75+
}
76+
77+
/**
78+
* {@inheritdoc}
79+
*
80+
* @throws \Psr\SimpleCache\InvalidArgumentException
81+
*/
82+
protected function doRead($sessionId)
83+
{
84+
return $this->cache->get($this->prefix.$sessionId, '');
85+
}
86+
87+
/**
88+
* {@inheritdoc}
89+
*/
90+
protected function doWrite($sessionId, $data)
91+
{
92+
return $this->cache->set($this->prefix.$sessionId, $data, $this->ttl);
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
protected function doDestroy($sessionId)
99+
{
100+
return $this->cache->delete($this->prefix.$sessionId);
101+
}
102+
}

0 commit comments

Comments
 (0)