{$text}
+diff --git a/misuzu.php b/misuzu.php index 2f0a10c2..3de78cf1 100644 --- a/misuzu.php +++ b/misuzu.php @@ -4,20 +4,25 @@ namespace Misuzu; define('MSZ_STARTUP', microtime(true)); define('MSZ_DEBUG', file_exists(__DIR__ . '/.debug')); +error_reporting(MSZ_DEBUG ? -1 : 0); +ini_set('display_errors', MSZ_DEBUG ? 'On' : 'Off'); + date_default_timezone_set('UTC'); mb_internal_encoding('UTF-8'); require_once __DIR__ . '/vendor/autoload.php'; -if (MSZ_DEBUG) { - $errorHandler = new \Whoops\Run; - $errorHandler->pushHandler( +$errorHandler = new \Whoops\Run; +$errorHandler->pushHandler( + MSZ_DEBUG + ? ( PHP_SAPI === 'cli' ? new \Whoops\Handler\PlainTextHandler : new \Whoops\Handler\PrettyPageHandler - ); - $errorHandler->register(); -} + ) + : ($errorReporter = new WhoopsReporter) +); +$errorHandler->register(); require_once __DIR__ . '/src/audit_log.php'; require_once __DIR__ . '/src/changelog.php'; @@ -43,6 +48,11 @@ require_once __DIR__ . '/src/Users/user.php'; require_once __DIR__ . '/src/Users/validation.php'; $app = new Application(__DIR__ . '/config/config.ini'); + +if (!empty($errorReporter)) { + $errorReporter->setReportInfo(...$app->getReportInfo()); +} + $app->startDatabase(); if (PHP_SAPI === 'cli') { diff --git a/src/Application.php b/src/Application.php index 7f18d173..3120971c 100644 --- a/src/Application.php +++ b/src/Application.php @@ -67,15 +67,14 @@ final class Application if ($this->config === false) { throw new UnexpectedValueException('Failed to parse configuration.'); } + } - // only use this error handler in prod mode, dev uses Whoops now - if (!MSZ_DEBUG) { - ExceptionHandler::register( - false, - $this->config['Exceptions']['report_url'] ?? null, - $this->config['Exceptions']['hash_key'] ?? null - ); - } + public function getReportInfo(): array + { + return [ + $this->config['Exceptions']['report_url'] ?? null, + $this->config['Exceptions']['hash_key'] ?? null, + ]; } /** diff --git a/src/ExceptionHandler.php b/src/ExceptionHandler.php deleted file mode 100644 index f08c46b1..00000000 --- a/src/ExceptionHandler.php +++ /dev/null @@ -1,163 +0,0 @@ - - */ -class ExceptionHandler -{ - /** - * Url to which report objects will be POSTed. - * @var string - */ - private static $reportUrl = null; - - /** - * HMAC key that will be used to sign the request. - * @var string - */ - private static $reportSign = null; - - /** - * Whether debug mode is active. - * If true (or in CLI) a backtrace will be displayed. - * If false a user friendly, non-exposing error page will be displayed. - * @var bool - */ - private static $debugMode = false; - - /** - * Registers the exception handler and make it so all errors are thrown as ErrorExceptions. - * @param bool $debugMode - * @param string|null $reportUrl - * @param string|null $reportSign - */ - public static function register(bool $debugMode, ?string $reportUrl = null, ?string $reportSign = null): void - { - self::$debugMode = $debugMode; - self::$reportUrl = $reportUrl; - self::$reportSign = $reportSign; - set_exception_handler([self::class, 'exception']); - set_error_handler([self::class, 'error']); - } - - /** - * Same as above except unregisters - */ - public static function unregister(): void - { - restore_exception_handler(); - restore_error_handler(); - } - - /** - * The actual handler for rendering and reporting exceptions. - * Checks if the exception is extends on HttpException, - * if not an attempt will be done to report it. - * @param Throwable $exception - */ - public static function exception(Throwable $exception): void - { - $report = !self::$debugMode && self::$reportUrl !== null; - - if ($report) { - self::report($exception); - } - - self::render($exception, $report); - } - - /** - * Converts regular errors to ErrorException instances. - * @param int $severity - * @param string $message - * @param string $file - * @param int $line - * @throws ErrorException - */ - public static function error(int $severity, string $message, string $file, int $line): void - { - throw new ErrorException($message, 0, $severity, $file, $line); - } - - /** - * Shoots a POST request to the report URL. - * @todo Implement this. - * @param Throwable $throwable - */ - private static function report(Throwable $throwable): bool - { - if (!mb_strlen(self::$reportUrl)) { - return false; - } - - if (!($curl = curl_init(self::$reportUrl))) { - return false; - } - - $json = json_encode([ - 'git' => [ - 'branch' => git_branch(), - 'hash' => git_commit_hash(true), - ], - 'exception' => [ - 'type' => get_class($throwable), - 'message' => $throwable->getMessage(), - 'code' => $throwable->getCode(), - 'file' => str_replace(dirname(__DIR__, 1), '', $throwable->getFile()), - 'line' => $throwable->getLine(), - 'trace' => $throwable->getTraceAsString(), - ], - ]); - - $headers = [ - 'Content-Type: application/json;charset=utf-8', - ]; - - if (mb_strlen(self::$reportSign)) { - $headers[] = 'X-Misuzu-Signature: sha256=' . hash_hmac('sha256', $json, self::$reportSign); - } - - $setOpts = curl_setopt_array($curl, [ - CURLOPT_TCP_NODELAY => true, - CURLOPT_POSTFIELDS => $json, - CURLOPT_HTTPHEADER => $headers, - ]); - - if (!$setOpts) { - return false; - } - - return curl_exec($curl) !== false; - } - - /** - * Renders exceptions. - * In debug or cli mode a backtrace is displayed. - * @param Throwable $exception - * @param bool $reported - */ - private static function render(Throwable $exception, bool $reported): void - { - if (PHP_SAPI !== 'cli' && !headers_sent()) { - ob_clean(); - http_response_code(500); - header('Content-Type: text/plain'); - } - - if (PHP_SAPI === 'cli' || self::$debugMode) { - echo $exception; - } else { - echo 'Something broke!'; - - if ($reported) { - echo PHP_EOL . 'Information about this error has been sent to the devs.'; - } - } - } -} diff --git a/src/WhoopsReporter.php b/src/WhoopsReporter.php new file mode 100644 index 00000000..6bb9ffb8 --- /dev/null +++ b/src/WhoopsReporter.php @@ -0,0 +1,106 @@ +setReportInfo($reportUrl, $reportSign); + } + + public function setReportInfo(?string $reportUrl = null, ?string $reportSign = null): void + { + $this->reportUrl = $reportUrl; + $this->reportSign = $reportSign; + } + + public function handle() + { + echo $this->html( + $this->report() + ? 'Information about this error has been sent to the devs.' + : 'Report what you were trying to a developer.' + ); + + return Handler::QUIT; + } + + public function contentType(): string + { + return 'text/html'; + } + + public function html(string $text): string + { + return << + +
+ +{$text}
+