From f3ff6ad6c20a1fb260073a783dfcee443b4344c4 Mon Sep 17 00:00:00 2001 From: flashwave Date: Fri, 5 Aug 2016 21:13:55 +0200 Subject: [PATCH] Fixed the exception system up. --- app/ExceptionHandler.php | 108 +++++++++++++++++ app/Net.php | 33 +++-- app/Router.php | 5 +- app/Template.php | 9 ++ config/config.example.ini | 3 + resources/views/yuuno/errors/403.twig | 1 + resources/views/yuuno/errors/404.twig | 47 ++++++++ resources/views/yuuno/errors/500.twig | 35 ++++++ .../maintenance.twig => errors/503.twig} | 0 resources/views/yuuno/global/notfound.twig | 47 -------- sakura.php | 10 +- utility.php | 113 ------------------ 12 files changed, 233 insertions(+), 178 deletions(-) create mode 100644 app/ExceptionHandler.php create mode 100644 resources/views/yuuno/errors/403.twig create mode 100644 resources/views/yuuno/errors/404.twig create mode 100644 resources/views/yuuno/errors/500.twig rename resources/views/yuuno/{global/maintenance.twig => errors/503.twig} (100%) delete mode 100644 resources/views/yuuno/global/notfound.twig diff --git a/app/ExceptionHandler.php b/app/ExceptionHandler.php new file mode 100644 index 0000000..66d89f2 --- /dev/null +++ b/app/ExceptionHandler.php @@ -0,0 +1,108 @@ + + */ +class ExceptionHandler +{ + /** + * Disables checking if the templating engine is available + * @var bool + */ + private static $disableTemplate = false; + + /** + * The entry point for set_exception_handler. + * @param Throwable $ex + */ + public static function exception(Throwable $ex) + { + try { + $report = config('dev.report_host'); + } catch (Exception $ex) { + $report = null; + } + + if ($report !== null) { + self::report($ex, $report); + } + + self::view($ex, $report !== null); + } + + /** + * The entry point for set_error_handler. + * @param int $severity + * @param string $message + * @param string $file + * @param int $line + */ + public static function error($severity, $message, $file, $line) + { + throw new ErrorException($message, 0, $severity, $file, $line); + } + + /** + * Display an error message. + * @param Throwable $ex + * @param bool $reported + */ + private static function view(Throwable $ex, $reported = false) + { + http_response_code(500); + + try { + $debug = config('dev.show_errorsa'); + } catch (Exception $ex) { + $debug = false; + } + + if ($debug) { + header('Content-Type: text/plain'); + echo $ex; + } else { + if (!self::$disableTemplate && Template::available()) { + echo view('errors/500', compact('reported')); + } else { + // Disable templates permanently so we don't get stuck in an infinite loop + // if an exception is caused by the templating engine. + self::$disableTemplate = true; + echo "Something broke so badly that the error page failed to render."; + + if ($reported) { + echo " The developers have been notified of the issue."; + } + } + } + } + + /** + * Posts the exception as json to a remote server. + * @param Throwable $ex + * @param string $destination + */ + private static function report(Throwable $ex, $destination) + { + $send = new stdClass; + $send->Date = date('c'); + $send->Message = $ex->getMessage(); + $send->Code = $ex->getCode(); + $send->File = $ex->getFile(); + $send->Line = $ex->getLine(); + $send->Trace = $ex->getTraceAsString(); + + Net::request($destination, 'POST', json_encode($send)); + } +} diff --git a/app/Net.php b/app/Net.php index 3d05caa..b22bf42 100644 --- a/app/Net.php +++ b/app/Net.php @@ -201,26 +201,35 @@ class Net } /** - * Fetch a remote file. + * Make a web request. * @param string $url - * @return mixed + * @param string $method + * @param mixed $params + * @return string */ - public static function fetch($url) + public static function request($url, $method = 'GET', $params = null) { - // Create a curl instance $curl = curl_init(); - // Set options - curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2); - curl_setopt($curl, CURLOPT_TIMEOUT, 4); - curl_setopt($curl, CURLOPT_USERAGENT, 'Sakura/' . SAKURA_VERSION); + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CONNECTTIMEOUT => 2, + CURLOPT_TIMEOUT => 4, + CURLOPT_USERAGENT => 'Sakura/' . SAKURA_VERSION, + ]); + + switch (strtolower($method)) { + case 'post': + curl_setopt_array($curl, [ + CURLOPT_POST => is_array($params) ? count($params) : 1, + CURLOPT_POSTFIELDS => is_array($params) ? http_build_query($params) : $params, + ]); + break; + } - // Execute $curl = curl_exec($curl); - // Return the data return $curl; } } diff --git a/app/Router.php b/app/Router.php index 1903b85..72a7372 100644 --- a/app/Router.php +++ b/app/Router.php @@ -172,11 +172,10 @@ class Router return self::$dispatcher->dispatch($method, $url); } catch (HttpMethodNotAllowedException $e) { http_response_code(403); + return view('errors/403'); } catch (HttpRouteNotFoundException $e) { http_response_code(404); + return view('errors/404'); } - - // Default to the not found page - return Template::render('global/notfound'); } } diff --git a/app/Template.php b/app/Template.php index 09a8e07..d8ce7e4 100644 --- a/app/Template.php +++ b/app/Template.php @@ -120,6 +120,15 @@ class Template } } + /** + * Checks if twig is available. + * @return bool + */ + public static function available() + { + return self::$engine !== null && self::$name !== null; + } + /** * Merge the parse variables. * @param array $vars diff --git a/config/config.example.ini b/config/config.example.ini index 9dbb697..5c40fb3 100644 --- a/config/config.example.ini +++ b/config/config.example.ini @@ -87,6 +87,9 @@ show_changelog = false ; Host for the mahou serve command host = localhost:8000 +; Host for dumping exceptions, sends the exception as a json object in a raw post request. Leave empty to disable. +report_host = + ; Mailing settings [mail] contact_address = sakura@localhost diff --git a/resources/views/yuuno/errors/403.twig b/resources/views/yuuno/errors/403.twig new file mode 100644 index 0000000..19d0844 --- /dev/null +++ b/resources/views/yuuno/errors/403.twig @@ -0,0 +1 @@ +{% include 'errors/404.twig' %} diff --git a/resources/views/yuuno/errors/404.twig b/resources/views/yuuno/errors/404.twig new file mode 100644 index 0000000..8a6557d --- /dev/null +++ b/resources/views/yuuno/errors/404.twig @@ -0,0 +1,47 @@ + + + + + Cannot find page + + + +
+

+ + The page cannot be found +

+

+ The page you are looking for might have been removed, had its + name changed, or is temporarily unavailable. +

+
+

+ Please try the following: +

+ +

+ HTTP 404 - File not found +
+ Internet Explorer +

+
+ + diff --git a/resources/views/yuuno/errors/500.twig b/resources/views/yuuno/errors/500.twig new file mode 100644 index 0000000..16c2043 --- /dev/null +++ b/resources/views/yuuno/errors/500.twig @@ -0,0 +1,35 @@ + + + + + Internal Server Error + + + +
+

+ + The page is currently unavailable +

+

+ The page you are looking for experienced a severe explosion. +

+ {% if reported %} +

+ The developers have been notified of this issue, sorry for the inconvenience! +

+ {% endif %} +
+ {% if message %} +

+ {{ message }} +

+ {% endif %} +

+ HTTP 500 - Internal Server Error +
+ Internet Explorer +

+
+ + diff --git a/resources/views/yuuno/global/maintenance.twig b/resources/views/yuuno/errors/503.twig similarity index 100% rename from resources/views/yuuno/global/maintenance.twig rename to resources/views/yuuno/errors/503.twig diff --git a/resources/views/yuuno/global/notfound.twig b/resources/views/yuuno/global/notfound.twig deleted file mode 100644 index faee1e6..0000000 --- a/resources/views/yuuno/global/notfound.twig +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Cannot find page - - - -
-

- - The page cannot be found -

-

- The page you are looking for might have been removed, had its - name changed, or is temporarily unavailable. -

-
-

- Please try the following: -

- -

- HTTP 404 - File not found -
- Internet Explorer -

-
- - diff --git a/sakura.php b/sakura.php index 54c1c1e..fa947fe 100644 --- a/sakura.php +++ b/sakura.php @@ -15,6 +15,9 @@ if (php_sapi_name() === 'cli') { define('IN_CLI', true); } +// Turn error reporting on regardless of anything +error_reporting(-1); + // Override expiration variables ignore_user_abort(true); set_time_limit(0); @@ -35,12 +38,13 @@ if (!file_exists(ROOT . 'vendor/autoload.php')) { // Include the autoloader require_once ROOT . 'vendor/autoload.php'; +// Register the handlers +set_exception_handler(['Sakura\ExceptionHandler', 'exception']); +set_error_handler(['Sakura\ExceptionHandler', 'error']); + // Load the configuration Config::init(ROOT . 'config/config.ini'); -set_error_handler('error_handler'); -error_reporting(config('dev.show_errors') ? -1 : 0); - // Start the database module $capsule = new DB; $capsule->addConnection(config('database')); diff --git a/utility.php b/utility.php index 5877903..557ecff 100644 --- a/utility.php +++ b/utility.php @@ -169,116 +169,3 @@ function send_mail($to, $subject, $body) return $mailer->send($message); } - -function error_handler($errno, $errstr, $errfile, $errline) -{ - // Remove ROOT path from the error string and file location - $errstr = str_replace(ROOT, '', $errstr); - $errfile = str_replace(ROOT, '', $errfile); - - switch ($errno) { - case E_ERROR: - case E_USER_ERROR: - $error = "FATAL ERROR"; - break; - - case E_WARNING: - case E_USER_WARNING: - $error = "WARNING"; - break; - - case E_NOTICE: - case E_USER_NOTICE: - $error = "NOTICE"; - break; - - default: - $error = "Unknown error type [{$errno}]"; - } - - $error .= ": {$errstr} on line {$errline} in {$errfile}"; - - // Truncate all previous outputs - ob_clean(); - ob_end_clean(); - - // Check for dev mode - $detailed = config('dev.show_errors'); - - // Build page (not even going to bother cleaning this one up) - $errorPage = ' - - - - Sakura Internal Error - - - -
-

An error occurred while executing the script.

-
-

To prevent potential security risks or data loss Sakura has stopped execution of the script.

'; - - if (isset($errid)) { - $errorPage .= '

The error and surrounding data has been logged.

-

' . (!$detailed ? 'Report the following text to a staff member' : 'Logged as') . '

-
' . $errid . '
'; - } else { - $errorPage .= '

Sakura was not able to log this error which could mean that there was an error - with the database connection. If you\'re the system administrator check the database credentials - and make sure the server is running and if you\'re not please let the system administrator - know about this error if it occurs again.

'; - } - - if ($detailed) { - $errorPage .= '

Summary

-
' . $error . '
-

Backtraces

'; - - foreach (debug_backtrace() as $num => $trace) { - $errorPage .= '

#' . $num . '

';
-
-            foreach ($trace as $key => $val) {
-                $errorPage .=
-                str_pad(
-                    '[' . $key . ']',
-                    12
-                ) . '=> ' . (
-                    is_array($val) || is_object($val) ?
-                    json_encode($val) :
-                    $val
-                ) . "\r\n";
-            }
-
-            $errorPage .= '
'; - } - } - - $errorPage .= '
- -
- -'; - - // Die and display error message - die($errorPage); -}