* @copyright Copyright (c) 2022, Robert Strutts. * @license https://mit-license.org/ */ namespace tts; use Exception; /** * * @todo Ensure tts JS error reporting works * @todo Finish Session MGT, Encrypted Sessions * @todo Make Cached Sessions * @todo Force Database methods to try Cache First and Save Cache Data */ class app { private $file; private $class; private $method; private $params; private function get_first_chunks(string $input): string { $parts = explode('/', $input); $last = array_pop($parts); $parts = array(implode('/', $parts), $last); return $parts[0]; } private function get_last_part(string $input): string { $reversedParts = explode('/', strrev($input), 2); return strrev($reversedParts[0]); } /** * Do not declare a return type here, as it will Error out!! */ public function __construct() { $full_route = \bs_tts\site_helper::get_route(); $no_hmtl = str_replace(".html", "", $full_route); // Find the Route $route = $this->get_first_chunks($no_hmtl); // Find the Method $the_method = $this->get_last_part($no_hmtl); $params = \bs_tts\site_helper::get_params(); // Now load Route $is_from_the_controller = true; // TRUE for from Constructor... $this->router($route, $the_method, $params, $is_from_the_controller); } private function get_ctrl_dir(): string { $ctrl = (\tts\console_app::is_cli()) ? "cli_" : ""; return (\bs_tts\site_helper::get_testing()) ? "test_" : $ctrl; } /** * Gets route and checks if valid * @param string $route * @param string $method * @param bool $is_controller * @retval action */ public function router(?string $route, ?string $method, $params, bool $is_controller = false) { $ROOT = \bs_tts\site_helper::get_root(); $file = ""; $class = ""; if (\tts\misc::is_empty($route)) { $uri = '/app/' . \main_tts\configure::get('tts', 'default_project'); } else { $uri = $route; } try { $filtered_uri = \tts\security::filter_uri($uri); } catch (Exception $ex) { $this->local404(); // Route Un-Safe URI to Local 404 Page } $safe_folders = \bs_tts\requires::filter_dir_path( $this->get_first_chunks($filtered_uri) ); if (\bs_tts\requires::is_dangerous($safe_folders)) { $this->local404(); } $safe_folders = rtrim($safe_folders, '/'); if (empty($ROOT)) { $this->local404(); } $safe_file = \bs_tts\requires::filter_dir_path( $this->get_last_part($filtered_uri) ); if (\bs_tts\requires::is_dangerous($safe_file)) { $this->local404(); } $test = $this->get_ctrl_dir(); $dir = \bs_tts\requires::safer_dir_exists($ROOT . \bs_tts\site_helper::get_project() . "{$test}controllers/" . $safe_folders); //check for default site controller first if ($dir === false) { $this->local404(); } else { $file = \bs_tts\requires::safer_file_exists(basename($safe_file) . '_ctrl.php', $dir); if ($file !== false) { $class = \tts\security::filter_class($safe_folders) . "\\" . \tts\security::filter_class($safe_file . "_ctrl"); } else { $this->local404(); } } if (\tts\misc::is_empty($method)) { $method = ""; // Clear out :null if exists } if (substr($method, 0, 2) == '__') { $method = ""; // Stop any magical methods being called } if ($is_controller === true) { $this->file = $file; $this->class = $class; $this->method = $method; $this->params = $params; } else { return $this->action($file, $class, $method, $params); } } private function local404() { \tts\page_not_found::error404(); } /** * Do controller action * @param string $file * @param string $class * @param string $method * @retval type */ private function action(string $file, string $class, string $method, $params) { $safer_file = \bs_tts\requires::safer_file_exists($file); if (! $safer_file) { $this->local404(); } if (empty($class)) { $this->local404(); } $use_api = \tts\misc::is_api(); $test = $this->get_ctrl_dir(); $project_folder = \bs_tts\site_helper::get_project(); $call_class = "\\prj\\" . rtrim($project_folder, "/") . '\\' . $test . 'controllers\\' . $class; $controller = new $call_class(); if ($method === "error" && str_contains($class, "app") && method_exists($controller, $method) === false ) { tts_broken_error(); return false; } if ($use_api) { if (empty($method)) { $method = "index"; } $method .= "_api"; if (method_exists($controller, $method)) { return $controller->$method($params); } else { \tts\page_not_found::error404_cli(); } } else { if (!empty($method) && method_exists($controller, $method)) { return $controller->$method($params); } else { if (empty($method) && method_exists($controller, 'index')) { return $controller->index($params); } else { $this->local404(); } } } } /** * Does load controller by calling action */ public function load_controller() { return $this->action($this->file, $this->class, $this->method, $this->params); } } // end of app