1 <?php
2
3 namespace Alo\Session;
4
5 use Alo;
6 use Alo\Statics\Security;
7 use SessionHandlerInterface;
8
9 if (!defined('GEN_START')) {
10 http_response_code(404);
11 } else {
12
13 Alo::loadConfig('session');
14
15 /**
16 * The session interface
17 *
18 * @author Art <a.molcanovas@gmail.com>
19 * @package Session
20 */
21 abstract class AbstractSession implements SessionHandlerInterface {
22
23 /**
24 * Instantiates the class
25 *
26 * @author Art <a.molcanovas@gmail.com>
27 */
28 function __construct() {
29 $this->setID();
30 }
31
32 /**
33 * Performs the internal steps of initialising a session
34 *
35 * @author Art <a.molcanovas@gmail.com>
36 *
37 * @param Alo\Db\MySQL|Alo\Cache\AbstractCache $dependcyObject Session handlers have a dependency, e.g. a MySQL
38 * instance for MySQLSession, a RedisWrapper instance
39 * for RedisSession etc. You can provide an object
40 * reference containing such an instance here,
41 * otherwise Alo::$db/Alo::$cache will be used.
42 * @param string $handler If you want to test a session with a different
43 * handler you can overwrite it here by passing a
44 * class name
45 */
46 protected static function initSession(&$dependcyObject = null, $handler = ALO_SESSION_HANDLER) {
47 if (session_status() !== PHP_SESSION_ACTIVE) {
48 session_set_cookie_params(ALO_SESSION_TIMEOUT, null, null, ALO_SESSION_SECURE, true);
49 session_name(ALO_SESSION_COOKIE);
50
51 /** @var Alo\Session\AbstractSession $handler */
52 $handler = new $handler($dependcyObject);
53
54 session_set_save_handler($handler, true);
55 session_start();
56 $handler->identityCheck();
57 } else {
58 phpWarning('A session has already been started');
59 }
60 }
61
62 /**
63 * Only calls session_destroy() if a session is active
64 *
65 * @author Art <a.molcanovas@gmail.com>
66 * @return bool
67 */
68 static function destroySafely() {
69 if (self::isActive()) {
70 session_destroy();
71
72 return true;
73 } else {
74 return false;
75 }
76 }
77
78 /**
79 * Checks whether a session is currently active
80 * @author Art <a.molcanovas@gmail.com>
81 * @return bool
82 */
83 static function isActive() {
84 return session_status() === PHP_SESSION_ACTIVE;
85 }
86
87 /**
88 * Closes the session
89 *
90 * @author Art <a.molcanovas@gmail.com>
91 * @return bool
92 */
93 function close() {
94 return true;
95 }
96
97 /**
98 * Cleans old sessions
99 *
100 * @author Art <a.molcanovas@gmail.com>
101 *
102 * @param int $maxlifetime Sessions that have not updated for the last maxlifetime seconds will be removed.
103 *
104 * @return bool
105 */
106 function gc($maxlifetime) {
107 unset($maxlifetime);
108
109 return true;
110 }
111
112 /**
113 * Initialize session
114 *
115 * @author Art <a.molcanovas@gmail.com>
116 * @link http://php.net/manual/en/sessionhandlerinterface.open.php
117 *
118 * @param string $savePath Unused, but required for the interface
119 * @param string $sessionID Unused, but required for the interface
120 *
121 * @return bool
122 */
123 function open($savePath, $sessionID) {
124 unset($savePath, $sessionID);
125
126 return true;
127 }
128
129 /**
130 * Checks if the session hasn't been hijacked
131 *
132 * @author Art <a.molcanovas@gmail.com>
133 * @return boolean TRUE if the check has passed, FALSE if not and the
134 * session has been terminated.
135 */
136 function identityCheck() {
137 $token = self::getToken();
138 if (!get($_SESSION[ALO_SESSION_FINGERPRINT])) {
139 $_SESSION[ALO_SESSION_FINGERPRINT] = $token;
140 } elseif ($token !== $_SESSION[ALO_SESSION_FINGERPRINT]) {
141 \Log::debug('Session identity check failed');
142 $this->destroy(session_id());
143
144 return false;
145 }
146 \Log::debug('Session identity check passed');
147
148 return true;
149 }
150
151 /**
152 * Destroys a session
153 *
154 * @author Art <a.molcanovas@gmail.com>
155 *
156 * @param string $sessionID The ID to destroy
157 *
158 * @return bool
159 */
160 function destroy($sessionID) {
161 unset($sessionID);
162 setcookie(ALO_SESSION_COOKIE, '', time() - 3, null, null, ALO_SESSION_SECURE, true);
163
164 return true;
165 }
166
167 /**
168 * Generates a session token
169 *
170 * @author Art <a.molcanovas@gmail.com>
171 * @return string
172 */
173 protected static function getToken() {
174 return md5('sЕss' . Security::getFingerprint() . 'ия');
175 }
176
177 /**
178 * Sets the session ID variable & the cookie
179 *
180 * @author Art <a.molcanovas@gmail.com>
181 * @return AbstractSession
182 */
183 protected function setID() {
184 $c = get($_COOKIE[ALO_SESSION_COOKIE]);
185
186 if ($c && strlen($c) == 128) {
187 session_id($c);
188 } else {
189 session_id(Security::getUniqid('sha512', 'session'));
190 }
191
192 \Log::debug('Session ID set to ' . session_id());
193
194 return $this;
195 }
196 }
197 }
198