diff --git a/src/bootstrap/errors.php b/src/bootstrap/errors.php
index c18bd9b..35d50ef 100644
--- a/src/bootstrap/errors.php
+++ b/src/bootstrap/errors.php
@@ -32,11 +32,11 @@ function tts_broken_error($ex = ''): void {
\tts\api::error(array('response' => $internal_error, 'code' => 500, 'reason' => 'Internal Error'));
}
- if (\main_tts\configure::get('tts', 'live') === true) {
+ if (\main_tts\is_live()) {
$resource = \main_tts\configure::get('tts', 'error_page');
$exists = \bs_tts\requires::secure_include('views/errors', $resource); // Show Broken Page
if ($exists === false) {
- echo "Sorry, we had an error...We apologize for any inconvenience this may cause.";
+ echo "
Sorry, we had an error...
We apologize for any inconvenience this may cause.
";
}
} else {
$view = new \tts\view();
@@ -211,7 +211,7 @@ function tts_json_error_handler($data) {
} catch (Exception $e) {
}
- if (\main_tts\configure::get('tts', 'live') === true) {
+ if (\main_tts\is_live()) {
\tts_email_error($data);
}
@@ -251,6 +251,10 @@ function tts_json_error_handler($data) {
* @param \Throwable $exception Error
*/
function tts_exception_handler(\Throwable $exception) {
+ if (!\main_tts\errors::get_handle_exceptions()) {
+ return;
+ }
+
$err = "Fatal Error: Uncaught exception " . get_class($exception) . " with message: " . $exception->getMessage();
$err .= " thrown in: " . $exception->getFile() . " on line: " . $exception->getLine() . "\r\n";
$common_err = 'Fatal error: Uncaught exception \'' . get_class($exception) . '\' with message ';
@@ -266,7 +270,7 @@ function tts_exception_handler(\Throwable $exception) {
$msg .= $common_err;
$msg .= '';
- if (\main_tts\configure::get('tts', 'live') === true) {
+ if (\main_tts\is_live()) {
tts_global_error_handler(E_USER_ERROR, $err);
} else {
echo tts_mini_view('dev_error', 'tts', $msg);
@@ -276,7 +280,7 @@ function tts_exception_handler(\Throwable $exception) {
set_exception_handler('tts_exception_handler');
-if (\main_tts\configure::get('tts', 'live') === true) {
+if (\main_tts\is_live()) {
error_reporting(E_ALL ^ E_NOTICE);
set_error_handler('tts_global_error_handler', E_ALL ^ (E_NOTICE | E_USER_NOTICE));
} else {
@@ -289,10 +293,13 @@ register_shutdown_function('tts_custom_error_checker');
* Custom Error Checked called on Script Shutdown.
*/
function tts_custom_error_checker(): void {
+ if (!\main_tts\errors::get_handle_shutdown_errors()) {
+ return;
+ }
$a_errors = error_get_last();
if (is_array($a_errors)) {
$msg = "Error: {$a_errors['message']} File:{$a_errors['file']} Line:{$a_errors['line']}.";
- if (\main_tts\configure::get('tts', 'live') === true) {
+ if (\main_tts\is_live()) {
$msg = wordwrap($msg, WORD_WRAP_CHRS, "
\n");
try {
$exists = \main_tts\registry::get('di')->exists('log');
@@ -327,6 +334,10 @@ function tts_custom_error_checker(): void {
* @param type $errline
*/
function tts_global_error_handler(int $errno = 0, string $errstr = '', string $errfile = '', int $errline = 0) {
+ if (!\main_tts\errors::get_handle_global_errors()) {
+ return;
+ }
+
switch ($errno) {
case E_USER_ERROR:
$err = "My ERROR [$errno] $errstr
\n";
@@ -352,7 +363,7 @@ function tts_global_error_handler(int $errno = 0, string $errstr = '', string $e
tts_json_error_handler($err);
- if (\main_tts\configure::get('tts', 'live') === false) {
+ if (! \main_tts\is_live()) {
return true;
}
diff --git a/src/bootstrap/safer_io.php b/src/bootstrap/safer_io.php
index 1724821..d861292 100644
--- a/src/bootstrap/safer_io.php
+++ b/src/bootstrap/safer_io.php
@@ -139,10 +139,23 @@ final class use_iol {
}
final class safer_io {
+ private static $JSON_POST_DATA = [];
+ private static $DATA_INPUTS = [];
protected function __construct() {
}
+ // Allow anything to set_data_inputs is desired here
+ public static function set_data_input(string $var_name, $data_in): void {
+ if (! isset(self::$DATA_INPUTS[$var_name])) {
+ self::$DATA_INPUTS[$var_name] = $data_in;
+ }
+ }
+ // Do not allow anyone out-side of this class to get this un-filtered input
+ private static function get_data_input(string $var_name) {
+ return (isset(self::$DATA_INPUTS[$var_name])) ?
+ self::$DATA_INPUTS[$var_name] : null;
+ }
public static function convert_to_utf8(string $in_str): string {
if (! extension_loaded('mbstring')) {
@@ -294,12 +307,17 @@ final class safer_io {
return $item;
}
- static $JSON_POST_DATA = [];
private static function get_input_by_type(
string $input_field_name,
INPUTS $input_type,
): mixed {
+ /* Must return here to avoid Failing Resolve later on in this FN
+ * as input types variable, debugging, and json will not Resolve!
+ */
+ if ($input_type == INPUTS::variable) {
+ return self::get_data_input($input_field_name);
+ }
if ($input_type == INPUTS::debugging) {
if (isset(self::$JSON_POST_DATA[$input_field_name])) {
return self::$JSON_POST_DATA[$input_field_name];
diff --git a/src/bootstrap/site_helper.php b/src/bootstrap/site_helper.php
index d76ef4e..4e8ac4c 100644
--- a/src/bootstrap/site_helper.php
+++ b/src/bootstrap/site_helper.php
@@ -21,11 +21,60 @@ final class site_helper {
private static $queryParams;
private static $DEFAULT_PROJECT;
private static $all_projects = [];
+ private static $local_site_domains = ['localhost'];
+ private static $Private_IPs_allowed = ['127.0.0.1', '::1'];
+ private static $Public_IPs_allowed = [];
public static function set_all_projects(array $projects): void {
self::$all_projects = $projects;
}
+ public static function set_local_site_domains(string|array $domain_name): void {
+ if (is_array($domain_name)) {
+ foreach($domain_name as $domain) {
+ self::$local_site_domains[] = $domain;
+ }
+ } elseif (is_string($domain_name)) {
+ self::$local_site_domains[] = $domain_name;
+ }
+ }
+
+ public static function set_allowed_Private_IPs(string|array $IP_addresses): void {
+ if (is_array($IP_addresses)) {
+ foreach($IP_addresses as $IP) {
+ $s_ip = \tts\security::get_valid_ip($IP);
+ if ($s_ip === false) {
+ continue;
+ }
+ self::$Private_IPs_allowed[] = $IP;
+ }
+ } elseif (is_string($IP_addresses)) {
+ $s_ip = \tts\security::get_valid_ip($IP);
+ if ($s_ip === false) {
+ return;
+ }
+ self::$Private_IPs_allowed[] = $IP_addresses;
+ }
+ }
+
+ public static function set_allowed_Public_IPs(string|array $IP_addresses): void {
+ if (is_array($IP_addresses)) {
+ foreach($IP_addresses as $IP) {
+ $s_ip = \tts\security::get_valid_public_ip($IP);
+ if ($s_ip === false) {
+ continue;
+ }
+ self::$Public_IPs_allowed[] = $s_ip;
+ }
+ } elseif (is_string($IP_addresses)) {
+ $s_ip = \tts\security::get_valid_public_ip($IP);
+ if ($s_ip === false) {
+ return;
+ }
+ self::$Public_IPs_allowed[] = $IP_addresses;
+ }
+ }
+
public static function get_root(): string {
return self::$ROOT;
}
@@ -58,13 +107,33 @@ final class site_helper {
self::$DEFAULT_PROJECT = $project;
}
+ public static function is_server_name_a_private_domain(): bool {
+ $white_list = array_merge(self::$local_site_domains, self::$Private_IPs_allowed);
+ return (\tts\security::is_server_name_on_domain_list($white_list));
+ }
+
+ public static function remote_not_allowed_force_live(): bool {
+ return (! self::is_allowed());
+ }
+
+ public static function is_allowed(): bool {
+ $remote_ip = \tts\security::get_client_ip_address();
+ if (in_array($remote_ip, self::$Public_IPs_allowed)) {
+ return true;
+ }
+ if (self::is_server_name_a_private_domain() && in_array($remote_ip, self::$Private_IPs_allowed)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Because $_SERVER['REQUEST_URI'] May only available on Apache,
* we generate an equivalent using other environment variables.
* @return string
*/
public static function tts_request_uri() {
- if (!empty(self::$REQUEST_URI) && self::$REQUEST_URI !== null) {
+ if (self::$REQUEST_URI !== null && !empty(self::$REQUEST_URI)) {
$uri = self::$REQUEST_URI;
} else if (isset($_SERVER['REQUEST_URI'])) {
$uri = \bs_tts\safer_io::get_clean_server_var('REQUEST_URI');
diff --git a/src/classes/app.php b/src/classes/app.php
index 0d7a079..aa84022 100644
--- a/src/classes/app.php
+++ b/src/classes/app.php
@@ -81,7 +81,11 @@ class app {
$uri = $route;
}
- $filtered_uri = \tts\security::filter_uri($uri);
+ 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)
@@ -138,13 +142,7 @@ class app {
private function local404() {
\tts\page_not_found::tts_error404();
}
-
- private function handle_my_errors($controller, string $method_name): void {
-// if (! method_exists($controller, "skip_default_error_handler_for_" . $method_name)) {
-// require_once \main_tts\TTS_FRAMEWORK . 'bootstrap/errors.php';
-// }
- }
-
+
/**
* Do controller action
* @param string $file
@@ -175,18 +173,15 @@ class app {
}
$method .= "_api";
if (method_exists($controller, $method)) {
- $this->handle_my_errors($controller, $method);
return $controller->$method($params);
} else {
\tts\page_not_found::tts_error404_cli();
}
} else {
if (!empty($method) && method_exists($controller, $method)) {
- $this->handle_my_errors($controller, $method);
return $controller->$method($params);
} else {
if (empty($method) && method_exists($controller, 'index')) {
- $this->handle_my_errors($controller, 'index');
return $controller->index($params);
} else {
$this->local404();
diff --git a/src/classes/assets.php b/src/classes/assets.php
index bb18456..e8ecdc8 100644
--- a/src/classes/assets.php
+++ b/src/classes/assets.php
@@ -215,7 +215,7 @@ final class assets {
$safe_file = \tts\security::filter_uri($file);
if (\bs_tts\common::is_string_found($safe_file, '.auto.js')) {
- $production = (\main_tts\configure::get('tts', 'live') === true) ? true : false;
+ $production = (\main_tts\is_live());
$safe_file = str_replace('.auto.js', '', $safe_file);
if ( $production && file_exists($safe_path . $safe_file . '.min.js') ) {
return $safe_file . '.min.js';
@@ -224,7 +224,7 @@ final class assets {
}
if (\bs_tts\common::is_string_found($safe_file, '.auto.css')) {
- $production = (\main_tts\configure::get('tts', 'live') === true) ? true : false;
+ $production = (\main_tts\is_live());
$safe_file = str_replace('.auto.css', '', $safe_file);
if ( $production && file_exists($safe_path . $safe_file . '.min.css') ) {
return $safe_file . '.min.css';
diff --git a/src/classes/database/help_save.php b/src/classes/database/help_save.php
index b46418e..5a45d74 100644
--- a/src/classes/database/help_save.php
+++ b/src/classes/database/help_save.php
@@ -126,7 +126,7 @@ final class help_save {
* the DB security and Inject stuff into the DB via POST, etc...
*/
public function auto_set_members(array $post = [], array $skip = ['route', 'm'], array $only_these = []): void {
- if (\main_tts\configure::get('tts', 'live') === true) {
+ if (\main_tts\is_live()) {
return; // Bail if LIVE
}
if (isset($post['json'])) {
diff --git a/src/classes/exceptions/DB_Exception.php b/src/classes/exceptions/DB_Exception.php
index dec3e8a..fd295da 100644
--- a/src/classes/exceptions/DB_Exception.php
+++ b/src/classes/exceptions/DB_Exception.php
@@ -53,7 +53,7 @@ class DB_Exception extends \Exception {
if (empty($message)) {
$message = self::$error_message;
}
- $live = \bs_tts\common::get_bool( \main_tts\configure::get('tts', 'live') );
+ $live = (\main_tts\is_live());
if ($live === false || \bs_tts\common::has_user_right('debugger')) {
$msg = ($debug == DEBUGGER::basic ||
(self::$debug === DEBUGGER::basic &&
diff --git a/src/classes/page_not_found.php b/src/classes/page_not_found.php
index c306c9b..c7ca65a 100644
--- a/src/classes/page_not_found.php
+++ b/src/classes/page_not_found.php
@@ -48,17 +48,9 @@ class page_not_found {
self::tts_api_method_not_found();
}
- $resource = \main_tts\configure::get('tts', '404_page');
-
- if ($resource === null) {
- echo "404 Page Not Found!";
- exit(1);
- }
-
- $loaded = \bs_tts\requires::secure_include('views/404', $resource); // Show 404, Page Not Found Error Page!
-
+ $loaded = \bs_tts\requires::secure_include('views/404', 'tts'); // Show 404, Page Not Found Error Page!
if ($loaded === false) {
- echo "404 Page Not Found!";
+ echo "404 Page Not Found!
";
}
exit(1);
diff --git a/src/classes/security.php b/src/classes/security.php
index 141bb9c..5670280 100644
--- a/src/classes/security.php
+++ b/src/classes/security.php
@@ -156,28 +156,23 @@ final class security {
public static function id_hash(): string {
return crc32($_SESSION['user_id']);
}
+
+ public static function get_valid_ip(string $ip) {
+ return (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6));
+ }
+ public static function get_valid_public_ip(string $ip) {
+ return (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6|FILTER_FLAG_NO_PRIV_RANGE));
+ }
/**
- * LocalHost / Private IP - Check
- * @return bool is LocalHost
+ * Is the server on the local test domain name
+ * @return bool SERVER Domain name is on whitelist
*/
- public static function is_localhost(): bool {
- $whitelist = array('127.0.0.1', '::1', 'localhost', 'dev');
+ public static function is_server_name_on_domain_list(array $whitelist): bool {
if (!isset($_SERVER['SERVER_NAME'])) {
return false;
}
-
- if (\bs_tts\common::get_bool(\main_tts\configure::get('important', 'private_ip_as_local')) === true) {
- if (!filter_var($_SERVER['SERVER_NAME'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE)) { // | FILTER_FLAG_NO_RES_RANGE
- return true; // Private IP
- }
- }
-
- if (in_array($_SERVER['SERVER_NAME'], $whitelist)) {
- return true;
- } else {
- return false;
- }
+ return (in_array($_SERVER['SERVER_NAME'], $whitelist));
}
/**
@@ -185,22 +180,23 @@ final class security {
* @return bool
*/
public static function request_is_same_domain(): bool {
- if (self::is_localhost()) {
- return true;
- }
-
if (!isset($_SERVER['HTTP_REFERER'])) {
// No referer send, so can't be same domain!
return false;
} else {
$referer_host = parse_url($_SERVER['HTTP_REFERER'] . PHP_URL_HOST);
+ if ($referer_host === false) {
+ return false; // Malformed URL
+ }
+ $refed_host = $referer_host['host'] ?? "";
+
$server_host = $_SERVER['HTTP_HOST'];
- return ($referer_host === $server_host) ? true : false;
+ return ($refed_host === $server_host);
}
}
- public static function get_client_ip_server() {
+ public static function get_client_ip_address() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
diff --git a/src/classes/tag_matches.php b/src/classes/tag_matches.php
index 5769006..b1ad9ee 100644
--- a/src/classes/tag_matches.php
+++ b/src/classes/tag_matches.php
@@ -50,11 +50,11 @@ public static function check_tags(string $page): array {
if ($total_still_open > 0) {
$msg = "{$total_still_open} possibly MISSING closing {$tag_name} !!!";
$alert .= "console.log('{$msg}');\r\n";
- $output .= (\main_tts\configure::get('tts', 'live') === true) ? "\r\n" : "{$ui}{$msg}{$ui_end}\r\n";
+ $output .= (\main_tts\is_live()) ? "\r\n" : "{$ui}{$msg}{$ui_end}\r\n";
} elseif ($total_still_open < 0) {
$msg = abs($total_still_open) . " possibly MISSING opening {$tag_name} !!!";
$alert .= "console.log('{$msg}');\r\n";
- $output .= (\main_tts\configure::get('tts', 'live') === true) ? "\r\n" : "{$ui}{$msg}{$ui_end}\r\n";
+ $output .= (\main_tts\is_live()) ? "\r\n" : "{$ui}{$msg}{$ui_end}\r\n";
}
}
return array('output' => $output, 'alert' => $alert);
diff --git a/src/classes/view.php b/src/classes/view.php
index 3a8f9e7..5386f4e 100644
--- a/src/classes/view.php
+++ b/src/classes/view.php
@@ -22,6 +22,7 @@ namespace tts;
final class view {
public $white_space_control = false;
+ public $page_output;
private $vars = array();
private $project_dir;
private $files = array();
@@ -218,7 +219,7 @@ final class view {
$assigns = $this->vars['template_assigns'] ?? [];
$filters = $this->vars['template_filters'] ?? null;
$registers = $this->vars['template_registers'] ?? [];
- $assigns['production'] =(\main_tts\configure::get('tts', 'live') === true) ? true : false;
+ $assigns['production'] =(\main_tts\is_live());
echo $this->tempalte_engine->render($assigns, $filters, $registers);
}
}
diff --git a/src/main.inc.php b/src/main.inc.php
index 3d223eb..af0d475 100644
--- a/src/main.inc.php
+++ b/src/main.inc.php
@@ -10,8 +10,8 @@ declare(strict_types=1);
namespace main_tts;
-unset($_REQUEST); // Request is dangerious
-unset($_GET);
+unset($_REQUEST); // Request is dangerious as order of Vars is not Known
+unset($_GET); // Super Globals are not Filtered, so unset them
unset($_POST);
$mem_baseline = memory_get_usage();
@@ -34,6 +34,31 @@ if (\bs_tts\site_helper::get_testing() === false) {
views::ob_start();
}
+final class errors {
+ private static $handle_global_errors = true;
+ private static $handle_shutdown_errors = true;
+ private static $handle_exceptions = true;
+
+ public static function set_handle_shutdown_errors(bool $do_handle_errors): void {
+ self::$handle_shutdown_errors = $do_handle_errors;
+ }
+ public static function get_handle_shutdown_errors(): bool {
+ return self::$handle_shutdown_errors;
+ }
+ public static function set_handle_exceptions(bool $do_handle_errors): void {
+ self::$handle_exceptions = $do_handle_errors;
+ }
+ public static function get_handle_exceptions(): bool {
+ return self::$handle_exceptions;
+ }
+ public static function set_handle_global_errors(bool $do_handle_errors): void {
+ self::$handle_global_errors = $do_handle_errors;
+ }
+ public static function get_handle_global_errors(): bool {
+ return self::$handle_global_errors;
+ }
+}
+
final class configure {
private static $config = [];
@@ -191,10 +216,12 @@ final class di {
try {
$reflection_class = new \ReflectionClass($service_name);
} catch (\ReflectionException $e) {
- if (! \main_tts\configure::set('tts', 'live')) {
+ if (! is_live()) {
var_dump($e->getTrace());
echo $e->getMessage();
exit;
+ } else {
+ throw new \Exception("Failed to resolve resource: {$service_name}!");
}
}
if (! $reflection_class->isInstantiable()) {
@@ -242,7 +269,10 @@ if (extension_loaded('mbstring')) {
setlocale(LC_ALL, "en_US.UTF-8");
}
-require_once TTS_FRAMEWORK . 'bootstrap/errors.php';
+function is_live() {
+ return (\bs_tts\common::get_bool(configure::get('tts', 'live')));
+}
+
require_once TTS_FRAMEWORK . 'bootstrap/common.php';
require_once TTS_FRAMEWORK . 'bootstrap/requires.php';
require_once TTS_FRAMEWORK . 'bootstrap/auto_loader.php';
@@ -253,4 +283,6 @@ registry::get('loader')->add_namespace("bs_tts", TTS_FRAMEWORK . "bootstrap");
registry::get('loader')->add_namespace("tts", TTS_FRAMEWORK . "classes");
registry::get('loader')->add_namespace("tts", TTS_FRAMEWORK . "tests");
+require_once TTS_FRAMEWORK . 'bootstrap/errors.php';
+
\bs_tts\site_helper::set_project_namespace();
\ No newline at end of file