1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\HttpFoundation\Session\Storage;
13:
14: use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
15: use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
16: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
17: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
18: use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
19:
20: 21: 22: 23: 24:
25: class NativeSessionStorage implements SessionStorageInterface
26: {
27: 28: 29: 30: 31:
32: protected $bags;
33:
34: 35: 36:
37: protected $started = false;
38:
39: 40: 41:
42: protected $closed = false;
43:
44: 45: 46:
47: protected $saveHandler;
48:
49: 50: 51:
52: protected $metadataBag;
53:
54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98:
99: public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
100: {
101: session_cache_limiter('');
102: ini_set('session.use_cookies', 1);
103:
104: if (PHP_VERSION_ID >= 50400) {
105: session_register_shutdown();
106: } else {
107: register_shutdown_function('session_write_close');
108: }
109:
110: $this->setMetadataBag($metaBag);
111: $this->setOptions($options);
112: $this->setSaveHandler($handler);
113: }
114:
115: 116: 117: 118: 119:
120: public function getSaveHandler()
121: {
122: return $this->saveHandler;
123: }
124:
125: 126: 127:
128: public function start()
129: {
130: if ($this->started) {
131: return true;
132: }
133:
134: if (PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE === session_status()) {
135: throw new \RuntimeException('Failed to start the session: already started by PHP.');
136: }
137:
138: if (PHP_VERSION_ID < 50400 && !$this->closed && isset($_SESSION) && session_id()) {
139:
140: throw new \RuntimeException('Failed to start the session: already started by PHP ($_SESSION is set).');
141: }
142:
143: if (ini_get('session.use_cookies') && headers_sent($file, $line)) {
144: throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
145: }
146:
147:
148: if (!session_start()) {
149: throw new \RuntimeException('Failed to start the session');
150: }
151:
152: $this->loadSession();
153: if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
154:
155: $this->saveHandler->setActive(true);
156: }
157:
158: return true;
159: }
160:
161: 162: 163:
164: public function getId()
165: {
166: return $this->saveHandler->getId();
167: }
168:
169: 170: 171:
172: public function setId($id)
173: {
174: $this->saveHandler->setId($id);
175: }
176:
177: 178: 179:
180: public function getName()
181: {
182: return $this->saveHandler->getName();
183: }
184:
185: 186: 187:
188: public function setName($name)
189: {
190: $this->saveHandler->setName($name);
191: }
192:
193: 194: 195:
196: public function regenerate($destroy = false, $lifetime = null)
197: {
198: if (null !== $lifetime) {
199: ini_set('session.cookie_lifetime', $lifetime);
200: }
201:
202: if ($destroy) {
203: $this->metadataBag->stampNew();
204: }
205:
206: return session_regenerate_id($destroy);
207: }
208:
209: 210: 211:
212: public function save()
213: {
214: session_write_close();
215:
216: if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
217:
218: $this->saveHandler->setActive(false);
219: }
220:
221: $this->closed = true;
222: $this->started = false;
223: }
224:
225: 226: 227:
228: public function clear()
229: {
230:
231: foreach ($this->bags as $bag) {
232: $bag->clear();
233: }
234:
235:
236: $_SESSION = array();
237:
238:
239: $this->loadSession();
240: }
241:
242: 243: 244:
245: public function registerBag(SessionBagInterface $bag)
246: {
247: $this->bags[$bag->getName()] = $bag;
248: }
249:
250: 251: 252:
253: public function getBag($name)
254: {
255: if (!isset($this->bags[$name])) {
256: throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
257: }
258:
259: if ($this->saveHandler->isActive() && !$this->started) {
260: $this->loadSession();
261: } elseif (!$this->started) {
262: $this->start();
263: }
264:
265: return $this->bags[$name];
266: }
267:
268: 269: 270: 271: 272:
273: public function setMetadataBag(MetadataBag $metaBag = null)
274: {
275: if (null === $metaBag) {
276: $metaBag = new MetadataBag();
277: }
278:
279: $this->metadataBag = $metaBag;
280: }
281:
282: 283: 284: 285: 286:
287: public function getMetadataBag()
288: {
289: return $this->metadataBag;
290: }
291:
292: 293: 294:
295: public function isStarted()
296: {
297: return $this->started;
298: }
299:
300: 301: 302: 303: 304: 305: 306: 307: 308: 309:
310: public function setOptions(array $options)
311: {
312: $validOptions = array_flip(array(
313: 'cache_limiter', 'cookie_domain', 'cookie_httponly',
314: 'cookie_lifetime', 'cookie_path', 'cookie_secure',
315: 'entropy_file', 'entropy_length', 'gc_divisor',
316: 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
317: 'hash_function', 'name', 'referer_check',
318: 'serialize_handler', 'use_cookies',
319: 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
320: 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
321: 'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags',
322: ));
323:
324: foreach ($options as $key => $value) {
325: if (isset($validOptions[$key])) {
326: ini_set('session.'.$key, $value);
327: }
328: }
329: }
330:
331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352:
353: public function setSaveHandler($saveHandler = null)
354: {
355: if (!$saveHandler instanceof AbstractProxy &&
356: !$saveHandler instanceof NativeSessionHandler &&
357: !$saveHandler instanceof \SessionHandlerInterface &&
358: null !== $saveHandler) {
359: throw new \InvalidArgumentException('Must be instance of AbstractProxy or NativeSessionHandler; implement \SessionHandlerInterface; or be null.');
360: }
361:
362:
363: if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
364: $saveHandler = new SessionHandlerProxy($saveHandler);
365: } elseif (!$saveHandler instanceof AbstractProxy) {
366: $saveHandler = PHP_VERSION_ID >= 50400 ?
367: new SessionHandlerProxy(new \SessionHandler()) : new NativeProxy();
368: }
369: $this->saveHandler = $saveHandler;
370:
371: if ($this->saveHandler instanceof \SessionHandlerInterface) {
372: if (PHP_VERSION_ID >= 50400) {
373: session_set_save_handler($this->saveHandler, false);
374: } else {
375: session_set_save_handler(
376: array($this->saveHandler, 'open'),
377: array($this->saveHandler, 'close'),
378: array($this->saveHandler, 'read'),
379: array($this->saveHandler, 'write'),
380: array($this->saveHandler, 'destroy'),
381: array($this->saveHandler, 'gc')
382: );
383: }
384: }
385: }
386:
387: 388: 389: 390: 391: 392: 393: 394: 395: 396:
397: protected function loadSession(array &$session = null)
398: {
399: if (null === $session) {
400: $session = &$_SESSION;
401: }
402:
403: $bags = array_merge($this->bags, array($this->metadataBag));
404:
405: foreach ($bags as $bag) {
406: $key = $bag->getStorageKey();
407: $session[$key] = isset($session[$key]) ? $session[$key] : array();
408: $bag->initialize($session[$key]);
409: }
410:
411: $this->started = true;
412: $this->closed = false;
413: }
414: }
415: