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

Namespaces

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

Classes

  • AbstractCacheSession
  • AbstractSession
  • MemcachedSession
  • RedisSession
  • 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        * Checks if the session hasn't been hijacked
 83        *
 84        * @author Art <a.molcanovas@gmail.com>
 85        * @return boolean TRUE if the check has passed, FALSE if not and the
 86        *         session has been terminated.
 87        */
 88       protected function identityCheck() {
 89          $token = self::getToken();
 90 
 91          if(!\get($this->data[ALO_SESSION_FINGERPRINT])) {
 92             $this->data[ALO_SESSION_FINGERPRINT] = $token;
 93             \Log::debug('Session identity check passed');
 94          } elseif($token !== $this->data[ALO_SESSION_FINGERPRINT]) {
 95             \Log::debug('Session identity check failed');
 96             $this->terminate();
 97 
 98             return false;
 99          }
100 
101          return true;
102       }
103 
104       /**
105        * Generates a session token
106        *
107        * @author Art <a.molcanovas@gmail.com>
108        * @return string
109        */
110       protected static function getToken() {
111          return md5('sЕss' . Security::getFingerprint() . 'ия');
112       }
113 
114       /**
115        * Terminates the session
116        *
117        * @author Art <a.molcanovas@gmail.com>
118        * @return AbstractSession
119        */
120       function terminate() {
121          $this->save = false;
122          Cookie::delete(ALO_SESSION_COOKIE);
123          \Log::debug('Terminated session');
124 
125          return $this;
126       }
127 
128       /**
129        * Removes expired session keys
130        *
131        * @author Art <a.molcanovas@gmail.com>
132        * @return SQLSession
133        */
134       protected function removeExpired() {
135          if(isset($this->data[self::EXPIRE_KEY])) {
136             foreach($this->data[self::EXPIRE_KEY] as $k => $v) {
137                if($this->time > $v) {
138                   unset($this->data[self::EXPIRE_KEY][$k], $this->data[$k]);
139                }
140             }
141             if(empty($this->data[self::EXPIRE_KEY])) {
142                unset($this->data[self::EXPIRE_KEY]);
143             }
144 
145             \Log::debug('Removed expired session keys');
146          }
147 
148          return $this;
149       }
150 
151       /**
152        * Fetches session data
153        *
154        * @author Art <a.molcanovas@gmail.com>
155        * @return AbstractSession
156        */
157       abstract protected function fetch();
158 
159       /**
160        * Refreshes the user's session token. This will have no effect unless you overwrite the token during runtime.
161        *
162        * @author      Art <a.molcanovas@gmail.com>
163        * @return bool Whether the user passes the identity check after the token refresh. The session is terminated if
164        *              the identity check fails.
165        */
166       function refreshToken() {
167          unset($this->data[ALO_SESSION_FINGERPRINT]);
168 
169          return $this->identityCheck();
170       }
171 
172       /**
173        * Returns the expected session token
174        *
175        * @author Art <a.molcanovas@gmail.com>
176        * @return string
177        */
178       function getTokenExpected() {
179          return self::getToken();
180       }
181 
182       /**
183        * Returns the actual session token
184        *
185        * @author Art <a.molcanovas@gmail.com>
186        * @return string|null
187        */
188       function getTokenActual() {
189          return \get($this->data[ALO_SESSION_FINGERPRINT]);
190       }
191 
192       /**
193        * Clears all session variables except for the token
194        *
195        * @author Art <a.molcanovas@gmail.com>
196        * @return AbstractSession
197        */
198       function clear() {
199          $token      = \get($this->data[ALO_SESSION_FINGERPRINT]);
200          $this->data = [];
201 
202          if($token) {
203             $this->data[ALO_SESSION_FINGERPRINT] = $token;
204          }
205 
206          return $this;
207       }
208 
209       /**
210        * Gets a session value
211        *
212        * @author Art <a.molcanovas@gmail.com>
213        *
214        * @param string $key The identifier
215        *
216        * @return mixed
217        */
218       function __get($key) {
219          return \get($this->data[$key]);
220       }
221 
222       /**
223        * Sets a session value
224        *
225        * @author Art <a.molcanovas@gmail.com>
226        *
227        * @param string $key The identifier
228        * @param mixed  $val The value
229        */
230       function __set($key, $val) {
231          $this->data[$key] = $val;
232       }
233 
234       /**
235        * Force-calls the write method
236        *
237        * @author Art <a.molcanovas@gmail.com>
238        * @see    AbstractSession::write()
239        * @return AbstractSession
240        */
241       function forceWrite() {
242          return $this->write();
243       }
244 
245       /**
246        * Saves session data
247        *
248        * @author Art <a.molcanovas@gmail.com>
249        * @return AbstractSession
250        */
251       abstract protected function write();
252 
253       /**
254        * Unsets a session key
255        *
256        * @author Art <a.molcanovas@gmail.com>
257        *
258        * @param string $key The session value's key
259        */
260       function __unset($key) {
261          $this->delete($key);
262       }
263 
264       /**
265        * Deletes a session value
266        *
267        * @author Art <a.molcanovas@gmail.com>
268        *
269        * @param string|array $key The corresponding key or array of keys
270        *
271        * @return AbstractSession
272        */
273       function delete($key) {
274          if(is_array($key)) {
275             foreach($key as $k) {
276                unset($this->data[$k]);
277             }
278          } else {
279             \Log::debug('Removed session key ' . $key);
280             unset($this->data[$key]);
281          }
282 
283          return $this;
284       }
285 
286       /**
287        * Checks if a session key is set
288        *
289        * @author Art <a.molcanovas@gmail.com>
290        *
291        * @param string $key The key
292        *
293        * @return bool
294        */
295       function __isset($key) {
296          return isset($this->data[$key]);
297       }
298 
299       /**
300        * Returns a string representation of the session data
301        *
302        * @author Art <a.molcanovas@gmail.com>
303        * @return string
304        */
305       function __toString() {
306          $r = 'ID: ' . $this->id . "\nData:";
307 
308          foreach($this->data as $k => $v) {
309             echo "\n\t$k => $v";
310          }
311 
312          return $r;
313       }
314 
315       /**
316        * Returns all session data in an associative array
317        *
318        * @author Art <a.molcanovas@gmail.com>
319        * @return array
320        */
321       function getAll() {
322          return $this->data;
323       }
324 
325       /**
326        * Returns the session ID
327        *
328        * @author Art <a.molcanovas@gmail.com>
329        * @return string
330        */
331       function getID() {
332          return $this->id;
333       }
334 
335       /**
336        * Sets the session ID variable & the cookie
337        *
338        * @author Art <a.molcanovas@gmail.com>
339        * @return SQLSession
340        */
341       protected function setID() {
342          $c = \get($_COOKIE[ALO_SESSION_COOKIE]);
343 
344          if($c && strlen($c) == 128) {
345             $this->id = $c;
346          } else {
347             $this->id = Security::getUniqid(self::HASH_ALGO, 'session');
348          }
349 
350          \Log::debug('Session ID set to ' . $this->id);
351          Cookie::set(ALO_SESSION_COOKIE, $this->id, $this->time + ALO_SESSION_TIMEOUT, '/', '', false, true);
352 
353          return $this;
354       }
355 
356       /**
357        * Sets a session key to expire
358        *
359        * @author Art <a.molcanovas@gmail.com>
360        *
361        * @param string $key  The key
362        * @param int    $time Expiration time in seconds
363        *
364        * @return AbstractSession
365        */
366       function expire($key, $time) {
367          $e = &$this->data[self::EXPIRE_KEY][$key];
368          $e = $this->time + $time;
369 
370          \Log::debug('Set the session key ' . $key . ' to expire in ' . $time . ' seconds');
371 
372          return $this;
373       }
374 
375       /**
376        * Saves session data if $this->save hasn't been changed to false
377        *
378        * @author Art <a.molcanovas@gmail.com>
379        */
380       function __destruct() {
381          if($this->save) {
382             $this->write();
383          }
384       }
385 
386    }
AloFramework documentation API documentation generated by ApiGen 2.8.0