From 21fedb3af692b12c1f0aa266bbf788b01f2cbe4c Mon Sep 17 00:00:00 2001 From: George Halkiadakis Date: Sun, 26 Mar 2023 04:50:46 +0300 Subject: auth tests --- core/classes/Render.php | 343 ++++++++++++++++++++++++++++++++ core/classes/session/DefaultSession.php | 9 +- core/classes/session/FilesSession.php | 20 +- core/config/anom_settings.php | 312 +++++++++++++++++++++-------- core/config/credentials.php | 126 ------------ core/config/init.php | 17 +- core/helpers/error_handling.php | 8 +- core/helpers/render.php | 338 ------------------------------- 8 files changed, 602 insertions(+), 571 deletions(-) create mode 100644 core/classes/Render.php delete mode 100644 core/config/credentials.php delete mode 100644 core/helpers/render.php (limited to 'core') diff --git a/core/classes/Render.php b/core/classes/Render.php new file mode 100644 index 0000000..401178d --- /dev/null +++ b/core/classes/Render.php @@ -0,0 +1,343 @@ +"; + } + + } + + /** parse_sections + * --- + * parse a group of views (sections) + * @param $sections: an array of sections + * + * each section group is an array with view, key and data properties + * + view: defines the view template/file + * + key: the variable name that view uses to parse data OR empty-string* + * * if key is an empty then $data should be an array (which + * includes all [variable-name:data] pairs utilized by the view) + * + data: holds the actual data + */ + + public static function sections($sections) { + + foreach($sections as $sect) { + + if ($sect['key'] == '') { + self::view( $sect['view'], $sect['data'] ); + + } else { + self::view( $sect['view'], [ $sect['key'] => $sect['data']] ); + } + } + } + + + /** render function + * --- + * uses php's short-tag syntax for templating system + * extract data into template + * @param $view: view-template filename + * @param $data: data to embed into view-template + * @param $sanitize: of true then sanitize data. + * important NOTE: data is an array [key => value] + */ + public static function view($view, $data=[], $sanitize = false) { + + $file = VIEWS_DIRECTORY . $view . '.php'; + + if (file_exists($file)) { + if (!defined('OUTPUT_STARTED')) define('OUTPUT_STARTED', 1); + + extract( $sanitize ? self::sanitize_output($data) : $data ); + require( $file ); + + } else if (!PRODUCTION) { + + echo ""; + } + + } + + + /** render asap + * --- + * render_view then output code + * so that client will get html to render + * while server calculates next html + */ + public static function asap($view, $data, $sanitize = false) { + self::view($view, $data, $sanitize); + ob_flush(); + } + + + /** render text + * --- + * This function simply echoes text + * with Content-Type and Cache Headers + * @param $data : the text to echo + * @param $cType : Content-Type header + * @param $ttl : cache-contol headers; if false response is not-cached; else (int) chache for $ttl seconds + */ + public static function text( $data, $contentType = 'text/html; charset=UTF-8', $ttl = false ) { + header('Content-Type: '. $contentType); + if ($ttl) { + $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; + header("Expires: {$ts}"); + header("Pragma: cache"); + header("Cache-Control: max-age={$ttl}"); + + } else { + $ts = gmdate("D, d M Y H:i:s") . " GMT"; + header("Expires: {$ts}"); + header("Last-Modified: {$ts}"); + header("Pragma: no-cache"); + header("Cache-Control: no-cache, must-revalidate"); + } + echo htmlspecialchars($data); + } + + + /** reply_json + * --- + * transform a php-array to json and echo to client + * Can be used for API calls + * + * @param $data : the php array) + * @param $ttl : cache-contol headers; if false response is not-cached; else chache for $ttl seconds + */ + public static function json( $data, $ttl = false ) { + header('Content-Type: application/json'); + if ($ttl) { + $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; + header("Expires: {$ts}"); + header("Pragma: cache"); + header("Cache-Control: max-age={$ttl}"); + + } else { + $ts = gmdate("D, d M Y H:i:s") . " GMT"; + header("Expires: {$ts}"); + header("Last-Modified: {$ts}"); + header("Pragma: no-cache"); + header("Cache-Control: no-cache, must-revalidate"); + } + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + + + // HELPER FUNCTIONS + // ----------------------------------------------------------------------------- + + + /** link asset + * --- + * the function defines the assets (css or js) + * to be loaded on the client (creates the HTML) + * @param $type : type of asset [css|js] + * @param $assetIDs : an array of ('assetID' => 'paramaters') + * + * example calls: + * load_asset('css', ['main' => 'media="all"', 'filters' => 'media="all"']); + * load_asset( 'js', ['jquery' => '', 'lazyloader' => 'async']); + */ + public static function asset( $type, $assetIDs, $paramatres = '' ) { + + $code = ""; // code to return + + // make sure $assetIDs is array (for coding simplicity) + if (!is_array($assetIDs)) { + $assetIDs = [ $assetIDs ]; + } + + // check asset type and construct all asset inserts + switch ($type) { + + case 'font': + foreach($assetIDs as $asset) { + $code .= "\n\t"; + } + break; + + case 'js': + foreach($assetIDs as $asset) { + $code .= "\n\t"; + } + break; + + case 'css': + default: + foreach($assetIDs as $asset) { + $code .= "\n\t"; + } + } + + echo $code; + } + + + /** sanitize_output (recursive) + * --- + * Sanitizes data that are about to rendered + * (usually when render_view() is called). + * + * NOTE: + * mitigates XSS attachs + * + * @param $data: (array) + */ + public static function sanitize_output($data) { + //// check https://stackoverflow.com/questions/2002710/php-how-to-perform-htmlspecialchar-on-an-array-of-arrays + + //// $output = array_map("myFunc", $data); + + global $secure; + + $output = array(); + foreach($data as $key => $val) { + + if (is_string($val)) { + $output[$key] = htmlspecialchars(self::remove_invisible_characters($val)); + + } else if (is_array($val)) { + $output[$key] = self::sanitize_output($val); + + } else { + $output[$key] = $val; + } + } + return $output; + } + + + /** remove_invisible_characters() + * --- + * @used by sanitize_output() + */ + public static function remove_invisible_characters($str, $url_encoded = TRUE) + { + $non_displayables = array(); + + // every control character except newline (dec 10), + // carriage return (dec 13) and horizontal tab (dec 09) + if ($url_encoded) { + $non_displayables[] = '/%0[0-8bcef]/i'; // url encoded 00-08, 11, 12, 14, 15 + $non_displayables[] = '/%1[0-9a-f]/i'; // url encoded 16-31 + $non_displayables[] = '/%7f/i'; // url encoded 127 + } + + $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 + + do { + $str = preg_replace($non_displayables, '', $str, -1, $count); + } while ($count); + + return $str; + } + + + /** html + * --- + * outputs code as html + * + * @param $str (string) + * @return html5 (string) + */ + public static function html($str) { + if (!isset($str) || $str== null) return; + if (($str == '') || is_numeric($str)) return $str; + return htmlspecialchars_decode($str, ENT_QUOTES|ENT_HTML5); + } + + + /** set_headers + * --- + * set custom response-Headers + * + * @param $contentType + * @param $ttl: int or false) + * @param $more: array of (content-type => content-value) pairs + */ + public static function set_headers($contentType = 'text/html; charset=UTF-8', $ttl = false, $more = [] ) { + + // handle common content-type shorcuts + switch ($contentType) { + case 'text': + case 'html': + $contentType = 'text/html; charset=UTF-8'; + break; + case 'json': + $contentType = 'application/json; charset=utf-8'; + break; + case 'js': + $contentType = 'application/javascript; charset=utf-8'; + break; + case 'css': + $contentType = 'text/css'; + break; + default: + // $contentType stays as-is + break; + } + + // send headers + header('Content-Type: '. $contentType); + if ($ttl) { + $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; + header("Expires: {$ts}"); + header("Pragma: cache"); + header("Cache-Control: max-age={$ttl}"); + + } else { + $ts = gmdate("D, d M Y H:i:s") . " GMT"; + header("Expires: {$ts}"); + header("Last-Modified: {$ts}"); + header("Pragma: no-cache"); + header("Cache-Control: no-cache, must-revalidate"); + } + + // send more headers + if ($more != []) { + foreach($more as $header => $value) { + header($header .': '. $value); + } + } + + } + + + +} \ No newline at end of file diff --git a/core/classes/session/DefaultSession.php b/core/classes/session/DefaultSession.php index d3099a5..079ab9d 100644 --- a/core/classes/session/DefaultSession.php +++ b/core/classes/session/DefaultSession.php @@ -2,14 +2,19 @@ /** 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 + // (the default way) + // and let the session* functions + // do what they know session_name(SESSION_NAME); session_start(); } @@ -21,7 +26,9 @@ class DefaultSession implements SessionHandlerInterface { public function close() {} #[ReturnTypeWillChange] - public function read(string $id) {} + public function read(string $id) { + + } #[ReturnTypeWillChange] public function write(string $id, string $data) {} diff --git a/core/classes/session/FilesSession.php b/core/classes/session/FilesSession.php index 8762776..a06f29c 100644 --- a/core/classes/session/FilesSession.php +++ b/core/classes/session/FilesSession.php @@ -35,6 +35,7 @@ class FileSessionHandler implements SessionHandlerInterface public function __construct() { // values comming from configuration + $this->sessionName = SESSION_NAME; $this->sess_filename = $path; $this->minutes = $minutes; @@ -49,7 +50,7 @@ class FileSessionHandler implements SessionHandlerInterface ); // Start the session - session_name(SESSION_NAME); + session_name($this->sessionName); session_start(); } @@ -80,14 +81,9 @@ class FileSessionHandler implements SessionHandlerInterface public function read($sessionId): string|false { if (!file_exists($filename) || !is_readable($filename)) return false; - return file_get_contents($filename); + $data = 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 ''; + return @unserialize($data); } /** write @@ -96,11 +92,11 @@ class FileSessionHandler implements SessionHandlerInterface public function write($sessionId, $data): bool { $h = fopen($filename, 'w'); - if (fwrite($h,$data) === false) { + if (fwrite($h, serialize($data)) === false) { throw new Exception('Could not write session data'); return false; - } - fclose($h); + } + fclose($h); return true; } @@ -128,7 +124,7 @@ class FileSessionHandler implements SessionHandlerInterface ->in($this->path) ->files() ->ignoreDotFiles(true) - ->date('<= now - '.$lifetime.' seconds'); + ->date('<= now - '. $lifetime .' seconds'); $deletedSessions = 0; diff --git a/core/config/anom_settings.php b/core/config/anom_settings.php index 406c6aa..76c7c62 100644 --- a/core/config/anom_settings.php +++ b/core/config/anom_settings.php @@ -1,35 +1,37 @@ 'Please forgive me, I know not what I do']); + Render::view('error/general', ['message' => 'Please forgive me, I know not what I do']); } } else { - if (!defined('VIEW_LOADED')) { + if (!defined('OUTPUT_STARTED')) { // no template loaded; render erros in general-error template - render_view('error/general', ['message' => implode("
And:
", $anom_ERRORS)]); + Render::view('error/general', ['message' => implode("
And:
", $anom_ERRORS)]); } else { echo '
diff --git a/core/helpers/render.php b/core/helpers/render.php deleted file mode 100644 index 9dcd34a..0000000 --- a/core/helpers/render.php +++ /dev/null @@ -1,338 +0,0 @@ -"; - } - -} - -/** parse_sections - * --- - * parse a group of views (sections) - * @param $sections: an array of sections - * - * each section group is an array with view, key and data properties - * + view: defines the view template/file - * + key: the variable name that view uses to parse data OR empty-string* - * * if key is an empty then $data should be an array (which - * includes all [variable-name:data] pairs utilized by the view) - * + data: holds the actual data - */ - -function parse_sections($sections) { - - foreach($sections as $sect) { - - if ($sect['key'] == '') { - render_view( $sect['view'], $sect['data'] ); - - } else { - render_view( $sect['view'], [ $sect['key'] => $sect['data']] ); - } - } -} - - -/** render function - * --- - * uses php's short-tag syntax for templating system - * extract data into template - * @param $view: view-template filename - * @param $data: data to embed into view-template - * @param $sanitize: of true then sanitize data. - * important NOTE: data is an array [key => value] - */ -function render_view($view, $data, $sanitize = false) { - - $file = VIEWS_DIRECTORY . $view . '.php'; - - if (file_exists($file)) { - if (!defined('VIEW_LOADED')) define('VIEW_LOADED', 1); - - extract( $sanitize ? sanitize_output($data) : $data ); - require( $file ); - - } else if (!PRODUCTION) { - - echo ""; - } - -} - - -/** render asap - * --- - * render_view then output code - * so that client will get html to render - * while server calculates next html - */ -function render_asap($view, $data, $sanitize = false) { - render_view($view, $data, $sanitize); - ob_flush(); -} - - -/** render text - * --- - * This function simply echoes text - * with Content-Type and Cache Headers - * @param $data : the text to echo - * @param $cType : Content-Type header - * @param $ttl : cache-contol headers; if false response is not-cached; else (int) chache for $ttl seconds - */ -function render_text( $data, $contentType = 'text/html; charset=UTF-8', $ttl = false ) { - header('Content-Type: '. $contentType); - if ($ttl) { - $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; - header("Expires: {$ts}"); - header("Pragma: cache"); - header("Cache-Control: max-age={$ttl}"); - - } else { - $ts = gmdate("D, d M Y H:i:s") . " GMT"; - header("Expires: {$ts}"); - header("Last-Modified: {$ts}"); - header("Pragma: no-cache"); - header("Cache-Control: no-cache, must-revalidate"); - } - echo htmlspecialchars($data); -} - - -/** reply_json - * --- - * transform a php-array to json and echo to client - * Can be used for API calls - * - * @param $data : the php array) - * @param $ttl : cache-contol headers; if false response is not-cached; else chache for $ttl seconds - */ -function reply_json( $data, $ttl = false ) { - header('Content-Type: application/json'); - if ($ttl) { - $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; - header("Expires: {$ts}"); - header("Pragma: cache"); - header("Cache-Control: max-age={$ttl}"); - - } else { - $ts = gmdate("D, d M Y H:i:s") . " GMT"; - header("Expires: {$ts}"); - header("Last-Modified: {$ts}"); - header("Pragma: no-cache"); - header("Cache-Control: no-cache, must-revalidate"); - } - echo json_encode($data, JSON_UNESCAPED_UNICODE); -} - - - - -// HELPER FUNCTIONS -// ----------------------------------------------------------------------------- - - -/** link asset - * --- - * the function defines the assets (css or js) - * to be loaded on the client (creates the HTML) - * @param $type : type of asset [css|js] - * @param $assetIDs : an array of ('assetID' => 'paramaters') - * - * example calls: - * load_asset('css', ['main' => 'media="all"', 'filters' => 'media="all"']); - * load_asset( 'js', ['jquery' => '', 'lazyloader' => 'async']); - */ -function link_asset( $type, $assetIDs, $paramatres = '' ) { - - $code = ""; // code to return - - // make sure $assetIDs is array (for coding simplicity) - if (!is_array($assetIDs)) { - $assetIDs = [ $assetIDs ]; - } - - // check asset type and construct all asset inserts - switch ($type) { - - case 'font': - foreach($assetIDs as $asset) { - $code .= "\n\t"; - } - break; - - case 'js': - foreach($assetIDs as $asset) { - $code .= "\n\t"; - } - break; - - case 'css': - default: - foreach($assetIDs as $asset) { - $code .= "\n\t"; - } - } - - echo $code; -} - - -/** sanitize_output (recursive) - * --- - * Sanitizes data that are about to rendered - * (usually when render_view() is called). - * NOTE: mitigates XSS attachs - * @param $data: (array) - */ -function sanitize_output($data) { - //// // check https://stackoverflow.com/questions/2002710/php-how-to-perform-htmlspecialchar-on-an-array-of-arrays - - //// $output = array_map("myFunc", $data); - global $secure; - - $output = array(); - foreach($data as $key => $val) { - - if (is_string($val)) { - $output[$key] = htmlspecialchars(remove_invisible_characters($val)); - - } else if (is_array($val)) { - $output[$key] = sanitize_output($val); - - } else { - $output[$key] = $val; - } - } - return $output; -} - - -/** remove_invisible_characters() - * --- - * @used by sanitize_output() - */ -function remove_invisible_characters($str, $url_encoded = TRUE) -{ - $non_displayables = array(); - - // every control character except newline (dec 10), - // carriage return (dec 13) and horizontal tab (dec 09) - if ($url_encoded) { - $non_displayables[] = '/%0[0-8bcef]/i'; // url encoded 00-08, 11, 12, 14, 15 - $non_displayables[] = '/%1[0-9a-f]/i'; // url encoded 16-31 - $non_displayables[] = '/%7f/i'; // url encoded 127 - } - - $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 - - do { - $str = preg_replace($non_displayables, '', $str, -1, $count); - } while ($count); - - return $str; -} - - -/** html - * --- - * outputs code as html - * - * @param $str (string) - * @return html5 (string) - */ -function html($str) { - if (!isset($str) || $str== null) return; - if (($str == '') || is_numeric($str)) return $str; - return htmlspecialchars_decode($str, ENT_QUOTES|ENT_HTML5); -} - - -/** set_headers - * --- - * set custom response-Headers - * - * @param $contentType - * @param $ttl: int or false) - * @param $more: array of (content-type => content-value) pairs - */ -function set_headers($contentType = 'text/html; charset=UTF-8', $ttl = false, $more = [] ) { - - // handle common content-type shorcuts - switch ($contentType) { - case 'text': - case 'html': - $contentType = 'text/html; charset=UTF-8'; - break; - case 'json': - $contentType = 'application/json; charset=utf-8'; - break; - case 'js': - $contentType = 'application/javascript; charset=utf-8'; - break; - case 'css': - $contentType = 'text/css'; - break; - default: - // $contentType stays as-is - break; - } - - // send headers - header('Content-Type: '. $contentType); - if ($ttl) { - $ts = gmdate("D, d M Y H:i:s", time() + $ttl) . " GMT"; - header("Expires: {$ts}"); - header("Pragma: cache"); - header("Cache-Control: max-age={$ttl}"); - - } else { - $ts = gmdate("D, d M Y H:i:s") . " GMT"; - header("Expires: {$ts}"); - header("Last-Modified: {$ts}"); - header("Pragma: no-cache"); - header("Cache-Control: no-cache, must-revalidate"); - } - - // send more headers - if ($more != []) { - foreach($more as $header => $value) { - header($header .': '. $value); - } - } - -} - - - -- cgit v1.2.3