summaryrefslogtreecommitdiff
path: root/classes
diff options
context:
space:
mode:
authorGeorge Halkiadakis <gchalkiadakis@sklavenitis.co.gr>2023-03-12 07:16:23 +0200
committerGeorge Halkiadakis <gchalkiadakis@sklavenitis.co.gr>2023-03-12 07:16:23 +0200
commit7076343338ae3439f3c86f01144818abe8c31978 (patch)
tree794abb1e6b8f821091fd095341885496b6dad51d /classes
parent47cbb529f5723b246125ae083a193e11481b89ef (diff)
downloadclassroom-7076343338ae3439f3c86f01144818abe8c31978.tar.gz
classroom-7076343338ae3439f3c86f01144818abe8c31978.tar.bz2
classroom-7076343338ae3439f3c86f01144818abe8c31978.zip
add container helpers; constuct public directory-tree
Diffstat (limited to 'classes')
-rw-r--r--classes/Benchmark.php150
-rw-r--r--classes/Cart.php71
-rw-r--r--classes/Database.php331
-rw-r--r--classes/Registry.php129
-rw-r--r--classes/Repository.php43
-rw-r--r--classes/Request.php94
-rw-r--r--classes/Route.php97
-rw-r--r--classes/Security.php923
-rw-r--r--classes/User.php111
-rw-r--r--classes/authenticator/PasswordTrait.php40
-rw-r--r--classes/authenticator/User.php102
-rw-r--r--classes/authenticator/UserInterface.php15
-rw-r--r--classes/authenticator/UserManager.php69
-rw-r--r--classes/authenticator/UserManagerInterface.php21
-rw-r--r--classes/authenticator/UserToken.php33
-rw-r--r--classes/authenticator/UserTokenInterface.php13
-rw-r--r--classes/authenticator/info.md114
-rw-r--r--classes/cache/Cache_interface.php34
-rw-r--r--classes/cache/FileCache.php93
-rw-r--r--classes/cache/MemcachedCache.php37
-rw-r--r--classes/cache/RedisCache.php69
-rw-r--r--classes/session/DatabaseSession.php138
-rw-r--r--classes/session/DefaultSession.php35
-rw-r--r--classes/session/FilesSession.php142
-rw-r--r--classes/session/SessionHandlerInterface.php169
25 files changed, 0 insertions, 3073 deletions
diff --git a/classes/Benchmark.php b/classes/Benchmark.php
deleted file mode 100644
index a7e93ea..0000000
--- a/classes/Benchmark.php
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-
-// define('BENCHMARKED', true); // then you know if class is active
-
-class Benchmark {
-
- private static $timeSpots = Array();
-
- private static $memoryUse = Array();
-
- private static $enableReport = true;
-
-
- /** add_timespot
- * ---
- * add new timespot
- * @param $key : label of timespot
- */
- public static function add_spot(string $key)
- {
- self::$timeSpots[$key] = microtime(true);
- self::$memoryUse[$key] = round(memory_get_usage()/(1024*1024),2);
- }
-
-
- /** exist
- * checks if a benchmark spot with label $key exists
- */
- public static function exist(string $key) : bool
- {
- return isset(self::$timeSpots[$key]);
- }
-
-
- /** desableReport
- * (Self-explanatory)
- */
- public static function disableReport()
- {
- self::$enableReport = false;
- }
-
-
- /** render_benchmark_report
- * ---
- * renders performance report
- * as html comment at the end of webpage in various modes
- * @param $mode (string)
- * + 'comment' (default): include report as html comment
- * + 'html' : include report as a html div
- * + 'code' : include report as a pre/code block
- */
- public static function render_report(string $mode = 'comment' )
- {
- if (self::$enableReport) {
-
- switch ($mode) {
- case 'html':
- $open = '<p>';
- $close = '</b></p>';
- $divider = ":<b>";
- $prefix = '<div>';
- $suffix = '</div>';
- break;
- case 'code':
- $open = '';
- $close = '';
- $divider = ": ";
- $prefix = '<pre>';
- $suffix = '</pre>';
- break;
- case 'comment':
- default:
- $open = '<!--';
- $close = '-->';
- $divider = ":";
- $prefix = '';
- $suffix = '';
- break;
- }
-
- echo $prefix;
-
- // TIME REPORT
- // ---------------------------------------------------------------------
- echo "\n\n{$open} Timings {$close}";
-
- // valid from php 7.3
- // $start = self::$timeSpots[ array_key_first(self::$timespots) ];
- // $end = self::$timeSpots[ array_key_last(self::$timespots) ];
- $start = self::$timeSpots['start'];
- $end = self::$timeSpots['end'];
- $all_dt = number_format($end - $start , 4)*1000 ." ms";
-
-
-
- // if more than 2 timespots
- // echo dt between each spot
- if (count(self::$timeSpots) > 2) {
-
- // calculate dt between spots
- $time_results = array();
- $prev_key = '';
- $prev_time = 0;
- foreach(self::$timeSpots as $key => $t) {
- if (!$prev_time) {
- $prev_time = $t;
- $prev_key = $key;
- }
- else {
- $dt = number_format($t - $prev_time , 4)*1000 ." ms";
- $time_results[] = array(
- 'part' => "{$prev_key}[..{$key}]", ///$key,
- 'dt' => $dt
- );
- $prev_key = $key; //// "{$prev_key}[..{$key}]";
- $prev_time = $t;
- }
- }
-
- // echo timings
- foreach ($time_results as $key => $val) {
- echo "\n\t{$open} {$val['part']} {$divider} {$val['dt']} {$close}";
- }
- }
-
- // echo total time
- echo "\n\t{$open} total {$divider} {$all_dt} {$close}";
-
-
- // MEMORY REPORT
- // ---------------------------------------------------------------------
- echo "\n\n{$open} Memory Usage {$close}";
-
- if (count(self::$memoryUse) > 2) {
-
- foreach (self::$memoryUse as $key => $val) {
- echo "\n\t{$open} {$key} {$divider} {$val}MB {$close}";
- }
-
- } else {
- echo "\n\t{$open} memory usage {$divider} ". round(memory_get_usage()/(1024*1024),2) ."MB {$close}";
- }
-
- echo $suffix;
-
- }
-
- }
-}
diff --git a/classes/Cart.php b/classes/Cart.php
deleted file mode 100644
index 4e6f585..0000000
--- a/classes/Cart.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-class Cart
-{
-
- public function checkout()
- {
-
- }
-
- public function addOrder()
- {
- // get cart from cookie
- // VITAL: validate + sanitize
- //
- // then
- //
- // get address and contact details from post
- }
-
-
- /** history
- * get the last $limit cart-orders
- * @param $limit (int)
- */
- public function history($limit)
- {
- // SELECT O.* , OP.* , P.*
- // FROM orders O
- // lEFT JOIN order_products OP ON OP.oid = O.id
- // LEFT JOIN products P ON P.id = OP.pid
- // WHERE uid = :uid
- // AND O.id IN (
- // SELECT id FROM orders WHERE uid = :uid
- // ORDER BY id DESC
- // )
- //
- // $items = runLimitQuery(sql, [uid = $this->uid], 10)
- //
- // oranize in results = [
- // {
- // oid,
- // prods: [
- // {
- // pid,
- // prodlabel,
- // count
- // },
- // ...
- // ]
- // },
- // ...,
- // ]
- //
- // return $results
-
- }
-}
-
-
-
-/* ---
-orders:
- : id
- : uid (user id)
-
-order_products
- : id
- : oid (order id)
- : pid (product id)
- -- */ \ No newline at end of file
diff --git a/classes/Database.php b/classes/Database.php
deleted file mode 100644
index 35ff65f..0000000
--- a/classes/Database.php
+++ /dev/null
@@ -1,331 +0,0 @@
-<?php
-/** Database Class
- *
- */
-class Database {
-
- /** PROPERTIES
- * -------------------------------------------------------------------------
- */
-
- private $throw_errors;
-
- private $connection = null;
-
- private $result = null;
-
-
- /** METHODS
- * -------------------------------------------------------------------------
- */
-
- /** __construct
- *
- * @param $errors: Set to true, to catch error exceptions.
- * @return void
- */
- public function __construct($errors = false)
- {
- $this->throw_errors = PRODUCTION ? false : true;
-
- if (null == $this->connection) {
- try {
- $this->connection = new PDO(
- "mysql:" . PDO_HOST . ";" . "dbname=" . DB_NAME,
- DB_USER,
- DB_PASS,
- array(
- PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
- PDO::MYSQL_ATTR_LOCAL_INFILE => true
- )
- );
-
- // handle error reporting
- if ($this->throw_errors) {
- $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- }
- $this->setTimezone();
-
- } catch (PDOException $exc) { handle_exception($exc); }
- }
- # return $this->connection;
- }
-
-
- /** disconnect
- * CHECK: not sure if needed
- */
- public function disconnect()
- {
- $this->connection = null;
- }
-
-
- /** set Timezone
- * (Self-explanatory)
- */
- public function setTimezone($timezone = DB_TIMEZONE) {
- // $this->connection->prepare($timezone)->execute();
- }
-
-
- /** lastInsertID
- * returns the ID of last inserted record
- */
- public function lastInsertID()
- {
- return $this->connection->insert_id;
- }
-
-
- /** query
- * ---
- * set and execute a query safely;
- * save results as associative array; DO NOT RETURN RESULTS
- * @param $sql (string): SQL query
- * @param $args (array): array of values to bind into SQL
- * @param $pypass (boolean): flag to bypass security check
- * @return $this (database handler)
- */
- public function query($sql, $args=[])
- {
- try {
-
- $stmt = $this->connection->prepare($sql);
-
- if ($args == []) {
- $result = $stmt->execute();
-
- } else {
- $result = $stmt->execute($args);
-
- }
-
- $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
-
- $this->result = $result;
-
- return $this;
-
- } catch (PDOException $exc) { handle_exception($exc); }
-
- }
-
-
- /** getAll
- * ---
- * return all resulted records
- * use it after db->query();
- */
- public function getAll()
- {
- return ($this->result === null) ? false : $this->result;
- }
-
-
- /** getFirst
- * ---
- * get first row of the resulted query;
- * used when one row is expected
- * ex. $db->query('SELECT * FROM users WHERE id = :id',['id'=>1])->getFirst();
- */
- public function getFirst()
- {
- if (($this->result === null) || ($this->result == [])) {
- return false;
-
- } else { return $this->result[0]; }
- }
-
-
- /** getOnly
- * ---
- * return the first column value of the first row
- * used when only one value is needed
- * ex. $db->query('SELECT Count(id) FROM table',[])->getOnly();
- */
- public function getOnly()
- {
- if (($this->result === null) || ($this->result == [])) {
- return false;
-
- } else { return array_values($this->result[0])[0]; }
- }
-
-
- /** runQuery
- * --- (shortcut method)
- * execute a query safely;
- * return results as associative array
- * @param $sql (string): SQL query
- * @param $args (array): array of values to bind into SQL
- * @param $pypass (boolean): flag to bypass security check
- */
- public function runQuery($sql, $args=[])
- {
- return $this->query($sql, $args)->getAll();
- }
-
-
- /** runLimitQuery( sql, args, limit=100, offset = null )
- * set LIMIT / OFFSET clauses in a secure way
- * @param $sql (string): SQL query
- * @param $args (array): array of values to bind into SQL
- * @param $limit (int): LIMIT number
- * @param $offset (int): OFFSET number
- */
- public function runLimitQuery($sql, $args, $limit = 100, $offset = null)
- {
- $limitStr = $offsetStr = "";
-
- // construct LIMIT clause
- if (is_int($limit)) {
- $limitStr = " LIMIT {$limit}";
-
- // construct OFFSET clause (when a LIMIT pre-exists)
- if (is_int($offset)) {
- $offsetStr =" OFFSET {$offset}";
- }
- }
-
- $sql = $sql . $limitStr . $offsetStr;
-
- return $this->runQuery($sql, $args);
- }
-
-
- /** insert
- * @param $table (string): name of table
- * @param $values: an associative of (fieldName => value) pairs
- *
- * example call:
- * ---
- * $db->insert('products',
- * [
- * 'title' => 'My Dark Chocolate 200g',
- * 'text' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit ...',
- * 'isFood' => 1,
- * 'isToxic' => 0
- * ]
- * );
- *
- * ...which prepares the SQL query:
- * INSERT INTO products (title, text, isFood, isToxic)
- * VALUES (:title, :text, :isFood, :isToxic)
- *
- * ...and injects the values: [ :title => 'My Dark Chocolate 200g' , ... ]
- */
- public function insert($table, array $values)
- {
- $fieldSets = [];
- $valueSets = [];
- $bindSets = [];
-
- foreach($values as $key => $val) {
- $fieldSets[] = $key;
- $valueSets[] =':'. $key;
- $bindSets[':'. $key] = $val;
- }
-
- $sql = "INSERT INTO {$table} (". implode(', ', $fieldSets) .")
- VALUES (". implode(', ', $valueSets) .")";
-
- return $this->runQuery($sql, $bindSets);
- }
-
-
- /** update
- * @param $table (string): name of table
- * @param $values: an associative of (fieldName => value) pairs
- * @param $id: an associative of (fieldName => value) index fields
- *
- * example call:
- * ---
- * $db->update('products',
- * [ 'title' => 'My Chocolate','isFood' => 1 ],
- * [ 'id' => 123 ]
- * );
- *
- * ...which prepares the SQL query:
- * UPDATE products SET `title` = :title, `isFood` = :isFood WHERE id = :id
- *
- * ...and injects: [':title'=> 'My Chocolate' , ':isFood'=> 1 , ':id'=> 123]
- */
- public function update( $table, array $values, array $identity)
- {
- $fieldSets = []; // array of field names
- $idSets = []; // array of data-holders
- $bindSets = []; // array of data-bindings
-
- foreach($values as $key => $val) {
- $fieldSets[] = "{$key} = :{$key}";
- $bindSets[':'. $key] = $val;
- }
-
- foreach($identity as $key => $val) {
- $idSets = "{$key} = :{$key}";
- $bindSets[':'. $key] = $val;
- }
-
- $sql = "UPDATE {$table} SET ". implode(', ', $fieldSets)
- ." WHERE ". implode(" AND ", $idSets);
-
- return $this->runQuery($sql, $bindsArray);
- }
-
-
- /** multiInsert( table, fields , values )
- * Construct a multiple-insert clause
- *
- * @param $table (string): name of table
- * @param $fields (array): array with field-names
- * @param $values (array): array of value-arrays
- *
- * example call:
- * ---
- * $db->multiInsert('order_products',
- * [ 'orderID', 'productID', 'unitPrice', 'quantity', 'note' ],
- * [
- * [ 124, 102030, 1.25, 5, '' ],
- * [ 124, 102040, 10.50, 2, 'some note about product #102040' ],
- * [ 124, 102050, 7.20, 3, '' ],
- * [ 124, 102060, 3.25, 1, 'some other note' ]
- * ]
- * );
- */
- public function multiInsert($table, array $fieldsArray, array $valuesArray)
- {
- if (count($fieldsArray) != count($valuesArray[0])) {
- throw new Exception('Fields and value arrays don\'t match.');
- }
-
- // setup fieldsSet
- // ex. "(Title, Price, Status)"
- $fieldsSet = ' (`'. implode(
- '`, `', // make sure fieldnames are not SQL-bound terms
- str_replace('`', '', $fieldsArray) // clean fieldnames
- ) .'`) ';
-
- // setup holders array and bind-values array
- // ex. "(:Title1, :Price1, :Status1), (:Title2, :Price2, :Status2), ...",
- $holdersArray = [];
- $bindsArray = [];
- $counter = 1;
- foreach($valuesArray as $key => $rowArray) {
- $rowHolders = [];
-
- foreach($itemArray as $key => $val) {
- $rowHolders = ':'. $fieldsArray[$key] . $counter;
- $bindsArray[ ':'. $fieldsArray[$key] . $counter ] = $val;
- }
- $holdersArray[] = '('. implode(', ', $rowHolders ) .')';
- $counter++;
- }
-
- $sql = "INSERT INTO {$table}" . $fieldsSet
- . ' VALUES '. impload(', ', $holdersArray);
-
- return $this->runQuery($sql, $bindsArray);
- }
-
-}
diff --git a/classes/Registry.php b/classes/Registry.php
deleted file mode 100644
index df012e9..0000000
--- a/classes/Registry.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-
-/** Registry
- * ---
- * Regisrty is a global repository of {key: value} pairs,
- * where key is a friendly label, and...
- * value can be anything (numbet|string|array|object etc)
- *
- * It has a central role in the framework.
- * By default it holds the Request instance and several
- * othe core instanses like database connections etc.
- */
-class Registry
-{
- /** STATIC PROPERTIES
- * -------------------------------------------------------------------------
- */
-
- /** keeps all ready-to-use records
- * ---
- * These are all records defined via Registry::set(), and
- * vow-records defined (Registry::vow()) AND called (Registry::use())
- * (it does not include the vows that have not carried-out yet )
- */
- private static $records = Array();
-
- /** keeps all records that will be carried-out later (if ever)
- * ---
- * These are registered via Registry::vow()
- */
- private static $wish = Array();
-
-
- /** METHODS
- * -------------------------------------------------------------------------
- */
-
- /** set
- * ---
- * store $data to the registry undel the label $key
- * @param $key (string)
- * @param $data *
- */
- static function set($key, $data)
- {
- // TODO: not use if needed...
- // you may include an explicit method for reseting the key
- // or even reVOWing a wish;
- // or it could be just a 3rd paremeter like
- // function set($key, $data, $reset = false) {...}
- // function set($key, $function, $reset = false) {...}
-
- if (!isset(self::$records[$key])) {
-
- self::$records[$key] = $data;
- return true;
-
- } else { return fasle; }
- }
-
-
- /** get
- * ---
- * get data from registry,
- * stored under the label $key
- * @param $key (string): the label
- * @return data (mixed)
- */
- static function get($key)
- {
- // if defined and not beeing a vow/wish, serve
- if (isset(self::$records[$key]) && (!isset(self::$wish[$key]))) {
-
- return self::$records[$key];
-
- } else { return false; }
- }
-
-
- /** vow
- * ---
- * implements a promise of a function operation
- * when/if the registry label is called;
- * it can store a function, an object handler etc.
- *
- * example:
- * Registry::vow('key', function(){ return new Obj(); })
- *
- * The main advantage of using a 'vow' vs a 'set' is
- * that a 'vow' will not use system resources to prepare
- * the data/object/handler/etc until/if-ever is called.
- *
- * @param $label (string): label / refference key
- * @param function :
- */
- static function vow($label, $function)
- {
- self::$wish[$label] = $function;
- }
-
-
- /** use (some vow)
- * ---
- * this is the method that carries out
- * the promissed function (with arguments)
- */
- static function use($label, $args=[])
- {
- // if already prepered (and is a wish) serve it
- if (isset(self::$records[$label]) && isset(self::$wish[$label])) {
-
- return self::$records[$label];
-
- } else {
-
- // otherwise if is a wish/promise
- if (array_key_exists($label, self::$wish)) {
-
- // prepare, store and serve it
- $carryOut = call_user_func_array(self::$wish[$label], $args);
- self::$records[$label] = $carryOut;
-
- return $carryOut;
-
- } else { return false; }
- }
- }
-
-}
diff --git a/classes/Repository.php b/classes/Repository.php
deleted file mode 100644
index c01d0c1..0000000
--- a/classes/Repository.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/** Repository
- * is an abstract class that strores entities
- * and serves them via ::pull() method when needed
- *
- * it also has an ::echo() method to list the
- */
-abstract class Repository
-{
-
- /** all repositories (need to) have
- * one public static array named '$repository'
- */
- public static $repository = [];
-
- /** pull
- * one entity from repository
- * @param $entity (string): the label of the entity
- */
- public static function pull($entity)
- {
- if (array_key_exists($entity, static::$repository)) {
-
- return static::$repository[$entity];
-
- } else die('repository does not exist');
-
- }
-
-
- /** echo
- * lists the entities of the repository;
- * by default it only lists the labes of the entities;
- * @param $content (bool): if true serve contents along with the labels
- * @return (array)
- */
- public static function echo($content =false)
- {
- if ($content) return static::$repository;
- else return array_keys(static::$repository);
- }
-} \ No newline at end of file
diff --git a/classes/Request.php b/classes/Request.php
deleted file mode 100644
index 20b82c7..0000000
--- a/classes/Request.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-
-class Request
-{
-
- public $URL; // full request url
-
- public $PATH; // Path (decoded)
-
- public $QUERY; // Query string (decoded)
-
- public $HOST;
-
- public $PORT;
-
- public $METHOD; // request method
-
- public $TIME; // request timestamp
-
- public $IP; // Client's IP address
-
- public $AGENT; // Client's User Agent
-
- public $GET = [];
-
- public $POST = [];
-
- public $SIGNATURE; // user/client's device signature
-
-
-
- public function __construct($errors = false)
- {
- $parsed = parse_url($_SERVER['REQUEST_URI']);
- $this->URL = $_SERVER['REQUEST_URI'];
- $this->PATH = (!empty($parsed['path'])) ? urldecode($parsed['path']) : '';
- $this->QUERY = (!empty($parsed['query'])) ? urldecode($parsed['query']) : false;
- $this->HOST = $_SERVER['HTTP_HOST'];
- $this->PORT = $_SERVER['SERVER_PORT'];
- $this->TIME = $_SERVER['REQUEST_TIME'];
- $this->CLI_IP = $_SERVER['REMOTE_ADDR'];
-
- $this->METHOD = strtolower($_SERVER['REQUEST_METHOD']);
-
- $this->GET = $_GET; // $_GET should only used
- // to request data or specify options (never to perform
- // system-changes) thus should not need any validation;
- // * If (for any reason) you requide $_GET sanitization
- // enable it later on the method's code
-
- // $this->INTERFACE = php_sapi_name();
-
- $this->AGENT = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
- $this->SIGNATURE = sha1(
- $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
- . $_SERVER['HTTP_ACCEPT'] ?? ''
- . $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''
- . $_SERVER['HTTP_ACCEPT_ENCODING'] ?? ''
- );
-
- // sanitize user input
- // if (isset($_GET)) { $this->GET = $this->sanitize($_GET); }
- $this->GET = $this->sanitize($_GET);
- if (isset($_POST)) { $this->POST = $this->sanitize($_POST); }
- if (isset($_COOKIE)) { $this->COOKIE = $this->sanitize($_COOKIE); }
-
- // check anti-CSRF token if needed
- // (again, GET requests should not need CSRF cheking)
- if (in_array($this->METHOD, ['post', 'put', 'patch', 'delete'])) {
- // TODO: only if CSRF protection enabled...
- $this->checkCsrfToken();
- }
-
- }
-
-
- private function sanitize($array)
- {
- // TODO:
- // ...
- return $array;
- }
-
-
- public function checkCsrfToken()
- {
- // TODO:
- // ...
- // if SCRF-token is not valideted, serve 403
- return $array;
- }
-
-}
-
diff --git a/classes/Route.php b/classes/Route.php
deleted file mode 100644
index 072723c..0000000
--- a/classes/Route.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-/** Route
- * ---
- * Methods:
- * - add( expression , callback_function , method )
- * - notFound( callback_function )
- * - methodNotAllowed( callback_function )
- * - run()
- *
- * + matches static paths
- * + matches dynamic paths through regex expressions
- * + takes care of request-method
- */
-class Route {
-
- private static $routes = Array(); // array to host routes
- private static $notFound = null; // 404 error function
- private static $methodNotAllowed = null; // 404 error function
-
- /** add (route)
- * ---
- * @param $expression : (string) static or regex matcher
- * @param $function : callback function to be executed if expression is matched
- * @param $method : get / post / any
- */
- public static function add( $expression, $function, $method = 'get' )
- {
- array_push(self::$routes, Array(
- 'expression' => $expression,
- 'function' => $function,
- 'method' => strtolower($method)
- ));
- }
-
-
- /** notFound($function)
- * ---
- * @param $function : call back function to be executed
- */
- public static function notFound($function)
- {
- self::$notFound = $function;
- }
-
-
- /** run()
- * ---
- * Parse request ; Find mathing route ;
- * then call route's function
- * usualy a Controller::method([poarametres])
- */
- public static function run(Request $request)
- {
- // $request = Registry::get('REQUEST');
- $path = $request->PATH; // request path
- $method = $request->METHOD; // request method
-
- $path_match_found = false;
- $route_match_found = false;
-
- foreach(self::$routes as $route) {
-
- // If method matched check the path
- if ($route['method'] == $method || $method == 'any') {
-
- // Add 'find string start' automatically
- $route['expression'] = '^'.$route['expression'];
-
- // Add 'find string end' automatically
- $route['expression'] = $route['expression'].'$';
-
- // Check path match
- if (preg_match('#'. $route['expression'] .'#', $path, $matches)) {
-
- $route_match_found = true;
-
- array_shift($matches); // Always remove first element. This contains the whole string
-
- call_user_func_array($route['function'], $matches);
- break; // Do not check other routes
-
- }
- }
- }
-
- // No matching route was found
- if (!$route_match_found) {
- header("HTTP/1.0 404 Not Found");
- if (self::$notFound) {
- call_user_func_array(self::$notFound, []);
- }
- }
-
- }
-
-}
diff --git a/classes/Security.php b/classes/Security.php
deleted file mode 100644
index 61979db..0000000
--- a/classes/Security.php
+++ /dev/null
@@ -1,923 +0,0 @@
-<?php
-/** Security Class
- * ---
- * based on CodeIgniter\Security
- * @author EllisLab Dev Team
- * @link https://codeigniter.com/userguide3/libraries/security.html
- * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
- * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
- * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
- * @license https://opensource.org/licenses/MIT MIT License
- * @link https://codeigniter.com
- */
-class Security
-{
-
- // List of sanitize filename strings @var (array)
- public $filename_bad_chars = array(
- '../', '<!--', '-->', '<', '>',
- "'", '"', '&', '$', '#',
- '{', '}', '[', ']', '=',
- ';', '?', '%20', '%22',
- '%3c', // <
- '%253c', // <
- '%3e', // >
- '%0e', // >
- '%28', // (
- '%29', // )
- '%2528', // (
- '%26', // &
- '%24', // $
- '%3f', // ?
- '%3b', // ;
- '%3d' // =
- );
-
- public $charset = 'UTF-8'; // Character set @var (string) Will be overridden by the constructor.
-
- protected $_xss_hash; // XSS Hash: @var (string) Random Hash for protecting URLs.
-
- protected $_csrf_hash; // CSRF Hash: @var (string) Random hash for Cross Site Request Forgery protection cookie
-
- // CSRF Expire time @var (int)
- // Expiration time for Cross Site Request Forgery protection cookie.
- protected $_csrf_expire = 7200; // defaults to 2hours (=7200 seconds)
-
- // CSRF Token name: @var (string) Token name for Cross Site Request Forgery protection cookie.
- protected $_csrf_token_name = 'pi_csrf_token';
-
- // CSRF Cookie name: @var (string) Cookie name for Cross Site Request Forgery protection cookie.
- protected $_csrf_cookie_name = 'pi_csrf_token';
-
- // List of never allowed strings @var (array)
- protected $_never_allowed_str = array(
- 'document.cookie' => '[removed]',
- '(document).cookie' => '[removed]',
- 'document.write' => '[removed]',
- '(document).write' => '[removed]',
- '.parentNode' => '[removed]',
- '.innerHTML' => '[removed]',
- '-moz-binding' => '[removed]',
- '<!--' => '&lt;!--',
- '-->' => '--&gt;',
- '<![CDATA[' => '&lt;![CDATA[',
- '<comment>' => '&lt;comment&gt;',
- '<%' => '&lt;&#37;'
- );
-
- // List of never allowed regex replacements @var (array)
- protected $_never_allowed_regex = array(
- 'javascript\s*:',
- '(\(?document\)?|\(?window\)?(\.document)?)\.(location|on\w*)',
- 'expression\s*(\(|&\#40;)', // CSS and IE
- 'vbscript\s*:', // IE, surprise!
- 'wscript\s*:', // IE
- 'jscript\s*:', // IE
- 'vbs\s*:', // IE
- 'Redirect\s+30\d',
- "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
- );
-
-
- /** Class constructor
- * ---
- * @return void
- */
- public function __construct($charset = 'UTF-8')
- {
- $this->charset = $charset;
-
- /* ---
- // Is CSRF protection enabled?
- if (CSRF_PROTCTION') && ! is_cli())
- { --*/
- /**************
- // CSRF config
- foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
- {
- //// if (NULL !== ($val = config_item($key)))
- //// {
- $this->{'_'.$key} = $val;
- //// }
- }
-
- // Append application specific cookie prefix
- //// if ($cookie_prefix = config_item('cookie_prefix'))
- //// {
- $this->_csrf_cookie_name = $cookie_prefix . $this->_csrf_cookie_name;
- //// }
-
- // Set the CSRF hash
- $this->_csrf_set_hash();
- $this->csrf_verify();
- ***************/
- /* ---
- } --*/
-
- //// log_message('info', 'Security Class Initialized');
- }
-
-
- /** CSRF Verify
- * ---
- * @return Security
- */
- public function csrf_verify()
- {
- // If it's not a POST request we will set the CSRF cookie
- if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
- {
- return $this->csrf_set_cookie();
- }
-
- /// // Check if URI has been whitelisted from CSRF checks
- /// if ($exclude_uris = config_item('csrf_exclude_uris'))
- /// {
- /// $uri = load_class('URI', 'core');
- /// foreach ($exclude_uris as $excluded)
- /// {
- /// if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), $uri->uri_string()))
- /// {
- /// return $this;
- /// }
- /// }
- /// }
-
- // Check CSRF token validity, but don't error on mismatch just yet - we'll want to regenerate
- $valid = isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
- && is_string($_POST[$this->_csrf_token_name]) && is_string($_COOKIE[$this->_csrf_cookie_name])
- && hash_equals($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name]);
-
- // We kill this since we're done and we don't want to pollute the _POST array
- unset($_POST[$this->_csrf_token_name]);
-
- // Regenerate on every submission?
- if (config_item('csrf_regenerate'))
- {
- // Nothing should last forever
- unset($_COOKIE[$this->_csrf_cookie_name]);
- $this->_csrf_hash = NULL;
- }
-
- $this->_csrf_set_hash();
- $this->csrf_set_cookie();
-
- if ($valid !== TRUE)
- {
- $this->csrf_show_error();
- }
-
- log_message('info', 'CSRF token verified');
- return $this;
- }
-
-
- /** CSRF Set Cookie
- * ---
- * @codeCoverageIgnore
- * @return Security
- */
- public function csrf_set_cookie()
- {
- $expire = time() + $this->_csrf_expire;
- $secure_cookie = (bool) config_item('cookie_secure');
-
- if ($secure_cookie && ! is_https())
- {
- return FALSE;
- }
-
- // php7.3+
- setcookie(
- $this->_csrf_cookie_name,
- $this->_csrf_hash,
- array(
- 'expires' => $expire,
- 'path' => config_item('cookie_path'),
- 'domain' => config_item('cookie_domain'),
- 'secure' => $secure_cookie,
- 'httponly' => config_item('cookie_httponly'),
- 'samesite' => 'Strict'
- )
- );
-
- log_message('info', 'CSRF cookie sent');
-
- return $this;
- }
-
-
- /** Show CSRF Error
- * --
- * @return void
- */
- public function csrf_show_error()
- {
- show_error('The action you have requested is not allowed.', 403);
- }
-
-
- /** Get CSRF Hash
- * ---
- * @see CI_Security::$_csrf_hash
- * @return string CSRF hash
- */
- public function get_csrf_hash()
- {
- return $this->_csrf_hash;
- }
-
-
- /** Get CSRF Token Name
- * ---
- * @see CI_Security::$_csrf_token_name
- * @return string CSRF token name
- */
- public function get_csrf_token_name()
- {
- return $this->_csrf_token_name;
- }
-
-
- /** XSS Clean
- * ---
- * Sanitizes data so that Cross Site Scripting Hacks can be
- * prevented. This method does a fair amount of work but
- * it is extremely thorough, designed to prevent even the
- * most obscure XSS attempts. Nothing is ever 100% foolproof,
- * of course, but I haven't been able to get anything passed
- * the filter.
- *
- * Note: Should only be used to deal with data upon submission.
- * It's not something that should be used for general
- * runtime processing.
- *
- * @link http://channel.bitflux.ch/wiki/XSS_Prevention
- * Based in part on some code and ideas from Bitflux.
- *
- * @link http://ha.ckers.org/xss.html
- * To help develop this script I used this great list of
- * vulnerabilities along with a few other hacks I've
- * harvested from examining vulnerabilities in other programs.
- *
- * @param string|string[] $str Input data
- * @param bool $is_image Whether the input is an image
- * @return string
- */
- public function xss_clean($str, $is_image = FALSE)
- {
- // Is the string an array?
- if (is_array($str))
- {
- foreach ($str as $key => &$value)
- {
- $str[$key] = $this->xss_clean($value);
- }
-
- return $str;
- }
-
- // Remove Invisible Characters
- $str = remove_invisible_characters($str);
-
- // URL Decode
- // Just in case stuff like this is submitted:
- // <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
- // NOTE: Use rawurldecode() so it does not remove plus signs
- if (stripos($str, '%') !== false)
- {
- do
- {
- $oldstr = $str;
- $str = rawurldecode($str);
- $str = preg_replace_callback('#%(?:\s*[0-9a-f]){2,}#i', array($this, '_urldecodespaces'), $str);
- }
- while ($oldstr !== $str);
- unset($oldstr);
- }
-
- // Convert character entities to ASCII
- // ---
- // This permits our tests below to work reliably.
- // We only convert entities that are within tags since
- // these are the ones that will pose security problems.
- $str = preg_replace_callback("/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
- $str = preg_replace_callback('/<\w+.*/si', array($this, '_decode_entity'), $str);
-
- // Remove Invisible Characters Again!
- $str = remove_invisible_characters($str);
-
-
- // Convert all tabs to spaces
- // ---
- // This prevents strings like this: ja vascript
- // NOTE: we deal with spaces between characters later.
- // NOTE: preg_replace was found to be amazingly slow here on
- // large blocks of data, so we use str_replace.
- $str = str_replace("\t", ' ', $str);
-
- // Capture converted string for later comparison
- $converted_string = $str;
-
- // Remove Strings that are never allowed
- $str = $this->_do_never_allowed($str);
-
-
- // Makes PHP tags safe
- // NOTE: XML tags are inadvertently replaced too:
- // <?xml
- // But it doesn't seem to pose a problem.
- if ($is_image === TRUE)
- {
- // Images have a tendency to have the PHP short opening and
- // closing tags every so often so we skip those and only
- // do the long opening tags.
- $str = preg_replace('/<\?(php)/i', '&lt;?\\1', $str);
- }
- else
- {
- $str = str_replace(array('<?', '?'.'>'), array('&lt;?', '?&gt;'), $str);
- }
-
- // Compact any exploded words
- // ---
- // This corrects words like: j a v a s c r i p t
- // These words are compacted back to their correct state.
- $words = array(
- 'javascript', 'expression', 'vbscript', 'jscript', 'wscript',
- 'vbs', 'script', 'base64', 'applet', 'alert', 'document',
- 'write', 'cookie', 'window', 'confirm', 'prompt', 'eval'
- );
-
- foreach ($words as $word)
- {
- $word = implode('\s*', str_split($word)).'\s*';
-
- // We only want to do this when it is followed by a non-word character
- // That way valid stuff like "dealer to" does not become "dealerto"
- $str = preg_replace_callback('#('.substr($word, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
- }
-
-
- // Remove disallowed Javascript in links or img tags
- // We used to do some version comparisons and use of stripos(),
- // but it is dog slow compared to these simplified non-capturing
- // preg_match(), especially if the pattern exists in the string
- //
- // Note: It was reported that not only space characters, but all in
- // the following pattern can be parsed as separators between a tag name
- // and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C]
- // ... however, remove_invisible_characters() above already strips the
- // hex-encoded ones, so we'll skip them below.
- do
- {
- $original = $str;
-
- if (preg_match('/<a/i', $str))
- {
- $str = preg_replace_callback('#<a(?:rea)?[^a-z0-9>]+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str);
- }
-
- if (preg_match('/<img/i', $str))
- {
- $str = preg_replace_callback('#<img[^a-z0-9]+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
- }
-
- if (preg_match('/script|xss/i', $str))
- {
- $str = preg_replace('#</*(?:script|xss).*?>#si', '[removed]', $str);
- }
- }
- while ($original !== $str);
- unset($original);
-
-
- // Sanitize naughty HTML elements
- // ---
- // If a tag containing any of the words in the list
- // below is found, the tag gets converted to entities.
- // So this: <blink>
- // Becomes: &lt;blink&gt;
- $pattern = '#'
- .'<((?<slash>/*\s*)((?<tagName>[a-z0-9]+)(?=[^a-z0-9]|$)|.+)' // tag start and name, followed by a non-tag character
- .'[^\s\042\047a-z0-9>/=]*' // a valid attribute character immediately after the tag would count as a separator
- // optional attributes
- .'(?<attributes>(?:[\s\042\047/=]*' // non-attribute characters, excluding > (tag close) for obvious reasons
- .'[^\s\042\047>/=]+' // attribute characters
- // optional attribute-value
- .'(?:\s*=' // attribute-value separator
- .'(?:[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*))' // single, double or non-quoted value
- .')?' // end optional attribute-value group
- .')*)' // end optional attributes group
- .'[^>]*)(?<closeTag>\>)?#isS';
-
- // Note: It would be nice to optimize this for speed, BUT
- // only matching the naughty elements here results in
- // false positives and in turn - vulnerabilities!
- do
- {
- $old_str = $str;
- $str = preg_replace_callback($pattern, array($this, '_sanitize_naughty_html'), $str);
- }
- while ($old_str !== $str);
- unset($old_str);
-
- // Sanitize naughty scripting elements
- // ---
- // Similar to above, only instead of looking for
- // tags it looks for PHP and JavaScript commands
- // that are disallowed. Rather than removing the
- // code, it simply converts the parenthesis to entities
- // rendering the code un-executable.
- // * For example: eval('some code')
- // ... Becomes: eval&#40;'some code'&#41;
- $str = preg_replace(
- '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si',
- '\\1\\2&#40;\\3&#41;',
- $str
- );
-
- // Same thing, but for "tag functions" (e.g. eval`some code`)
- // See https://github.com/bcit-ci/CodeIgniter/issues/5420
- $str = preg_replace(
- '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)`(.*?)`#si',
- '\\1\\2&#96;\\3&#96;',
- $str
- );
-
- // Final clean up
- // This adds a bit of extra precaution in case
- // something got through the above filters
- $str = $this->_do_never_allowed($str);
-
- // Images are Handled in a Special Way
- // - Essentially, we want to know that after all of the character
- // conversion is done whether any unwanted, likely XSS, code was found.
- // If not, we return TRUE, as the image is clean.
- // However, if the string post-conversion does not matched the
- // string post-removal of XSS, then it fails, as there was unwanted XSS
- // code found and removed/changed during processing.
- if ($is_image === TRUE)
- {
- return ($str === $converted_string);
- }
-
- return $str;
- }
-
-
- /** XSS Hash
- * ---
- * Generates the XSS hash if needed and returns it.
- * @see CI_Security::$_xss_hash
- * @return string XSS hash
- */
- public function xss_hash()
- {
- if ($this->_xss_hash === NULL)
- {
- $rand = $this->get_random_bytes(16);
- $this->_xss_hash = ($rand === FALSE)
- ? md5(uniqid(mt_rand(), TRUE))
- : bin2hex($rand);
- }
-
- return $this->_xss_hash;
- }
-
-
- /** Get random bytes
- * ---
- * @param int $length Output length
- * @return string
- */
- public function get_random_bytes($length)
- {
- if (empty($length) OR ! ctype_digit((string) $length))
- {
- return FALSE;
- }
-
- if (function_exists('random_bytes'))
- {
- try
- {
- // The cast is required to avoid TypeError
- return random_bytes((int) $length);
- }
- catch (Exception $e)
- {
- // If random_bytes() can't do the job, we can't either ...
- // There's no point in using fallbacks.
- log_message('error', $e->getMessage());
- return FALSE;
- }
- }
-
- // Unfortunately, none of the following PRNGs is guaranteed to exist ...
- if (defined('MCRYPT_DEV_URANDOM') && ($output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)) !== FALSE)
- {
- return $output;
- }
-
- if (is_readable('/dev/urandom') && ($fp = fopen('/dev/urandom', 'rb')) !== FALSE)
- {
- // Try not to waste entropy ...
- stream_set_chunk_size($fp, $length);
- $output = fread($fp, $length);
- fclose($fp);
- if ($output !== FALSE)
- {
- return $output;
- }
- }
-
- if (function_exists('openssl_random_pseudo_bytes'))
- {
- return openssl_random_pseudo_bytes($length);
- }
-
- return FALSE;
- }
-
-
- /** HTML Entities Decode
- * ---
- * A replacement for html_entity_decode()
- *
- * The reason we are not using html_entity_decode() by itself is because
- * while it is not technically correct to leave out the semicolon
- * at the end of an entity most browsers will still interpret the entity
- * correctly. html_entity_decode() does not convert entities without
- * semicolons, so we are left with our own little solution here. Bummer.
- *
- * @link https://secure.php.net/html-entity-decode
- *
- * @param string $str Input
- * @param string $charset Character set
- * @return string
- */
- public function entity_decode($str, $charset = NULL)
- {
- if (strpos($str, '&') === FALSE)
- {
- return $str;
- }
-
- static $_entities;
-
- isset($charset) OR $charset = $this->charset;
- isset($_entities) OR $_entities = array_map('strtolower', get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML5, $charset));
-
- do
- {
- $str_compare = $str;
-
- // Decode standard entities, avoiding false positives
- if (preg_match_all('/&[a-z]{2,}(?![a-z;])/i', $str, $matches))
- {
- $replace = array();
- $matches = array_unique(array_map('strtolower', $matches[0]));
- foreach ($matches as &$match)
- {
- if (($char = array_search($match.';', $_entities, TRUE)) !== FALSE)
- {
- $replace[$match] = $char;
- }
- }
-
- $str = str_replace(array_keys($replace), array_values($replace), $str);
- }
-
- // Decode numeric & UTF16 two byte entities
- $str = html_entity_decode(
- preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;])|(?:0*\d{2,4}(?![0-9;]))))/iS', '$1;', $str),
- ENT_COMPAT | ENT_HTML5,
- $charset
- );
- }
- while ($str_compare !== $str);
- return $str;
- }
-
-
- /** Sanitize Filename
- * ---
- * @param string $str Input file name
- * @param bool $relative_path Whether to preserve paths
- * @return string
- */
- public function sanitize_filename($str, $relative_path = FALSE)
- {
- $bad = $this->filename_bad_chars;
-
- if ( ! $relative_path)
- {
- $bad[] = './';
- $bad[] = '/';
- }
-
- $str = remove_invisible_characters($str, FALSE);
-
- do
- {
- $old = $str;
- $str = str_replace($bad, '', $str);
- }
- while ($old !== $str);
-
- return stripslashes($str);
- }
-
-
- /** Strip Image Tags
- * ---
- * @param string $str
- * @return string
- */
- public function strip_image_tags($str)
- {
- return preg_replace(
- array(
- '#<img[\s/]+.*?src\s*=\s*(["\'])([^\\1]+?)\\1.*?\>#i',
- '#<img[\s/]+.*?src\s*=\s*?(([^\s"\'=<>`]+)).*?\>#i'
- ),
- '\\2',
- $str
- );
- }
-
-
- /** URL-decode taking spaces into account
- * ---
- * @see https://github.com/bcit-ci/CodeIgniter/issues/4877
- * @param array $matches
- * @return string
- */
- protected function _urldecodespaces($matches)
- {
- $input = $matches[0];
- $nospaces = preg_replace('#\s+#', '', $input);
- return ($nospaces === $input)
- ? $input
- : rawurldecode($nospaces);
- }
-
-
- /** Compact Exploded Words
- * ---
- * Callback method for xss_clean() to remove whitespace from
- * things like 'j a v a s c r i p t'.
- *
- * @used-by Security::xss_clean()
- * @param array $matches
- * @return string
- */
- protected function _compact_exploded_words($matches)
- {
- return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
- }
-
-
- /** Sanitize Naughty HTML
- * ---
- * Callback method for xss_clean() to remove naughty HTML elements.
- * @used-by Security::xss_clean()
- * @param array $matches
- * @return string
- */
- protected function _sanitize_naughty_html($matches)
- {
- static $naughty_tags = array(
- 'alert', 'area', 'prompt', 'confirm', 'applet', 'audio', 'basefont', 'base', 'behavior', 'bgsound',
- 'blink', 'body', 'embed', 'expression', 'form', 'frameset', 'frame', 'head', 'html', 'ilayer',
- 'iframe', 'input', 'button', 'select', 'isindex', 'layer', 'link', 'meta', 'keygen', 'object',
- 'plaintext', 'style', 'script', 'textarea', 'title', 'math', 'video', 'svg', 'xml', 'xss'
- );
-
- static $evil_attributes = array(
- 'on\w+', 'style', 'xmlns', 'formaction', 'form', 'xlink:href', 'FSCommand', 'seekSegmentTime'
- );
-
- // First, escape unclosed tags
- if (empty($matches['closeTag']))
- {
- return '&lt;'.$matches[1];
- }
- // Is the element that we caught naughty? If so, escape it
- elseif (in_array(strtolower($matches['tagName']), $naughty_tags, TRUE))
- {
- return '&lt;'.$matches[1].'&gt;';
- }
- // For other tags, see if their attributes are "evil" and strip those
- elseif (isset($matches['attributes']))
- {
- // We'll store the already filtered attributes here
- $attributes = array();
-
- // Attribute-catching pattern
- $attributes_pattern = '#'
- .'(?<name>[^\s\042\047>/=]+)' // attribute characters
- // optional attribute-value
- .'(?:\s*=(?<value>[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' // attribute-value separator
- .'#i';
-
- // Blacklist pattern for evil attribute names
- $is_evil_pattern = '#^('.implode('|', $evil_attributes).')$#i';
-
- // Each iteration filters a single attribute
- do
- {
- // Strip any non-alpha characters that may precede an attribute.
- // Browsers often parse these incorrectly and that has been a
- // of numerous XSS issues we've had.
- $matches['attributes'] = preg_replace('#^[^a-z]+#i', '', $matches['attributes']);
-
- if ( ! preg_match($attributes_pattern, $matches['attributes'], $attribute, PREG_OFFSET_CAPTURE))
- {
- // No (valid) attribute found? Discard everything else inside the tag
- break;
- }
-
- if (
- // Is it indeed an "evil" attribute?
- preg_match($is_evil_pattern, $attribute['name'][0])
- // Or does it have an equals sign, but no value and not quoted? Strip that too!
- OR (trim($attribute['value'][0]) === '')
- )
- {
- $attributes[] = 'xss=removed';
- }
- else
- {
- $attributes[] = $attribute[0][0];
- }
-
- $matches['attributes'] = substr($matches['attributes'], $attribute[0][1] + strlen($attribute[0][0]));
- }
- while ($matches['attributes'] !== '');
-
- $attributes = empty($attributes)
- ? ''
- : ' '.implode(' ', $attributes);
- return '<'.$matches['slash'].$matches['tagName'].$attributes.'>';
- }
-
- return $matches[0];
- }
-
-
- /** JS Link Removal
- * ---
- * Callback method for xss_clean() to sanitize links.
- *
- * This limits the PCRE backtracks, making it more performance friendly
- * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
- * PHP 5.2+ on link-heavy strings.
- *
- * @used-by CI_Security::xss_clean()
- * @param array $match
- * @return string
- */
- protected function _js_link_removal($match)
- {
- return str_replace(
- $match[1],
- preg_replace(
- '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;|`|&\#96;)|javascript:|livescript:|mocha:|charset=|window\.|\(?document\)?\.|\.cookie|<script|<xss|d\s*a\s*t\s*a\s*:)#si',
- '',
- $this->_filter_attributes($match[1])
- ),
- $match[0]
- );
- }
-
-
- /** JS Image Removal
- * ---
- * Callback method for xss_clean() to sanitize image tags.
- *
- * This limits the PCRE backtracks, making it more performance friendly
- * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
- * PHP 5.2+ on image tag heavy strings.
- *
- * @used-by Security::xss_clean()
- * @param array $match
- * @return string
- */
- protected function _js_img_removal($match)
- {
- return str_replace(
- $match[1],
- preg_replace(
- '#src=.*?(?:(?:alert|prompt|confirm|eval)(?:\(|&\#40;|`|&\#96;)|javascript:|livescript:|mocha:|charset=|window\.|\(?document\)?\.|\.cookie|<script|<xss|base64\s*,)#si',
- '',
- $this->_filter_attributes($match[1])
- ),
- $match[0]
- );
- }
-
-
- /** Attribute Conversion
- * ---
- * @used-by CI_Security::xss_clean()
- * @param array $match
- * @return string
- */
- protected function _convert_attribute($match)
- {
- return str_replace(array('>', '<', '\\'), array('&gt;', '&lt;', '\\\\'), $match[0]);
- }
-
-
- /** Filter Attributes
- * ---
- * Filters tag attributes for consistency and safety.
- * @used-by CI_Security::_js_img_removal()
- * @used-by CI_Security::_js_link_removal()
- * @param string $str
- * @return string
- */
- protected function _filter_attributes($str)
- {
- $out = '';
- if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
- {
- foreach ($matches[0] as $match)
- {
- $out .= preg_replace('#/\*.*?\*/#s', '', $match);
- }
- }
-
- return $out;
- }
-
-
- /** HTML Entity Decode Callback
- * ---
- * @used-by CI_Security::xss_clean()
- * @param array $match
- * @return string
- */
- protected function _decode_entity($match)
- {
- // Protect GET variables in URLs
- // 901119URL5918AMP18930PROTECT8198
- $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', $this->xss_hash().'\\1=\\2', $match[0]);
-
- // Decode, then un-protect URL GET vars
- return str_replace(
- $this->xss_hash(),
- '&',
- $this->entity_decode($match, $this->charset)
- );
- }
-
-
- /** Do Never Allowed
- * ---
- * @used-by CI_Security::xss_clean()
- * @param string
- * @return string
- */
- protected function _do_never_allowed($str)
- {
- $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str);
-
- foreach ($this->_never_allowed_regex as $regex)
- {
- $str = preg_replace('#'.$regex.'#is', '[removed]', $str);
- }
-
- return $str;
- }
-
-
- /** Set CSRF Hash and Cookie
- * ---
- * @return string
- */
- protected function _csrf_set_hash()
- {
- if ($this->_csrf_hash === NULL)
- {
- // If the cookie exists we will use its value.
- // We don't necessarily want to regenerate it with
- // each page load since a page could contain embedded
- // sub-pages causing this feature to fail
- if (isset($_COOKIE[$this->_csrf_cookie_name]) && is_string($_COOKIE[$this->_csrf_cookie_name])
- && preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1)
- {
- return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
- }
-
- $rand = $this->get_random_bytes(16);
- $this->_csrf_hash = ($rand === FALSE)
- ? md5(uniqid(mt_rand(), TRUE))
- : bin2hex($rand);
- }
-
- return $this->_csrf_hash;
- }
-}
diff --git a/classes/User.php b/classes/User.php
deleted file mode 100644
index 65b5018..0000000
--- a/classes/User.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-
-class User_depricated
-{
-
- /** PROPERTIES
- * -------------------------------------------------------------------------
- */
-
- private $isLogged = false;
-
- private $who = Array(
- 'title' => '',
- 'name' => '',
- 'middle'=> '',
- 'surname' =>'',
- 'email' => ''
- );
-
- private $addresses = Array();
-
-
-
- /** METHODS
- * -------------------------------------------------------------------------
- */
-
-
- public function create()
- {
-
- }
-
-
- public function setDefaultAddress($id)
- {
-
- }
-
-
- public function addAddress()
- {
- // update session data
- // update user record
- }
-
-
- public function changePassword()
- {
-
- }
-
-
- public function confirmEmail()
- {
-
- }
-
-
- public function sendEmail()
- {
-
- }
-
- /** sendOTP()
- * sent One-Time-Password
- *
- */
- public function sendOTP($ttl)
- {
- $to = $this->who;
- $otp = rand(10000,99999);
- $expire = time() + $ttl;
-
- $mail = new PHPMailer(true);
- try {
- //Server settings
- // ...
-
- //Recipients
- $mail->setFrom('from@example.com', 'Mailer');
- $mail->addAddress($to['email'], $to['surname'] .' '. $to['name']); //Add a recipient
- $mail->addReplyTo('info@example.com', 'Information');
-
- //Attachments
- $mail->addAttachment('/var/tmp/file.tar.gz'); //Add attachments
- $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); //Optional name
-
- //Content
- $mail->isHTML(true); //Set email format to HTML
- $mail->Subject = 'Your OTP';
- $mail->Body = 'This is the HTML message body <b>in bold!</b>';
- $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
-
- $mail->send();
- echo 'Message has been sent';
- } catch (Exception $e) {
- echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
- }
-
- }
-
- /** updateSession()
- * regenerates session
- */
- public function updateSession()
- {
-
- }
-
-}
diff --git a/classes/authenticator/PasswordTrait.php b/classes/authenticator/PasswordTrait.php
deleted file mode 100644
index 22976d8..0000000
--- a/classes/authenticator/PasswordTrait.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-
-// namespace DevCoder\Authentication\Core;
-//
-// use DevCoder\Authentication\UserInterface;
-
-/**
- * Trait PasswordTrait
- * @package DevCoder\Authentication\Core
- */
-trait PasswordTrait
-{
- private $cost = 10;
-
- public function cryptPassword(string $plainPassword): string
- {
- return password_hash(
- $plainPassword,
- PASSWORD_BCRYPT,
- ['cost' => $this->cost]
- );
- }
-
- public function isPasswordValid(UserInterface $user, string $plainPassword): bool
- {
- return password_verify(
- $plainPassword,
- $user->getPassword()
- );
- }
-
- public function setCost(int $cost): void
- {
- if ($cost < 4 || $cost > 12) {
- throw new \InvalidArgumentException('Cost must be in the range of 4-31.');
- }
- $this->cost = $cost;
- }
-}
diff --git a/classes/authenticator/User.php b/classes/authenticator/User.php
deleted file mode 100644
index b99fa70..0000000
--- a/classes/authenticator/User.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-
-// namespace DevCoder\Authentication;
-
-class User implements UserInterface
-{
-
- // @var string
- private $userName;
-
- // @var string
- private $password;
-
- // @var array
- private $roles = [];
-
- // @var bool
- private $enabled = true;
-
-
- /** GETs
- * -------------------------------------------------------------------------
- */
-
- /** getUserName
- * @return null|string
- */
- public function getUsername(): ?string
- {
- return $this->userName;
- }
-
- /** getPassword
- * @return null|string
- */
- public function getPassword(): ?string
- {
- return $this->password;
- }
-
- /** getRoles
- * @return array
- */
- public function getRoles(): array
- {
- return $this->roles;
- }
-
- /** isEnabled
- * @return bool
- */
- public function isEnabled(): bool
- {
- return $this->enabled;
- }
-
-
- /** SETs
- * -------------------------------------------------------------------------
- */
-
- /** setUserName
- * @param string $userName
- * @return User
- */
- public function setUserName(string $userName): self
- {
- $this->userName = $userName;
- return $this;
- }
-
- /** setPassword
- * @param string $password
- * @return User
- */
- public function setPassword(string $password): self
- {
- $this->password = $password;
- return $this;
- }
-
- /** setRoles
- * @param array $roles
- * @return User
- */
- public function setRoles(array $roles): self
- {
- $this->roles = $roles;
- return $this;
- }
-
- /**
- * @param bool $enabled
- * @return User
- */
- public function setEnabled(bool $enabled): self
- {
- $this->enabled = $enabled;
- return $this;
- }
-}
diff --git a/classes/authenticator/UserInterface.php b/classes/authenticator/UserInterface.php
deleted file mode 100644
index 5cc6d2d..0000000
--- a/classes/authenticator/UserInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-/**
- * Interface UserInterface
- * @package DevCoder\Authentication
- */
-interface UserInterface
-{
- public function getUsername() :?string;
-
- public function getPassword() :?string;
-
- public function getRoles() : array;
-
- public function isEnabled(): bool;
-} \ No newline at end of file
diff --git a/classes/authenticator/UserManager.php b/classes/authenticator/UserManager.php
deleted file mode 100644
index 36f0d16..0000000
--- a/classes/authenticator/UserManager.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// namespace DevCoder\Authentication\Core;
-//
-// use DevCoder\Authentication\Token\UserToken;
-// use DevCoder\Authentication\Token\UserTokenInterface;
-// use DevCoder\Authentication\UserInterface;
-
-/**
- * Class UserManager
- * @package DevCoder\Authentication\Core
- */
-class UserManager implements UserManagerInterface
-{
-
- use PasswordTrait;
-
- public function __construct()
- {
- if (session_status() === PHP_SESSION_NONE) {
- session_start();
- }
- }
-
- public function getUserToken(): ?UserTokenInterface
- {
- $userToken = null;
- if ($this->hasUserToken()) {
- $userToken = unserialize($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]);
- }
-
- return $userToken;
- }
-
- public function hasUserToken(): bool
- {
- $key = UserTokenInterface::DEFAULT_PREFIX_KEY;
- return (array_key_exists($key, $_SESSION) && unserialize($_SESSION[$key]) !== false);
- }
-
- public function isGranted(array $roles): bool
- {
- if (!is_null($userToken = $this->getUserToken())) {
- return false;
- }
-
- if ($userToken->getUser() instanceof UserInterface) {
- return (!empty(array_intersect($roles, $userToken->getUser()->getRoles())));
- }
-
- return false;
- }
-
- public function createUserToken(UserInterface $user): UserTokenInterface
- {
- $userToken = new UserToken($user);
- $_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY] = $userToken->serialize();
-
- return $userToken;
- }
-
- public function logout(): void
- {
- if ($this->hasUserToken()) {
- unset($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]);
- }
- }
-}
-
diff --git a/classes/authenticator/UserManagerInterface.php b/classes/authenticator/UserManagerInterface.php
deleted file mode 100644
index ef120c1..0000000
--- a/classes/authenticator/UserManagerInterface.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-// namespace DevCoder\Authentication\Core;
-//
-// use DevCoder\Authentication\Token\UserTokenInterface;
-// use DevCoder\Authentication\UserInterface;
-
-interface UserManagerInterface
-{
- public function getUserToken(): ?UserTokenInterface;
-
- public function hasUserToken(): bool;
-
- public function createUserToken(UserInterface $user): UserTokenInterface;
-
- public function logout(): void;
-
- public function cryptPassword(string $plainPassword): string;
-
- public function isPasswordValid(UserInterface $user, string $plainPassword): bool;
-}
diff --git a/classes/authenticator/UserToken.php b/classes/authenticator/UserToken.php
deleted file mode 100644
index 7758086..0000000
--- a/classes/authenticator/UserToken.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-
-// namespace DevCoder\Authentication\Token;
-//
-// use DevCoder\Authentication\UserInterface;
-
-/**
- * Class UserToken
- * @package DevCoder\Authentication\Token
- */
-class UserToken implements UserTokenInterface
-{
- /**
- * @var UserInterface
- */
- private $user;
-
- public function __construct(UserInterface $user)
- {
- $this->user = $user;
- }
-
- public function getUser(): UserInterface
- {
- return $this->user;
- }
-
- public function serialize(): string
- {
- return serialize($this);
- }
-}
diff --git a/classes/authenticator/UserTokenInterface.php b/classes/authenticator/UserTokenInterface.php
deleted file mode 100644
index 2a21d8f..0000000
--- a/classes/authenticator/UserTokenInterface.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-/**
- * Interface UserTokenInterface
- * @package DevCoder\Authentication\Token
- */
-interface UserTokenInterface
-{
- const DEFAULT_PREFIX_KEY = 'user_security';
-
- public function getUser(): UserInterface;
-
- public function serialize(): string;
-} \ No newline at end of file
diff --git a/classes/authenticator/info.md b/classes/authenticator/info.md
deleted file mode 100644
index e6d1372..0000000
--- a/classes/authenticator/info.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Authentication System
-
-read/ref: https://dev.to/fadymr/php-create-your-own-php-authentication-4e20
-
-also for session: https://dev.to/fadymr/php-create-a-simple-session-wrapper-class-dpk
-
-
-
-## How to use ?
-
-
-### Registration
-
-
- // use DevCoder\Authentication\Core\UserManager;
- // use DevCoder\Authentication\User;
-
- // register
- $userManager = new UserManager();
- $req = Registry::get('REQUEST);
-
- $password = $userManager->cryptPassword($req->POST['password']);
-
- $user = (new User())
- ->setUserName($req->POST['username'])
- ->setPassword($password)
- ->setRoles(['ROLE_USER']);
-
- $userManager->createUserToken($user);
-
- // check Token in Session
- var_dump($userManager->getUserToken());
- // object(DevCoder\Authentication\Token\UserToken)[4]
- // private 'user' =>
- // object(DevCoder\Authentication\User)[5]
- // private 'userName' => string 'username' (length=8)
- // private 'password' => string '$2y$10$iWdcmebmikUFlgKMqW7/rOmUp1DjFAuWKqdUHBhL08FZ7LL6bwRey' (length=60)
- // private 'roles' =>
- // array (size=1)
- // 0 => string 'ROLE_USER' (length=9)
- // private 'enabled' => boolean true
-
-
-## Connected or not
-
- <?php
-
- // use DevCoder\Authentication\Core\UserManager;
- // use DevCoder\Authentication\User;
-
- $userManager = new UserManager();
- if ($userManager->hasUserToken()) {
- // connected
-
- $token = $userManager->getUserToken();
- $user = $token->getUser();
- var_dump($user);
- // object(DevCoder\Authentication\User)[5]
- // private 'userName' => string 'username' (length=8)
- // private 'password' => string '$2y$10$OBobeLhdvdiftuedlv1a6e4.qF6sCG/usq5WEV4E3uB.UiS1egv/m' (length=60)
- // private 'roles' =>
- // array (size=1)
- // 0 => string 'ROLE_USER' (length=9)
- // private 'enabled' => boolean true
-
- } else {
- // not connected
- }
-
-
-## Access management
-
- $userManager = new UserManager();
- if ($userManager->isGranted(['ROLE_ADMIN'])) {
- //is admin
- // return Response 200
- }else {
- //is not admin
- // return Response 403
- }
-
- Logout
-
- $userManager = new UserManager();
- $userManager->logout();
-
-
-## Login
-
- <?php
-
- use DevCoder\Authentication\Core\UserManager;
-
- $stmt = $pdo->prepare("SELECT * FROM users WHERE username=?");
- $stmt->execute([$_POST['username']]);
- $userFromDataBase = $stmt->fetch();
- /**
- * Hydration
- */
- $user = (new \Test\DevCoder\Authentication\User())
- ->setUserName($userFromDataBase['username'])
- ->setPassword($userFromDataBase['password'])
- ->setRoles(json_decode($userFromDataBase['roles']))
- ->setEnabled($userFromDataBase['active']);
-
- $userManager = new UserManager();
- if ($userManager->isPasswordValid($user, $_POST['password'])) {
-
- // login OK, set Token in session
- $userManager->createUserToken($user);
-
- } else {
- // login failed , return error
- }
diff --git a/classes/cache/Cache_interface.php b/classes/cache/Cache_interface.php
deleted file mode 100644
index 7c49789..0000000
--- a/classes/cache/Cache_interface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/** Cache interface
- * ---
- * Interface to save results of expensive data-extraction proccess,
- * in a fast-accessed medium (ussually RAM or NVME SSD units)
- */
-interface Cache_interface
-{
- /** Cache::set($key, $data, $ttl) : void
- *
- * @param $key (string): reference label
- * @param $data (mixed): actual data (avoid storing true|false)
- * @param $ttl (int): time to live (seconds)
- */
- public function set(string $key, $data, int $ttl);
-
-
- /** Cache::get($key) : mixed
- *
- * @param $key (string)
- * @return mixed: fetched $data -or- false on failure
- */
- public function get(string $key);
-
-
- /** Cache::flush( $olderThan ) : void
- *
- * clear cache older than $olderThan
- * @param $olderThan (int) in seconds
- */
- public function flush(int $olderThan = 0);
-
-} \ No newline at end of file
diff --git a/classes/cache/FileCache.php b/classes/cache/FileCache.php
deleted file mode 100644
index fb7eee5..0000000
--- a/classes/cache/FileCache.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-/* FileCache
- * ---
- * Saves serialized data into filesystem.
- * Use it for expensive database-queries.
- * Performanve on a NVMe-SSD drive is really great;
- * (even better than MemCached and Redis)
- * performance on a typical HDD is just fair.
- *
- * NOTE:
- * Memcached and Redis are much faster cache-technologies
- * and generally recommended; but they are not always available;
- * FileCache is (almost) always available;
- *
- * Before tou decide on your caching technology
- * run some benchmarks.
- */
-class FileCache implements Cache_interface
-{
-
- /** store
- * ---
- * serializes and saves data in a file
- * along with TTL (time-to-live)
- */
- public function set(string $key, $data, int $ttl)
- {
- // filename is a hashed 48-hex-digit string
- // probability of collision = exp( (-k*(k-1)) / 2N )
- // ex: for 10tril.samples P(collision) = 1.5E-11%
- $filename = FILECACHE_PATH . sha1($key);
-
- // Opening file for write
- $h = fopen($filename, 'w');
- if (!$h) throw new Exception('Can not write to cache');
-
- // Serialize along with the TTL
- $data = serialize( array(
- time() + $ttl, // array[0] holds expiration time
- $data) // array[1] holds the actual data
- );
-
- if (fwrite($h,$data) === false) {
- throw new Exception('Can not write to cache');
- }
- fclose($h);
- }
-
-
- /** fetch
- * ---
- * feth data for certain key
- * @param $key (string)
- * @return fetched $data -or- false on failure
- */
- public function get(string $key)
- {
- $filename = FILECACHE_PATH . sha1($key);
-
- // can not read the cache-file? return false
- if (!file_exists($filename) || !is_readable($filename)) return false;
-
- $data = file_get_contents($filename); // get cache-file contents
- $data = @unserialize($data); // unserialize
-
- if (!$data) {
-
- // Unlinking the file when unserializing failed
- unlink($filename);
- return false;
-
- }
-
- // checking if the data was expired
- if (time() > $data[0]) {
-
- // Unlinking
- unlink($filename);
- return false;
-
- }
-
- return $data[1];
- }
-
-
- public function flush(int $olderThan = 0)
- {
- return false; // reply false until implementation
- }
-
-}
diff --git a/classes/cache/MemcachedCache.php b/classes/cache/MemcachedCache.php
deleted file mode 100644
index c89d86a..0000000
--- a/classes/cache/MemcachedCache.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/** Memcached Implementation
- * (implements Cache interface; extends Cache)
- * ---
- */
-class MemcachedCache implements Cache_interface
-{
-
- public function set($key, $data, $ttl)
- {
- $hashkey = md5($key);
-
- $mc = new Memcached();
- $mc->addServer(\MEMCACHE_HOST, 11211);
-
- $mc->set($hashkey, $data, $ttl);
- }
-
-
- public function get($key)
- {
- $hashkey = md5($key);
-
- $mc = new Memcached();
- $mc->addServer(\MEMCACHE_HOST, 11211);
-
- return $mc->get($hashkey);
-
- }
-
- public function flush($olderThan = 0)
- {
- return false;
- }
-
-} \ No newline at end of file
diff --git a/classes/cache/RedisCache.php b/classes/cache/RedisCache.php
deleted file mode 100644
index ec50f08..0000000
--- a/classes/cache/RedisCache.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-/** Redis Cache implementation
- * ---
- * This class uses \Predis\Redis, so do not forget require it via composer
- * or to use the configuration options you will find into \README.md
- */
-class RedisCache implements Cache_interface
-{
- /** set
- * store $data under the label $key
- * cache expires in $ttl seconds
- */
- public function set($key, $data, $ttl)
- {
- $serialized = serialize($data);
-
- if ($serialized = '') {
- return false;
- }
-
- try {
- $redis = new \Predis\Client([
- 'host' => \REDIS_HOST
- ]);
- return $redis->set($key, $serialized, 'EX', $ttl);
-
- } catch (Exception $e) {
- // ...
- }
- }
-
-
- /** get
- * fetch previously stored $data under label $key
- * return $data (or false)
- */
- public function get($key)
- {
-
- try {
-
- $redis = new \Predis\Client([
- 'host' => \REDIS_HOST
- ]);
-
- if ($redis->exists($key)) {
- return unserialize($redis->get($key));
-
- } else {
- return false;
- }
-
- } catch (Exception $e) {
- // ...
- }
-
- }
-
-
- /** flush
- * --- not umplemented yet; may not needed
- */
- public function flush($olderThan = 0)
- {
- return false; // until implementation
- }
-
-} \ No newline at end of file
diff --git a/classes/session/DatabaseSession.php b/classes/session/DatabaseSession.php
deleted file mode 100644
index aa31b62..0000000
--- a/classes/session/DatabaseSession.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-// class DatabaseSession implements Session_interface
-class DatabaseSession implements SessionHandlerInterface
-{
- /** PROPERTIES
- * -------------------------------------------------------------------------
- */
-
- private $db; // the database object
-
- // private $db_driver; // the database driver
-
-
- /** METHODS
- * -------------------------------------------------------------------------
- */
-
- /** __construct
- * set database connection
- * set session handler to overide default session
- * start session
- */
- public function __construct()
- {
- // Prepare the Database object
- $this->db = Registry::use('database');
-
- // Set handler to overide SESSION
- session_set_save_handler(
- array($this, "open"),
- array($this, "close"),
- array($this, "read"),
- array($this, "write"),
- array($this, "destroy"),
- array($this, "gc")
- );
-
- // Start the session
- session_name(SESSION_NAME);
- session_start();
- }
-
- // public function open(string $path, string $name) : bool
- // NOTE: $path and $name are unsued
- public function open() : bool
- {
- if ($this->db) {
- return true;
- }
- else {
- // database connection may be closed from another class
- // (ex. from some user class); in this case...
- // create a new database connection, then recheck.
- $conn = new Database();
- // $this->db = $conn->connect();
-
- if ($conn) {
- $this->db = $conn;
- return true;
- }
- }
- return false;
- }
-
-
- public function close() : bool
- {
- // depricated: the database object is shared (don;t clode it!)
- // // Close the database connection
- // if ($this->db = null) { return true; }
- // else return false;
-
- return true;
- }
-
-
- public function read(string $id) : string|false
- {
- $exist = $this->db->runQuery(
- "SELECT data FROM sessions WHERE id = :id",
- [':id', $id]
- );
-
- if (($exist === false) || (count($exist) == 0)) {
- return false;
-
- } else {
- $data = $exist[0];
- }
-
- if (is_null($row['data'])) {
- return '';
- }
- return $row['data'];
- }
-
-
- public function write(string $id, string $data) : bool
- {
- // Create timestamp
- $access = time();
- $check = $this->db->runQuery(
- "REPLACE INTO sessions VALUES (:id, :access, :data)",
- [':id' => $id, ':access' => $access, ':data' => $data ]
- );
- return ($check == false) ? false : true;
- }
-
-
- public function destroy(string $sassionID) : bool
- {
- $check = $this->db->runQuery(
- 'DELETE FROM sessions WHERE id = :id',
- [':id' => $sassionID]
- );
- return ($check == false) ? false : true;
- }
-
-
- public function gc(int $max)
- {
- // Calculate what is to be deemed old
- $old = time() - $max;
- $check = $this->db->runQuery(
- 'DELETE FROM sessions WHERE access < :old',
- [':old' => $old]
- );
- return ($check == false) ? false : 1;
- // check garbage-collector probability to run
- // echo "probability: ". ini_get("session.gc_probability") ." / ". ini_get("session.gc_divisor") . ", ttl: ". ini_get("session.gc_maxlifetime"); die();
-
- }
-
- # callable $create_sid = ?,
- # callable $validate_sid = ?,
- # callable $update_timestamp = ?
-}
diff --git a/classes/session/DefaultSession.php b/classes/session/DefaultSession.php
deleted file mode 100644
index d3099a5..0000000
--- a/classes/session/DefaultSession.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-/** DefauleSession
- * --
- * is a dummy session hanlder that wraps the
- * php's default session engine implementation;
- */
-class DefaultSession implements SessionHandlerInterface {
-
- public function __construct()
- {
- // Start the session
- session_name(SESSION_NAME);
- session_start();
- }
-
- #[\ReturnTypeWillChange]
- public function open(string $path, string $name) {}
-
- #[ReturnTypeWillChange]
- public function close() {}
-
- #[ReturnTypeWillChange]
- public function read(string $id) {}
-
- #[ReturnTypeWillChange]
- public function write(string $id, string $data) {}
-
- #[ReturnTypeWillChange]
- public function destroy(string $id) {}
-
- #[ReturnTypeWillChange]
- public function gc(int $max_lifetime) {}
-
-} \ No newline at end of file
diff --git a/classes/session/FilesSession.php b/classes/session/FilesSession.php
deleted file mode 100644
index 8762776..0000000
--- a/classes/session/FilesSession.php
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-
-/** FileSessionHandler
- * is a custom File-based Session Handler
- *
- * Could be useful when implemented along with data-cryptography,
- * otherwise php's default session handler (which is also file-based)
- * seems to be the obvious way to go;
- *
- * NOTE:
- * if shared sessions accros an array of servers is needed,
- * a database-session handler is probably the best choice.
- *
- * TODO:
- * implement cryptography
- */
-class FileSessionHandler implements SessionHandlerInterface
-{
- /** The filesystem instance. */
- protected $sessionName;
-
- /** The path where all sessions should be stored. */
- protected $path;
-
- /** The number of minutes the session should be valid. */
- protected $minutes;
-
- /**
- * Create a new file driven session-handler instance.
- *
- * @param string $path
- * @param int $minutes
- * @return void
- */
- public function __construct()
- {
- // values comming from configuration
- $this->sess_filename = $path;
- $this->minutes = $minutes;
-
- // Set handler to overide SESSION
- session_set_save_handler(
- array($this, "open"),
- array($this, "close"),
- array($this, "read"),
- array($this, "write"),
- array($this, "destroy"),
- array($this, "gc")
- );
-
- // Start the session
- session_name(SESSION_NAME);
- session_start();
- }
-
- /** open
- * set filename;
- * no need to touch the filesystem yet
- * return true (always)
- */
- public function open($savePath, $sessionName): bool
- {
- $this->sess_filename = $this->$path .'/'. $sessionName;
- return true;
- }
-
- /** close
- * nothing needs to be closed;
- * return true (always)
- */
- public function close(): bool
- {
- return true;
- }
-
- /** read
- * chech if file exists; if not return false
- * read data
- */
- public function read($sessionId): string|false
- {
- if (!file_exists($filename) || !is_readable($filename)) return false;
- return file_get_contents($filename);
-
- # if ($this->files->isFile($path = $this->path.'/'.$sessionId) &&
- # $this->files->lastModified($path) >= Carbon::now()->subMinutes($this->minutes)->getTimestamp()) {
- # return $this->files->sharedGet($path);
- # }
-
- # depricated? return '';
- }
-
- /** write
- * data serielized already by php's internal session engine
- */
- public function write($sessionId, $data): bool
- {
- $h = fopen($filename, 'w');
- if (fwrite($h,$data) === false) {
- throw new Exception('Could not write session data');
- return false;
- }
- fclose($h);
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- *
- * @return bool
- */
- public function destroy($sassionID): bool
- {
- unlink($this->sassionID);
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- *
- * @return int
- */
- public function gc($lifetime) : int
- {
- $files = Finder::create()
- ->in($this->path)
- ->files()
- ->ignoreDotFiles(true)
- ->date('<= now - '.$lifetime.' seconds');
-
- $deletedSessions = 0;
-
- foreach ($files as $file) {
- $this->files->delete($file->getRealPath());
- $deletedSessions++;
- }
-
- return $deletedSessions;
- }
-}
diff --git a/classes/session/SessionHandlerInterface.php b/classes/session/SessionHandlerInterface.php
deleted file mode 100644
index cf6efac..0000000
--- a/classes/session/SessionHandlerInterface.php
+++ /dev/null
@@ -1,169 +0,0 @@
-<?php
-
-/** SessionHandlerInterface
- *
- * as of php's documentation (check manual)
- * https://www.php.net/manual/en/class.sessionhandlerinterface.php
- */
-interface SessionHandlerInterface
-{
-
- /* Methods
- *--------------------------------------------------------------------------
- */
-
- public function open(string $path, string $name) : bool;
-
- public function close() : bool;
-
- public function read(string $id) : string|false;
-
- public function write(string $id, string $data) : bool;
-
- public function destroy(string $id) : bool;
-
- public function gc(int $max_lifetime) : int|false;
-
-}
-
-/** TODO: (thoughts)
- * ... for a brand-new session implementation
- *
- * In most cases, the session data does not require persistence.
- * The session information could be cached to improve performance
- *
- * So (in theory) we could create a two-dimension session mechanism
- *
- * + a fast dimension
- * : could be file-based (using local FS [php's default?] or redis/memcached)
- *
- * + a shared dimension
- * : implemented in a shared database
- *
- * Posible algo:
- * ... (check later on this comment-block: session life-cycle )
- *
- * open :
- * close : on both
- * read : check Local; if not exist check database; set session_id($id)
- * write : on both
- * destroy : on both
- * gc : on server
- *
- * when regenerating session_id, keep database informed about the new session_id
- * when closing, keep database informed about the session end-of-life.
- *
- * a session timeout on the local leg will trigger a confirm-session-from-db
- *
- * garbage collector on the db should remove expired sessions of some X seconds
- * and earier (X needs to be determined by practice/expirience/tries)
- *
- * (+) in order to keep tracking of the session between multiple servers through
- * the (shared) database, a unique secret-between-the-servers id can be used
- *
- * so...
- *
- * #1
- * -> someone visits website through server A
- * -> server A creates a new session-id for the visitor and a shared-session-id
- * -> saves both into database
- *
- * later...
- *
- * #2
- * -> the same device is connected (via loadbalancer) into server B
- * -> server B don't have the session-id (send by the client) but gets it from db
- * (is session-id do not exist on the db, then this is a new session)
- *
- * = now both server A and B have the same session-id localy
- *
- * later...
- *
- * #3
- * -> some server (let's say B) regenerates the visitors session-id
- * -> if later the visitor falls into server A, the A will retrieve the new
- * session id through the #2 scenario
- *
- * this way
- * + any server can update/regenerate the visitor's session-id
- * + the visitor can be served from both servers randomly
- * + all session variables exist on the database (always)
- * + all session variables exist on all servers synced-on-demand
- *
- *
- * stucture of session:
- * ---
- * - shared-session-id: (secret + persistent); exposed between servers **primary
- * - session-id: (may change/regenerate/update); exposed to the client **indexed
- * - data: serialized array
- * - creation_timestamp:
- * - last_touched_timestamp:
- * - expiration_timestamp: should point to the future or session has expired
- * - csrf_token:
- * - JWT_token
- * - AES-key (this way private data can be kept in browser)
- *
- *
- * what will kept on browser/client (via cookie)
- * ---
- * - session-name => session-id
- * - user info => AES_ectypted(serialized[t=>csfr_token, u=> user_id, s=>SIGNATURE])
- *
- *
- * Writable file-system shall change
- * (local writable file-system tree)
- * ---
- * /html/storage
- * |
- * |-- cache : query-caches
- * |
- * `-- session : FS\sessions
- * |
- * `-- indexes : share-session-id indexes
- *
- *
- *
- * NOTE: Session life-cycle
- *
- * session_start() * firsts time
- * ---
- * ::open(path,PHPSESSID) -> (session_id not exist) -> false
- * ::create_sid -> '123def'
- * ::read('123def') ?-or/and- ::close()
- *
- *
- * session_start() * next times
- * ---
- * ::open(path, PHPSESSID) -> (session_id exist) -> true
- * ::read('123def') -> return data -> will fill $_SESSION[*]
- *
- *
- * $_SESSION['foo'] = 'bar';
- * ---
- * ::write('123def', 'foo|s:3:"bar";') -> ['foo' => "bar"]
- * ::close()
- *
- *
- * session_regenerate_id();
- * ---
- * ::create_sid() -> def123
- *
- *
- * session_reset()
- * ---
- * ::open()
- * ::read('def123')
- *
- *
- * session_write_close()
- * ---
- * ::write('123def', 'foo|s:3:"bar";')
- * ::close()
- *
- *
- * session_destroy()
- * ---
- * ::destroy('def123')
- * ::close()
- *
- */