AloFramework documentation
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  • Download

Namespaces

  • Alo
    • Cache
    • Controller
    • Db
    • Exception
    • Session
    • Statics
    • Test
    • Validators
  • Controller
  • None
  • PHP

Classes

  • AbstractSession
  • MemcachedSession
  • SQLSession
  1 <?php
  2 
  3    namespace Alo\Session;
  4 
  5    use Alo\Statics\Cookie;
  6    use Alo\Statics\Security;
  7 
  8    if (!defined('GEN_START')) {
  9       http_response_code(404);
 10       die();
 11    }
 12    \Alo::loadConfig('session');
 13 
 14    /**
 15     * The session interface
 16     *
 17     * @author  Art <a.molcanovas@gmail.com>
 18     * @package Session
 19     */
 20    abstract class AbstractSession {
 21 
 22       /**
 23        * Hash algorithm in use
 24        *
 25        * @var string
 26        */
 27       const HASH_ALGO = 'sha512';
 28 
 29       /**
 30        * Session key under which key expiration data is stored
 31        *
 32        * @var string
 33        */
 34       const EXPIRE_KEY = '__expire';
 35 
 36       /**
 37        * The data array
 38        *
 39        * @var array
 40        */
 41       protected $data;
 42 
 43       /**
 44        * Whether to save session data
 45        *
 46        * @var boolean
 47        */
 48       protected $save;
 49 
 50       /**
 51        * Value of time()
 52        *
 53        * @var int
 54        */
 55       protected $time;
 56 
 57       /**
 58        * The session ID
 59        *
 60        * @var string
 61        */
 62       protected $id;
 63 
 64       /**
 65        * Instantiates the class
 66        *
 67        * @author Art <a.molcanovas@gmail.com>
 68        */
 69       function __construct() {
 70          $this->data = [];
 71          $this->time = time();
 72          $this->save = true;
 73 
 74          $this->setID();
 75 
 76          if (\Alo::$router->is_cli_request() || $this->identityCheck()) {
 77             $this->fetch()->removeExpired();
 78          }
 79       }
 80 
 81       /**
 82        * Saves session data
 83        *
 84        * @author Art <a.molcanovas@gmail.com>
 85        * @return AbstractSession
 86        */
 87       abstract protected function write();
 88 
 89       /**
 90        * Sets the session ID variable & the cookie
 91        *
 92        * @author Art <a.molcanovas@gmail.com>
 93        * @return SQLSession
 94        */
 95       protected function setID() {
 96          $c = \get($_COOKIE[ALO_SESSION_COOKIE]);
 97 
 98          if ($c && strlen($c) == 128) {
 99             $this->id = $c;
100          } else {
101             $this->id = Security::getUniqid(self::HASH_ALGO, 'session');
102          }
103 
104          \Log::debug('Session ID set to ' . $this->id);
105          Cookie::set(ALO_SESSION_COOKIE, $this->id, $this->time + ALO_SESSION_TIMEOUT, '/', '', false, true);
106 
107          return $this;
108       }
109 
110       /**
111        * Fetches session data
112        *
113        * @author Art <a.molcanovas@gmail.com>
114        * @return AbstractSession
115        */
116       abstract protected function fetch();
117 
118       /**
119        * Removes expired session keys
120        *
121        * @author Art <a.molcanovas@gmail.com>
122        * @return SQLSession
123        */
124       protected function removeExpired() {
125          if (isset($this->data[self::EXPIRE_KEY])) {
126             foreach ($this->data[self::EXPIRE_KEY] as $k => $v) {
127                if ($this->time > $v) {
128                   unset($this->data[self::EXPIRE_KEY][$k], $this->data[$k]);
129                }
130             }
131             if (empty($this->data[self::EXPIRE_KEY])) {
132                unset($this->data[self::EXPIRE_KEY]);
133             }
134 
135             \Log::debug('Removed expired session keys');
136          }
137 
138          return $this;
139       }
140 
141       /**
142        * Checks if the session hasn't been hijacked
143        *
144        * @author Art <a.molcanovas@gmail.com>
145        * @return boolean TRUE if the check has passed, FALSE if not and the
146        *         session has been terminated.
147        */
148       protected function identityCheck() {
149          $token = self::getToken();
150 
151          if (!\get($this->data[ALO_SESSION_FINGERPRINT])) {
152             $this->data[ALO_SESSION_FINGERPRINT] = $token;
153             \Log::debug('Session identity check passed');
154          } elseif ($token !== $this->data[ALO_SESSION_FINGERPRINT]) {
155             \Log::debug('Session identity check failed');
156             $this->terminate();
157 
158             return false;
159          }
160 
161          return true;
162       }
163 
164       /**
165        * Refreshes the user's session token. This will have no effect unless you overwrite the token during runtime.
166        *
167        * @author      Art <a.molcanovas@gmail.com>
168        * @return bool Whether the user passes the identity check after the token refresh. The session is terminated if
169        *              the identity check fails.
170        */
171       function refreshToken() {
172          unset($this->data[ALO_SESSION_FINGERPRINT]);
173 
174          return $this->identityCheck();
175       }
176 
177       /**
178        * Generates a session token
179        *
180        * @author Art <a.molcanovas@gmail.com>
181        * @return string
182        */
183       protected static function getToken() {
184          return md5('sЕss' . Security::getFingerprint() . 'ия');
185       }
186 
187       /**
188        * Returns the expected session token
189        *
190        * @author Art <a.molcanovas@gmail.com>
191        * @return string
192        */
193       function getTokenExpected() {
194          return self::getToken();
195       }
196 
197       /**
198        * Returns the actual session token
199        *
200        * @author Art <a.molcanovas@gmail.com>
201        * @return string|null
202        */
203       function getTokenActual() {
204          return \get($this->data[ALO_SESSION_FINGERPRINT]);
205       }
206 
207       /**
208        * Clears all session variables except for the token
209        *
210        * @author Art <a.molcanovas@gmail.com>
211        * @return AbstractSession
212        */
213       function clear() {
214          $token = \get($this->data[ALO_SESSION_FINGERPRINT]);
215          $this->data = [];
216 
217          if ($token) {
218             $this->data[ALO_SESSION_FINGERPRINT] = $token;
219          }
220 
221          return $this;
222       }
223 
224       /**
225        * Gets a session value
226        *
227        * @author Art <a.molcanovas@gmail.com>
228        * @param string $key The identifier
229        * @return mixed
230        */
231       function __get($key) {
232          return \get($this->data[$key]);
233       }
234 
235       /**
236        * Force-calls the write method
237        *
238        * @author Art <a.molcanovas@gmail.com>
239        * @see    AbstractSession::write()
240        * @return AbstractSession
241        */
242       function forceWrite() {
243          return $this->write();
244       }
245 
246       /**
247        * Sets a session value
248        *
249        * @author Art <a.molcanovas@gmail.com>
250        * @param string $key The identifier
251        * @param mixed  $val The value
252        */
253       function __set($key, $val) {
254          $this->data[$key] = $val;
255       }
256 
257       /**
258        * Unsets a session key
259        *
260        * @author Art <a.molcanovas@gmail.com>
261        * @param string $key The session value's key
262        */
263       function __unset($key) {
264          $this->delete($key);
265       }
266 
267       /**
268        * Checks if a session key is set
269        *
270        * @author Art <a.molcanovas@gmail.com>
271        * @param string $key The key
272        * @return bool
273        */
274       function __isset($key) {
275          return isset($this->data[$key]);
276       }
277 
278       /**
279        * Returns a string representation of the session data
280        *
281        * @author Art <a.molcanovas@gmail.com>
282        * @return string
283        */
284       function __toString() {
285          $r = 'ID: ' . $this->id . "\nData:";
286 
287          foreach ($this->data as $k => $v) {
288             echo "\n\t$k => $v";
289          }
290 
291          return $r;
292       }
293 
294       /**
295        * Deletes a session value
296        *
297        * @author Art <a.molcanovas@gmail.com>
298        * @param string|array $key The corresponding key or array of keys
299        * @return AbstractSession
300        */
301       function delete($key) {
302          if (is_array($key)) {
303             foreach ($key as $k) {
304                unset($this->data[$k]);
305             }
306          } else {
307             \Log::debug('Removed session key ' . $key);
308             unset($this->data[$key]);
309          }
310 
311          return $this;
312       }
313 
314       /**
315        * Returns all session data in an associative array
316        *
317        * @author Art <a.molcanovas@gmail.com>
318        * @return array
319        */
320       function getAll() {
321          return $this->data;
322       }
323 
324       /**
325        * Returns the session ID
326        *
327        * @author Art <a.molcanovas@gmail.com>
328        * @return string
329        */
330       function getID() {
331          return $this->id;
332       }
333 
334       /**
335        * Sets a session key to expire
336        *
337        * @author Art <a.molcanovas@gmail.com>
338        * @param string $key  The key
339        * @param int    $time Expiration time in seconds
340        * @return AbstractSession
341        */
342       function expire($key, $time) {
343          $e = &$this->data[self::EXPIRE_KEY][$key];
344          $e = $this->time + $time;
345 
346          \Log::debug('Set the session key ' . $key . ' to expire in ' . $time . ' seconds');
347 
348          return $this;
349       }
350 
351       /**
352        * Terminates the session
353        *
354        * @author Art <a.molcanovas@gmail.com>
355        * @return AbstractSession
356        */
357       function terminate() {
358          $this->save = false;
359          Cookie::delete(ALO_SESSION_COOKIE);
360          \Log::debug('Terminated session');
361 
362          return $this;
363       }
364 
365       /**
366        * Saves session data if $this->save hasn't been changed to false
367        *
368        * @author Art <a.molcanovas@gmail.com>
369        */
370       function __destruct() {
371          if ($this->save) {
372             $this->write();
373          }
374       }
375 
376    }
AloFramework documentation API documentation generated by ApiGen 2.8.0