diff options
| author | George Halkiadakis <gchalkiadakis@sklavenitis.co.gr> | 2023-03-12 07:16:23 +0200 |
|---|---|---|
| committer | George Halkiadakis <gchalkiadakis@sklavenitis.co.gr> | 2023-03-12 07:16:23 +0200 |
| commit | 7076343338ae3439f3c86f01144818abe8c31978 (patch) | |
| tree | 794abb1e6b8f821091fd095341885496b6dad51d /helpers | |
| parent | 47cbb529f5723b246125ae083a193e11481b89ef (diff) | |
| download | classroom-7076343338ae3439f3c86f01144818abe8c31978.tar.gz classroom-7076343338ae3439f3c86f01144818abe8c31978.tar.bz2 classroom-7076343338ae3439f3c86f01144818abe8c31978.zip | |
add container helpers; constuct public directory-tree
Diffstat (limited to 'helpers')
| -rw-r--r-- | helpers/autoload.php | 43 | ||||
| -rw-r--r-- | helpers/design_patterns.php | 104 | ||||
| -rw-r--r-- | helpers/error_handling.php | 119 | ||||
| -rw-r--r-- | helpers/render.php | 338 |
4 files changed, 0 insertions, 604 deletions
diff --git a/helpers/autoload.php b/helpers/autoload.php deleted file mode 100644 index c4359c6..0000000 --- a/helpers/autoload.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/** register class-autoloader - * - * NOTE: - * Composer is strongly recommended; it is a much better option - * and takes care for many more than just autoloading classes; - * - * This's a fair autoloader in case composer is not available; - * supports single and namespaced classes. - */ -spl_autoload_register( - function($className) { - - // in order to support common namespaced classes - // replace '\' with '/' to get the path - $classPath = str_replace('\\', DIRECTORY_SEPARATOR, $className); - - // check all possible classPaths for class - foreach(CLASSPATHS as $key => $basePath) { - - $file = APP_ROOT . $basePath . $classPath .'.php'; - - // if class-file exist, include it - if (file_exists($file)) { - require_once $file; - break; - } - - } - - // // Feel free to extend the fanctionality - // // example: - // // custom (exception) namespaced classes loader - // $customNSclasses = array( - // '\\George\\Class' => 'path/to/George/Class', - // '\\Mary\\Class' => 'path/to/Marias/Class', - // ... - // ); - // if array_key_exists($className) { - // require_once $customNSclasses[$className]; - // } - } -); diff --git a/helpers/design_patterns.php b/helpers/design_patterns.php deleted file mode 100644 index d66ffa9..0000000 --- a/helpers/design_patterns.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php -/** proxy - * implements the proxy design pattern - * - * uses: Registry::cache - * - * algorithm: - * - 1: proxy gets (Class::method, Arguments) and calculates a unique key - * - 2: if a valid Cache for the triplete's key exists, it is served immediately - * - 3: otherwise calls Class::Method(Arguments), caches then serves response - * - * @param $class_method (array): a 2 (string) items array in the form - * : [ 'fully\qualifies\ClassName' , 'methodName' ] - * : Using the ClassName::class notation is strongly recommended. - * @param $args: array of arguments (passed to the Class::Method()) - * @param $ttl: time (in sec) where the data will remain valid (not expired) - * @param $options: bitwise flags* - * --- - * @return $data (mixed) - * - * (*) option flags - * all option flags represend non default behaviour of proxy - * --- - * PROXY_CACHE_ERRORS : cache value even if callback returns error - * PROXY_IGNORE_CACHE : ignore if cache exist; get result from callback - * PROXY_DO_NOT_CACHE : do not cache the result (even if from callback) - */ -function proxy(array $callable, array $args, int $ttl, int $options=0) -{ - // resolve option flags - $cache_errors = ($options&PROXY_CACHE_ERRORS) ? true : false; - $ignore_cache = ($options&PROXY_IGNORE_CACHE) ? true : false; - $do_not_cache = ($options&PROXY_DO_NOT_CACHE) ? true : false; - - // we're gonna use cache; - $cache = Registry::use('cache'); - - - // check validity of callable argument - // ------------------------------------------------------------------------- - if ((!is_callable($callable)) || (!is_array($callable))) { - - throw new Exception( - 'Proxy\'s first parameter has to be a callable array [fully\\qualified\\ClassName, method], passed:'.print_r($callable, true) - ); - - } - - // create a unique key - // ------------------------------------------------------------------------- - list($class, $method) = $callable; - $key = sha1( - $class .':'. $method .':'. json_encode( - $args, JSON_UNESCAPED_LINE_TERMINATORS|JSON_UNESCAPED_UNICODE - ) - ); - - // search cache if data for this key exist - // ------------------------------------------------------------------------- - if (!$ignore_cache) { - $data = $cache->get($key); - - } else { $data = false; } // ignore cache? pass false - - - if ($data !== false) { // if exists, serve cached data - - // if cashed data exist - // --------------------------------------------------------------------- - # if (!PRODUCTION) Benchmark::add_spot('proxy-cached'); - if ($data == '_ERROR_') return false; // previous cached error - else return $data; // previous cache () - - - } else { // else (not exist)... - - // no data on cache -> get data from Class::method( arguments ) - // --------------------------------------------------------------------- - $data = call_user_func_array($callable, $args); - - // handle newly created data - // --------------------------------------------------------------------- - - // if faulty data, return false - if ($data == false) { - - if ($cache_errors && !$do_not_cache) { // cache the error - $cache->set($key, '_ERROR_', $ttl); - } - - # if (!PRODUCTION) Benchmark::add_spot('proxy-new-error'); - return false; - } - - // store to cache - if (!$do_not_cache) { - $cache->set($key, $data, $ttl); - } - - # if (!PRODUCTION) Benchmark::add_spot('proxy-new'); - return $data; // serve data - } - -} diff --git a/helpers/error_handling.php b/helpers/error_handling.php deleted file mode 100644 index bc60968..0000000 --- a/helpers/error_handling.php +++ /dev/null @@ -1,119 +0,0 @@ -<?php -/** ERROR HANDLING SECTION - * handles exceptions and errors (even fatal) - * ----------------------------------------------------------------------------- - * The code... - * + Catches and handles all Errors and Throwable exceptions; - * - creates the error messages (for the requester and developer) - * ? TODO: routes the error messages to the logging channels - */ - - -// Global array to save errors -$anom_ERRORS = []; // ok, Globals are not recommended, but... - // this one collects only errors (about the application); - // it is oriented for the developer; not for the request. - - -/** Error handler, - * passes flow over the exception logger with new ErrorException. - */ -function handle_error(int $type, string $message, string $file, int $line) -{ - handle_exception( new ErrorException($message, 0, $type, $file, $line) ); -} - - -/** Uncaught exception handler. -*/ -function handle_exception(Throwable $e) -{ - global $anom_ERRORS; - - // full message description to be logged - $message = get_class($e) .": ". $e->getMessage() - . " on file '". $e->getFile() . "' at line {$e->getLine()}"; - - $anom_ERRORS[] = $message; // store the error -} - - -/** - * Catch fatal error work-around - * (set_error_handler not working on fatal errors). - */ -function on_shutdown_check_for_fatal() -{ - global $anom_ERRORS; - - $error = error_get_last(); - - if ($error != null) { // ignore 'normal' system shutdowns [exit|die]() - - if ( $error["type"] == E_ERROR ) { // get as much error-info - handle_error( - $error["type"] ?? -1, - $error["message"] ?? 'unknown error', - $error["file"] ?? 'unknown file', - $error["line"] ?? -1 - ); - } - } - - if (($anom_ERRORS != [])) { - - // TODO: - // Implemetnig the design/layout of the error-messages - // output should not be an error's-handling task, thus - // shall be assigned to the Rendes/View level; - // Same about the log service channels - - // TODO: - // FORWARD ERRORS into LOG-SYSTEM - // ex. into some file... - // file_put_contents("logs/thowable.log", $message_template .PHP_EOL, FILE_APPEND); - // or ...some other channer (Email, Slack, Database etc). - // Channes can be decided according to error severity; - // a file-system error loggin for backup is recommended - // partitioniong of errors onto file-system can be useful - - // TODO: - // 1st: Log Errors - // 2nd: Show Errors - - if (PRODUCTION) { - if (!defined('VIEW_LOADED')) { - // throw a prety-error message - render_view('error/general', ['message' => 'Please forgive me, I know not what I do']); - } - - } else { - - if (!defined('VIEW_LOADED')) { - // no template loaded; render erros in general-error template - render_view('error/general', ['message' => implode("<br/>And:<br/>", $anom_ERRORS)]); - - } else { - echo '<div style="padding:1em;background:#933;width:100%;color:#fff"> - Errors:<br />'. implode("<br/>And:<br/>", $anom_ERRORS) .'</div>'; - } - } - } -} - - -// register callback on shutdown -register_shutdown_function( "on_shutdown_check_for_fatal" ); - -// register custom error handler callback -set_error_handler( "handle_error" ); - -// set custom exception handler function -set_exception_handler( "handle_exception" ); - -// send errors to stderr (instead of stdout) -ini_set( "display_errors", "off" ); - -// thow out all errors -error_reporting( E_ALL ); - diff --git a/helpers/render.php b/helpers/render.php deleted file mode 100644 index 9dcd34a..0000000 --- a/helpers/render.php +++ /dev/null @@ -1,338 +0,0 @@ -<?php -/** Rendering System - * --- - * this is the View part of the MVC framework. - * Decided not to make it a Class - ***/ - - -/** load template - * --- - * TODO: - * explain/document the difference between a template and a view - * - * TODO: - * Implementing the Render/View operation as a class, using the same- - * name methods with Laraver or CodeIgniter could be good idea; - * and get rid of if(!defined('VIEW_LOADED')) define('VIEW_LOADED',1); - */ -function load_template($template, $data) { - - $file = VIEWS_DIRECTORY . $template . '.php'; - - if (file_exists($file)) { - if (!defined('VIEW_LOADED')) define('VIEW_LOADED', 1); - - ob_start(); - - extract( sanitize_output($data) ); - require( $file ); - - ob_flush(); - - } else if (!PRODUCTION) { - - echo "<!-- view ". $file ." is missing -->"; - } - -} - -/** 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 "<!-- view ". $file ." is missing -->"; - } - -} - - -/** 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<link href='". FONTS_DIR . FONT_FILES[$asset] ."' as='font' type='font/woff2' {$paramatres}/>"; - } - break; - - case 'js': - foreach($assetIDs as $asset) { - $code .= "\n\t<script src='". JS_DIR . JS_LIBRARIES[$asset] ."' id='{$asset}' {$paramatres}></script>"; - } - break; - - case 'css': - default: - foreach($assetIDs as $asset) { - $code .= "\n\t<link rel='stylesheet' href='". CSS_DIR . CSS_FILES[$asset] ."' id='{$asset}' {$paramatres} />"; - } - } - - 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); - } - } - -} - - - |
