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;
13:
14: /**
15: * MockFileSessionStorage is used to mock sessions for
16: * functional testing when done in a single PHP process.
17: *
18: * No PHP session is actually started since a session can be initialized
19: * and shutdown only once per PHP execution cycle and this class does
20: * not pollute any session related globals, including session_*() functions
21: * or session.* PHP ini directives.
22: *
23: * @author Drak <drak@zikula.org>
24: */
25: class MockFileSessionStorage extends MockArraySessionStorage
26: {
27: /**
28: * @var string
29: */
30: private $savePath;
31:
32: /**
33: * @var array
34: */
35: private $sessionData;
36:
37: /**
38: * Constructor.
39: *
40: * @param string $savePath Path of directory to save session files.
41: * @param string $name Session name.
42: * @param MetadataBag $metaBag MetadataBag instance.
43: */
44: public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null)
45: {
46: if (null === $savePath) {
47: $savePath = sys_get_temp_dir();
48: }
49:
50: if (!is_dir($savePath)) {
51: mkdir($savePath, 0777, true);
52: }
53:
54: $this->savePath = $savePath;
55:
56: parent::__construct($name, $metaBag);
57: }
58:
59: /**
60: * {@inheritdoc}
61: */
62: public function start()
63: {
64: if ($this->started) {
65: return true;
66: }
67:
68: if (!$this->id) {
69: $this->id = $this->generateId();
70: }
71:
72: $this->read();
73:
74: $this->started = true;
75:
76: return true;
77: }
78:
79: /**
80: * {@inheritdoc}
81: */
82: public function regenerate($destroy = false, $lifetime = null)
83: {
84: if (!$this->started) {
85: $this->start();
86: }
87:
88: if ($destroy) {
89: $this->destroy();
90: }
91:
92: return parent::regenerate($destroy, $lifetime);
93: }
94:
95: /**
96: * {@inheritdoc}
97: */
98: public function save()
99: {
100: if (!$this->started) {
101: throw new \RuntimeException("Trying to save a session that was not started yet or was already closed");
102: }
103:
104: file_put_contents($this->getFilePath(), serialize($this->data));
105:
106: // this is needed for Silex, where the session object is re-used across requests
107: // in functional tests. In Symfony, the container is rebooted, so we don't have
108: // this issue
109: $this->started = false;
110: }
111:
112: /**
113: * Deletes a session from persistent storage.
114: * Deliberately leaves session data in memory intact.
115: */
116: private function destroy()
117: {
118: if (is_file($this->getFilePath())) {
119: unlink($this->getFilePath());
120: }
121: }
122:
123: /**
124: * Calculate path to file.
125: *
126: * @return string File path
127: */
128: private function getFilePath()
129: {
130: return $this->savePath.'/'.$this->id.'.mocksess';
131: }
132:
133: /**
134: * Reads session from storage and loads session.
135: */
136: private function read()
137: {
138: $filePath = $this->getFilePath();
139: $this->data = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array();
140:
141: $this->loadSession();
142: }
143: }
144: