|
|
|
|
@ -6,9 +6,104 @@ define('WORD_WRAP_CHRS', 80); // Letters before Line Wrap on Errors |
|
|
|
|
|
|
|
|
|
// Configuration |
|
|
|
|
if (! defined('BaseDir')) { |
|
|
|
|
define('BaseDir', ""); // To avoid defination errors |
|
|
|
|
define('LOG_FILE', false); |
|
|
|
|
} else { |
|
|
|
|
define('LOG_FILE', BaseDir . '/protected/logs/error_log.txt'); |
|
|
|
|
define('LOG_FILE', BaseDir . '/protected/logs/errors.log.txt'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_dev(): bool { |
|
|
|
|
if (! defined("ENVIRONMENT")) { |
|
|
|
|
return false; // Force (false) which means Live on unknown state |
|
|
|
|
} |
|
|
|
|
return (ENVIRONMENT === 'development') ? true : false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_get_config(string $key, string $item, $default_when_not_found = false) { |
|
|
|
|
if (! method_exists("\CodeHydrater\bootstrap\configure", "has")) { |
|
|
|
|
return $default_when_not_found; |
|
|
|
|
} |
|
|
|
|
$value = $default_when_not_found; // Init defaults |
|
|
|
|
if (configure::has($key, $item)) { |
|
|
|
|
$value = configure::get($key, $item); |
|
|
|
|
if ($value === null) { |
|
|
|
|
return $default_when_not_found; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return $value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function should_be_broken(string $msg = ""): bool { |
|
|
|
|
|
|
|
|
|
$clear = fallback_get_config("CodeHydrater", "clear_screen_on_prod_errors"); |
|
|
|
|
|
|
|
|
|
if (fallback_get_config("CodeHydrater", "if_live_with_error_show_broken_page") === true) { |
|
|
|
|
broken_error($msg, $clear); |
|
|
|
|
return true; |
|
|
|
|
} else { |
|
|
|
|
broken_error($msg, false); // Don't Clear |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_mini_view_prod(string $msg, string $file = "prod_error.php") { |
|
|
|
|
if (fallback_get_config("CodeHydrater", "clear_screen_on_prod_errors") === false) { |
|
|
|
|
return $msg; // Return Error Message on False and do not clear the Screen |
|
|
|
|
} |
|
|
|
|
echo fallback_mini_view($msg, $file); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_mini_view_dev(string $msg, string $file = "dev_error.php") { |
|
|
|
|
if (fallback_get_config("CodeHydrater", "clear_screen_on_dev_errors") === false) { |
|
|
|
|
return $msg; // Return Error Message on False and do not clear the Screen |
|
|
|
|
} |
|
|
|
|
echo fallback_mini_view($msg, $file); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_mini_view(string $msg, string $file = "dev_error.php"): string { |
|
|
|
|
|
|
|
|
|
@ob_end_clean(); // Wipe all HTML content before this.... |
|
|
|
|
if (!headers_sent()) { |
|
|
|
|
header('Content-Type: text/html; charset=utf-8', true, 200); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
views::ob_start(); |
|
|
|
|
|
|
|
|
|
$saved_ob_level = ob_get_level(); |
|
|
|
|
|
|
|
|
|
$mini = new \stdClass(); |
|
|
|
|
$mini->page_output = $msg; |
|
|
|
|
if (fallback_requires($file, false, $mini) === false) { |
|
|
|
|
fallback_requires("views/on_error/" . $file, true, $mini); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If you really must close all of your output buffers except one, this'll do it: |
|
|
|
|
while (ob_get_level() > $saved_ob_level) { |
|
|
|
|
ob_end_flush(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return @ob_get_clean(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_logger(string $logMessage, string $file = LOG_FILE) { |
|
|
|
|
if (method_exists("CodeHydrater\services\log", "write")) { |
|
|
|
|
$logger = new \CodeHydrater\services\log("errors"); |
|
|
|
|
$written = $logger->write($logMessage); |
|
|
|
|
if ($written === false) { |
|
|
|
|
// Open a connection to the system logger |
|
|
|
|
openlog("PHP App", LOG_PID | LOG_ODELAY, LOG_LOCAL0); |
|
|
|
|
|
|
|
|
|
// Write a message |
|
|
|
|
syslog(LOG_INFO, $logMessage); |
|
|
|
|
|
|
|
|
|
// Close the connection |
|
|
|
|
closelog(); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
$Message = date('[Y-m-d H:i:s]') . $logMessage; |
|
|
|
|
file_put_contents($file, $Message, FILE_APPEND); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -29,13 +124,23 @@ function formatMessage($message, $type = 'error') { |
|
|
|
|
} else { |
|
|
|
|
// Web HTML formatting |
|
|
|
|
$styles = [ |
|
|
|
|
'error' => 'color:red;', |
|
|
|
|
'warning' => 'color:orange;', |
|
|
|
|
'notice' => 'color:blue;' |
|
|
|
|
'error' => 'uk-alert-danger', |
|
|
|
|
'warning' => 'uk-alert-warning', |
|
|
|
|
'notice' => 'uk-alert-primary' |
|
|
|
|
]; |
|
|
|
|
$style = $styles[$type] ?? $styles['error']; |
|
|
|
|
$message = wordwrap($message, WORD_WRAP_CHRS, "<br>\n"); |
|
|
|
|
return "<div style='{$style}padding:10px;border:1px solid #f99;margin:10px;'>$message</div>"; |
|
|
|
|
|
|
|
|
|
$assets = "/assets/uikit/css/uikit.gradient.min.css"; |
|
|
|
|
if (file_exists(BaseDir. "/public/" . $assets)) { |
|
|
|
|
$msg = '<link rel="stylesheet" href="' . $assets . '" type="text/css" media="all" />'; |
|
|
|
|
$msg .= "<div class=\"uk-alert $style\">"; |
|
|
|
|
} else { |
|
|
|
|
$msg = "<div style=\"color: red;padding:10px;border:1px solid #f99;margin:10px;\""; |
|
|
|
|
} |
|
|
|
|
$msg .= $message; |
|
|
|
|
$msg .= "</div>"; |
|
|
|
|
return $msg; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -71,26 +176,18 @@ set_error_handler(function($errno, $errstr, $errfile, $errline) { |
|
|
|
|
$errorType = $errorInfo[0]; |
|
|
|
|
$errorCategory = $errorInfo[1]; |
|
|
|
|
|
|
|
|
|
$logMessage = date('[Y-m-d H:i:s]') . " [$errorType] $errstr in $errfile on line $errline" . PHP_EOL; |
|
|
|
|
$logMessage = " [$errorType] $errstr in $errfile on line $errline" . PHP_EOL; |
|
|
|
|
$displayMessage = "$errorType: $errstr in $errfile on line $errline"; |
|
|
|
|
|
|
|
|
|
// Log to file |
|
|
|
|
if (LOG_FILE !== false) { |
|
|
|
|
file_put_contents(LOG_FILE, $logMessage, FILE_APPEND); |
|
|
|
|
} |
|
|
|
|
fallback_logger($logMessage); |
|
|
|
|
|
|
|
|
|
// Display in development environment |
|
|
|
|
if (fallback_dev()) { |
|
|
|
|
echo formatMessage($displayMessage, $errorCategory); |
|
|
|
|
echo fallback_mini_view_dev(formatMessage($displayMessage, $errorCategory)); |
|
|
|
|
// Prevent PHP's default error handler |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (is_on_error_page() === true) { |
|
|
|
|
if (fallback_requires('prod_error.php') === false) { |
|
|
|
|
fallback_requires('views/on_error/prod_error.php', true); |
|
|
|
|
} |
|
|
|
|
exit(1); // Prevent HTML Looping!!! |
|
|
|
|
} |
|
|
|
|
should_be_broken($displayMessage); |
|
|
|
|
return true; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
@ -99,20 +196,21 @@ set_exception_handler(function($e) { |
|
|
|
|
if (method_exists("errors", "get_handle_exceptions") && ! errors::get_handle_exceptions()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
$logMessage = date('[Y-m-d H:i:s]') . " [EXCEPTION] " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine() . PHP_EOL; |
|
|
|
|
$logMessage = " [EXCEPTION] " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine() . PHP_EOL; |
|
|
|
|
$displayMessage = "UNCAUGHT EXCEPTION: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine(); |
|
|
|
|
|
|
|
|
|
if (LOG_FILE !== false) { |
|
|
|
|
file_put_contents(LOG_FILE, $logMessage, FILE_APPEND); |
|
|
|
|
} |
|
|
|
|
fallback_logger($logMessage); |
|
|
|
|
|
|
|
|
|
// Are we developing...? if so, show details on error |
|
|
|
|
if (fallback_dev()) { |
|
|
|
|
echo formatMessage($displayMessage, 'error'); |
|
|
|
|
echo fallback_mini_view_dev(formatMessage($displayMessage, 'error')); |
|
|
|
|
} else { |
|
|
|
|
// In production, show user-friendly message |
|
|
|
|
echo PHP_SAPI === 'cli' |
|
|
|
|
? "An error occurred. Our team has been notified." . PHP_EOL |
|
|
|
|
: "An error occurred. Our team has been notified."; |
|
|
|
|
if (should_be_broken($displayMessage) === false) { |
|
|
|
|
// In production, show user-friendly message |
|
|
|
|
echo PHP_SAPI === 'cli' |
|
|
|
|
? "An error occurred. Our team has been notified." . PHP_EOL |
|
|
|
|
: "An error occurred. Our team has been notified."; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
@ -123,31 +221,28 @@ register_shutdown_function(function() { |
|
|
|
|
} |
|
|
|
|
$error = error_get_last(); |
|
|
|
|
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { |
|
|
|
|
$logMessage = date('[Y-m-d H:i:s]') . " [FATAL] {$error['message']} in {$error['file']} on line {$error['line']}" . PHP_EOL; |
|
|
|
|
$logMessage = " [FATAL] {$error['message']} in {$error['file']} on line {$error['line']}" . PHP_EOL; |
|
|
|
|
$displayMessage = "FATAL ERROR: {$error['message']} in {$error['file']} on line {$error['line']}"; |
|
|
|
|
|
|
|
|
|
fallback_logger($logMessage); |
|
|
|
|
|
|
|
|
|
if (LOG_FILE !== false) { |
|
|
|
|
file_put_contents(LOG_FILE, $logMessage, FILE_APPEND); |
|
|
|
|
} |
|
|
|
|
// If developing, show error |
|
|
|
|
if (fallback_dev()) { |
|
|
|
|
echo formatMessage($displayMessage, 'error'); |
|
|
|
|
echo fallback_mini_view_dev(formatMessage($displayMessage, 'error')); |
|
|
|
|
} else { |
|
|
|
|
should_be_broken($displayMessage); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function fallback_is_live(): bool { |
|
|
|
|
return is_live(); // from main.php |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Displays Error page |
|
|
|
|
* @param type $ex error message |
|
|
|
|
*/ |
|
|
|
|
function broken_error($ex = ''): void { |
|
|
|
|
function broken_error(string $ex = "", bool $clear = false): void { |
|
|
|
|
if (fallback_is_cli()) { |
|
|
|
|
echo $ex; |
|
|
|
|
exit(1); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
$use_api = fallback_is_api(); |
|
|
|
|
|
|
|
|
|
@ -155,24 +250,14 @@ function broken_error($ex = ''): void { |
|
|
|
|
$internal_error = "An unexpected error occured."; |
|
|
|
|
$status_code = 500; |
|
|
|
|
fallback_json_error($internal_error, $status_code); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fallback_is_live()) { |
|
|
|
|
// Try really Hard to display Prod Error Page |
|
|
|
|
$exists = fallback_requires('prod_error.php'); |
|
|
|
|
if (! $exists) { |
|
|
|
|
$exists = fallback_requires('views/on_error/prod_error.php', true); |
|
|
|
|
} |
|
|
|
|
if ($exists === false) { |
|
|
|
|
echo "<h1>Sorry, we had an error...</h1><p>We apologize for any inconvenience this may cause.</p>"; |
|
|
|
|
} |
|
|
|
|
$error_message = "<h1>Sorry, we had an error...</h1><p>We apologize for any inconvenience this may cause.</p>"; |
|
|
|
|
if ($clear === false) { |
|
|
|
|
echo $error_message; |
|
|
|
|
} else { |
|
|
|
|
if ($ex === "") { |
|
|
|
|
echo "<h2>Unknown Issue...</h2>"; |
|
|
|
|
} else { |
|
|
|
|
echo $ex; |
|
|
|
|
} |
|
|
|
|
echo "<h1>Error Page</h1><p>Please go back to another page...</p>"; |
|
|
|
|
echo fallback_mini_view_prod($error_message); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -188,7 +273,6 @@ function fallback_json_error(string $data, int $status_code): void { |
|
|
|
|
header('Content-Type: application/json; charset=utf-8', true, intval($status_code)); |
|
|
|
|
} |
|
|
|
|
echo json_encode($data); |
|
|
|
|
exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_is_api(): bool { |
|
|
|
|
@ -224,20 +308,14 @@ function fallback_is_cli() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_get_uri(): ?string { |
|
|
|
|
return strtok($_SERVER['REQUEST_URI']); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_dev(): bool { |
|
|
|
|
if (! defined("ENVIRONMENT")) { |
|
|
|
|
return false; // Force Live on unknown state |
|
|
|
|
} |
|
|
|
|
if (ENVIRONMENT === 'development') { |
|
|
|
|
return true; |
|
|
|
|
$uri = strtok($_SERVER['REQUEST_URI'], "?"); |
|
|
|
|
if ($uri === false) { |
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
return $uri; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fallback_requires(string $file, bool $fw = false): bool { |
|
|
|
|
function fallback_requires(string $file, bool $fw = false, $local = null): bool { |
|
|
|
|
$exists = method_exists("\CodeHydrater\bootstrap\requires", "secure_include"); |
|
|
|
|
if ($exists) { |
|
|
|
|
if ($fw === false) { |
|
|
|
|
@ -261,19 +339,6 @@ function fallback_requires(string $file, bool $fw = false): bool { |
|
|
|
|
return false; // You have failed me for the last time! LOL |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Check if already on Error Page |
|
|
|
|
* @return bool |
|
|
|
|
*/ |
|
|
|
|
function is_on_error_page(): bool { |
|
|
|
|
if (fallback_is_cli()) { |
|
|
|
|
exit(1); |
|
|
|
|
} else { |
|
|
|
|
return (stripos(fallback_get_uri(), "error.html") !== false); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test the error handler (uncomment to test) |
|
|
|
|
// trigger_error("This is a test warning", E_USER_WARNING); |
|
|
|
|
// throw new Exception("This is a test exception"); |
|
|
|
|
|