From cd22f8def50ede21e2a8b333664cf332aa130c63 Mon Sep 17 00:00:00 2001
From: slawkens <slawkens@gmail.com>
Date: Fri, 2 Jun 2023 15:20:07 +0200
Subject: [PATCH] Use Whoops only if installed, otherwise use myaac exception
 handler

---
 composer.json                        |  4 +-
 system/exception.php                 | 66 ++++++++++++++++++++---
 system/libs/SensitiveException.php   |  3 ++
 system/templates/exception.html.twig | 79 ++++++++++++++++++++++++++++
 4 files changed, 143 insertions(+), 9 deletions(-)
 create mode 100644 system/libs/SensitiveException.php
 create mode 100644 system/templates/exception.html.twig

diff --git a/composer.json b/composer.json
index 0a17947e..b1300e34 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,9 @@
         "twig/twig": "^2.0",
         "erusev/parsedown": "^1.7",
         "nikic/fast-route": "^1.3",
-        "matomo/device-detector": "^6.0",
+        "matomo/device-detector": "^6.0"
+    },
+    "require-dev": {
         "filp/whoops": "^2.15"
     }
 }
diff --git a/system/exception.php b/system/exception.php
index 9a233000..077d0f3f 100644
--- a/system/exception.php
+++ b/system/exception.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Whoops exception handler
+ * Exception handler
  *
  * @package   MyAAC
  * @author    Slawkens <slawkens@gmail.com>
@@ -8,13 +8,63 @@
  * @link      https://my-aac.org
  */
 
-$whoops = new \Whoops\Run;
+if (class_exists(\Whoops\Run::class)) {
+	$whoops = new \Whoops\Run;
+	if(IS_CLI) {
+		$whoops->pushHandler(new \Whoops\Handler\PlainTextHandler);
+	}
+	else {
+		$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
+	}
 
-if(IS_CLI) {
-	$whoops->pushHandler(new \Whoops\Handler\PlainTextHandler);
-}
-else {
-	$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
+	$whoops->register();
+	return;
 }
 
-$whoops->register();
+require LIBS . 'SensitiveException.php';
+
+/**
+ * @param Exception $exception
+ */
+function exception_handler($exception) {
+	$message = $exception->getMessage();
+	if($exception instanceof SensitiveException) {
+		$message = 'This error is sensitive and has been logged into ' . LOGS . 'error.log.<br/>View this file for more information.';
+
+		// log error to file
+		$f = fopen(LOGS . 'error.log', 'ab');
+		if(!$f) {
+			$message = 'We wanted to save detailed informations about this error, but file: ' . LOGS . "error.log couldn't be opened for writing.. so the detailed information couldn't be saved.. are you sure directory system/logs is writable by web server? Correct this, and then refresh this site.";
+		}
+		else {
+			fwrite($f, '[' . date(DateTime::RFC1123) . '] ' . $exception->getMessage() . PHP_EOL);
+			fclose($f);
+		}
+	}
+
+	$backtrace_formatted = nl2br($exception->getTraceAsString());
+
+	$message = $message . "<br/><br/>File: {$exception->getFile()}<br/>Line: {$exception->getLine()}";
+
+	// display basic error message without template
+	// template is missing, why? probably someone deleted templates dir, or it wasn't downloaded right
+	$template_file = SYSTEM . 'templates/exception.html.twig';
+	if(!file_exists($template_file)) {
+		echo 'Something went terribly wrong..<br/><br/>';
+		echo "$message<br/><br/>";
+		echo 'Backtrace:<br>';
+		echo $backtrace_formatted;
+		return;
+	}
+
+	// display beautiful error message
+	// the file is .twig.html, but its not really parsed by Twig
+	// we just replace some values manually
+	// cause in case Twig throws exception, we can show it too
+	$content = file_get_contents($template_file);
+	$content = str_replace(array('{{ BASE_URL }}', '{{ exceptionClass }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, get_class($exception), $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content);
+
+	echo $content;
+}
+
+set_exception_handler('exception_handler');
diff --git a/system/libs/SensitiveException.php b/system/libs/SensitiveException.php
new file mode 100644
index 00000000..58978198
--- /dev/null
+++ b/system/libs/SensitiveException.php
@@ -0,0 +1,3 @@
+<?php
+
+class SensitiveException extends Exception {}
diff --git a/system/templates/exception.html.twig b/system/templates/exception.html.twig
new file mode 100644
index 00000000..7a31b4bb
--- /dev/null
+++ b/system/templates/exception.html.twig
@@ -0,0 +1,79 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+	<meta charset="utf-8">
+
+	<title>Something went wrong...</title>
+	<meta name="description" content="myaac">
+	<meta name="generator" content="MyAAC">
+
+	<link rel="stylesheet" href="tools/css/messages.css">
+	<link rel="shortcut icon" href="images/error.ico">
+	<base href="{{ BASE_URL }}" />
+
+	<style>
+		body{
+			background-color: #e3e7ed;
+			font-family: Verdana, Geneva, sans-serif;
+		}
+		.center {
+			height: 500px;
+			position: absolute;
+			top:0;
+			bottom: 0;
+			left: 0;
+			right: 0;
+
+			margin: auto;
+		}
+
+		.wide{
+			min-width: 350px;
+			max-width: 350px;
+		}
+
+		.big{
+			font-size: 20px!important;
+		}
+
+		#footer {
+			position: absolute;
+			bottom: 15px;
+			width: 100%;
+
+			border-top: 1px solid #eee;
+			text-align: center;
+			color: #555;
+		}
+
+		#footer p {
+			text-align: center;
+		}
+
+		.error {
+			font-weight: normal;
+			font-size: 12px;
+		}
+	</style>
+	<!--[if lt IE 9]>
+	<script src="tools/js/html5shiv.min.js"></script>
+	<![endif]-->
+</head>
+<body>
+	<div class="center wide">
+		<h2 class="wide">Whoops something went wrong...</h2>
+		<div class="error wide">
+			Exception class: {{ exceptionClass }}()
+			<br/><br/>
+			{{ message }}
+			<br/><br/><br/>
+			<b>Backtrace:</b><br/><br/>
+			{{ backtrace }}
+		</div>
+	</div>
+	<div id="footer">
+		<p>{{ powered_by }}</p>
+	</div>
+</body>
+</html>