From 7a70b7093155f3e709d218a79cba3aae7db71edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Tue, 23 May 2023 19:48:40 +0200 Subject: [PATCH] Version 2.0.0 --- changelog.md | 10 ++ composer.json | 13 +- config/exception-handler.php | 2 +- phpcs.xml | 171 +++++++++++++++--------- readme.md | 9 +- src/Console/Commands/InstallHandler.php | 9 +- src/Console/Commands/RemoveHandler.php | 7 +- src/ExceptionHandlerServiceProvider.php | 1 - src/Exceptions/ExceptionHandler.php | 131 +++++++++--------- src/Exceptions/NoContactException.php | 7 + 10 files changed, 206 insertions(+), 154 deletions(-) create mode 100644 src/Exceptions/NoContactException.php diff --git a/changelog.md b/changelog.md index f70d532..33ca04d 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,16 @@ All notable changes to `ExceptionHandler` will be documented in this file. +# version 2.0.0 +- Changed enhance getAnonymizedMessage (for DB queries) +- Changed Support only for laravel 10 +- Added env element EXCEPTION_MAIL_LIST + +# version 0.1.1 +- Changed better parsing for email recipients +- Changed if no recipients are available, a warning will be emitted, also native Laravel report method will be called instead. +- Changed if mail report fails, native reporting method will be called. + # version 0.1.0 - Add a a method to manually send exception by email (plus the same to call statically). diff --git a/composer.json b/composer.json index 55ee28e..56a4960 100644 --- a/composer.json +++ b/composer.json @@ -17,13 +17,11 @@ "Policies" ], "require": { - "illuminate/support": "~7|~8|~9", - "laravel/framework": "~7|~8|~9" + "illuminate/support": "~10", + "laravel/framework": "~10" }, "require-dev": { - "phpunit/phpunit": "~9.0", - "squizlabs/php_codesniffer": "^3.5", - "orchestra/testbench": "^6.13" + "slevomat/coding-standard": "^8.10" }, "autoload": { "psr-4": { @@ -41,5 +39,10 @@ "Kwaadpepper\\ExceptionHandler\\ExceptionHandlerServiceProvider" ] } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/config/exception-handler.php b/config/exception-handler.php index 83ec149..44a67cd 100644 --- a/config/exception-handler.php +++ b/config/exception-handler.php @@ -11,5 +11,5 @@ return [ * Put a developper secured mailbox in here * so you can receive email if things go mad */ - 'contactsList' => [] + 'contactsList' => collect(explode(',', env('EXCEPTION_MAIL_LIST')))->all(), ]; diff --git a/phpcs.xml b/phpcs.xml index cb0efd6..6f3f290 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,74 +1,86 @@ - - - + + Created with the PHP Coding Standard Generator. http://edorian.github.com/php-coding-standard-generator/ + + src/ - tests/ - Created with the PHP Coding Standard Generator. http://edorian.github.com/php-coding-standard-generator/ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - - - + + + + + + + + + + + + - + @@ -76,12 +88,39 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */database/migrations/* + diff --git a/readme.md b/readme.md index 75de319..179e30d 100644 --- a/readme.md +++ b/readme.md @@ -17,15 +17,18 @@ $ composer require kwaadpepper/exception-handler ## Usage - `php artisan handler:install` - - `php artisan vendor:publish --provider "Kwaadpepper\\ExceptionHandler\\ExceptionHandlerServiceProvider" --tag config` - - Change configuration in `config/exception-handler.php` - - put at least your team email in the above file in `contactsList` array + - Change configuration in `config/exception-handler.php` if needed. + - Put at least your team email in the above file in `contactsList` array or using `.env` put a list in `EXCEPTION_MAIL_LIST`. You can add emails separated with `,` like `admin1@email.com,admin2@email.com` You can uninstall it by using `php artisan handler:remove` or just revert changes in Exception/Handler.php ## Change log Please see the [changelog](changelog.md) for more information on what has changed recently. +# Todo + +- Add other transmission possibilities (other than mail) + ## Security If you discover any security related issues, please email `github@jeremydev.ovh` instead of using the issue tracker. diff --git a/src/Console/Commands/InstallHandler.php b/src/Console/Commands/InstallHandler.php index 104632b..d5d1d47 100644 --- a/src/Console/Commands/InstallHandler.php +++ b/src/Console/Commands/InstallHandler.php @@ -7,7 +7,6 @@ use Illuminate\Support\Facades\File; class InstallHandler extends Command { - /** * The name and signature of the console command. * @@ -35,8 +34,8 @@ class InstallHandler extends Command exit; } $handlerFile = File::get($handlerPath); - $find = 'use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;'; - $replace = 'use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;'; + $find = 'use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;'; + $replace = 'use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;'; if (\strpos($handlerFile, $replace) !== false) { $this->error('Exception handler seems to already be installed'); exit; @@ -49,8 +48,8 @@ class InstallHandler extends Command File::put($handlerPath, $handlerFile); $this->info("Replaced $handlerPath"); - $source = __DIR__ . '/../../../config/exception-handler.php'; - $dest = \config_path('exception-handler.php'); + $source = __DIR__ . '/../../../config/exception-handler.php'; + $dest = \config_path('exception-handler.php'); $destExist = File::exists($dest); if ( !$destExist or diff --git a/src/Console/Commands/RemoveHandler.php b/src/Console/Commands/RemoveHandler.php index 8459816..5aacf0e 100644 --- a/src/Console/Commands/RemoveHandler.php +++ b/src/Console/Commands/RemoveHandler.php @@ -7,7 +7,6 @@ use Illuminate\Support\Facades\File; class RemoveHandler extends Command { - /** * The name and signature of the console command. * @@ -35,8 +34,8 @@ class RemoveHandler extends Command exit; } $handlerFile = File::get($handlerPath); - $find = 'use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;'; - $replace = 'use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;'; + $find = 'use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;'; + $replace = 'use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;'; if (\strpos($handlerFile, $replace) !== false) { $this->error('Exception handler seems to already be removed'); exit; @@ -48,7 +47,7 @@ class RemoveHandler extends Command $handlerFile = \str_replace($find, $replace, $handlerFile); File::put($handlerPath, $handlerFile); - $source = \config_path('exception-handler.php'); + $source = \config_path('exception-handler.php'); $sourceExist = File::exists($source); if ( $sourceExist and diff --git a/src/ExceptionHandlerServiceProvider.php b/src/ExceptionHandlerServiceProvider.php index b84bac4..5069312 100644 --- a/src/ExceptionHandlerServiceProvider.php +++ b/src/ExceptionHandlerServiceProvider.php @@ -6,7 +6,6 @@ use Illuminate\Support\ServiceProvider; class ExceptionHandlerServiceProvider extends ServiceProvider { - protected $commands = [ 'Kwaadpepper\ExceptionHandler\Console\Commands\InstallHandler', 'Kwaadpepper\ExceptionHandler\Console\Commands\RemoveHandler' diff --git a/src/Exceptions/ExceptionHandler.php b/src/Exceptions/ExceptionHandler.php index 733e506..ea63941 100644 --- a/src/Exceptions/ExceptionHandler.php +++ b/src/Exceptions/ExceptionHandler.php @@ -9,44 +9,29 @@ use Illuminate\Support\Facades\Mail; class ExceptionHandler extends Handler { - /** * Create a new exception handler instance. * - * @param \Illuminate\Contracts\Container\Container $container + * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function __construct(Container $container) { parent::__construct($container); - if ( - \strpos(app()->version(), '8') === 0 or - \strpos(app()->version(), '9') === 0 - ) { - $this->reportable($this->reportExceptionByEmail()); - } + $this->reportable($this->reportExceptionByEmail()); } /** * Report or log an exception. * - * @param \Throwable $exception + * @param \Throwable $e * @return void - * - * @throws \Exception */ public function report(\Throwable $e) { if (get_class($e) == RedirectTo::class) { abort(redirect($e->url)); } - // ? If in laravel 7 and and error occurs when sending mail. - if ( - \strpos(app()->version(), '7') === 0 and - !$this->reportExceptionByEmail()($e) - ) { - return false; - } parent::report($e); } @@ -80,47 +65,52 @@ class ExceptionHandler extends Handler private function reportExceptionByEmail(): \Closure { return function (\Throwable $e) { - $dest = config('exception-handler.contactsList', config('mail.from.address')); - try { - if ($dest and config('exception-handler.enableMaiLog')) { - if ($this->shouldntReport($e)) { - return false; - } - Mail::send([ - 'html' => 'exception-handler::emails.exception', - 'text' => 'exception-handler::emails.exception-plain' - ], [ - 'appName' => config('app.name'), - 'code' => $e->getCode(), - 'line' => $e->getLine(), - 'ename' => \get_class($e), - 'emessage' => $this->getAnonymizedMessage($e->getMessage()), - 'file' => str_replace(\realpath(\sprintf('%s/../', \app_path())), '', $e->getFile()), - 'stackTrace' => $this->getAnonymizedStackTrace($e), - 'uri' => app()->runningInConsole() ? - 'CONSOLE' : ( - (request() and request()->fullUrl()) ? - request()->fullUrl() : 'none') - ], function ($m) use ($dest) { - // ? Is laravel 9 (https://laravel.com/docs/master/upgrade#symfony-mailer) - if(\strpos(app()->version(), '9') !== 0) { - /** @var \Illuminate\Mail\Message $m */ - $m->setTo( - $dest, - sprintf('%s Exception Handler', config('app.name')) - )->setSubject('Need help !, an error occured in your application, please check Logs ASAP'); - } else { - /** @var \Illuminate\Mail\Message $m */ - $m->to( - $dest, - sprintf('%s Exception Handler', config('app.name')) - )->subject('Need help !, an error occured in your application, please check Logs ASAP'); - } - }); - } - } catch (\Error $e) { - Log::critical('Handler could not send Exception email', ['exception' => $e]); + if ($this->shouldntReport($e)) { + return false; } + // * Ignore NoContactException. + if ($e instanceof NoContactException) { + Log::critical($e->getMessage()); + return false; + } + $dest = \collect(config('exception-handler.contactsList', config('mail.from.address')))->filter(); + try { + if (!config('exception-handler.enableMaiLog')) { + return false; + } + if (!$dest->count()) { + throw new NoContactException( + 'No contact in `EXCEPTION_MAIL_LIST` nor `exception-handler.contactsList` config', + 0, + $e + ); + } + Mail::send([ + 'html' => 'exception-handler::emails.exception', + 'text' => 'exception-handler::emails.exception-plain' + ], [ + 'appName' => config('app.name'), + 'code' => $e->getCode(), + 'line' => $e->getLine(), + 'ename' => \get_class($e), + 'emessage' => self::getAnonymizedMessage($e->getMessage()), + 'file' => str_replace(\realpath(\sprintf('%s/../', \app_path())), '', $e->getFile()), + 'stackTrace' => self::getAnonymizedStackTrace($e), + 'uri' => app()->runningInConsole() ? + 'CONSOLE' : ( + (request() and request()->fullUrl()) ? + request()->fullUrl() : 'none') + ], function ($m) use ($dest) { + /** @var \Illuminate\Mail\Message $m */ + $m->to( + $dest->all(), + sprintf('%s Exception Handler', config('app.name')) + )->subject('Need help !, an error occured in your application, please check Logs ASAP'); + }); + } catch (\Error $reportE) { + parent::report($e); + Log::critical('Handler could not send Exception email', ['exception' => $reportE]); + }//end try }; } @@ -130,27 +120,30 @@ class ExceptionHandler extends Handler * @param string $message * @return string */ - private function getAnonymizedMessage(string $message): string + private static function getAnonymizedMessage(string $message): string { $message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message; + if ($sqlPos = \strpos($message, 'to use near')) { + $message = \mb_strcut($message, 0, $sqlPos); + } return $message; } /** * Anonymize stack trace * - * @param \Exception $e + * @param \Throwable $e * @return string */ - private function getAnonymizedStackTrace(\Throwable $e): string + private static function getAnonymizedStackTrace(\Throwable $e): string { - $projectPath = \realpath(\sprintf('%s/../', \app_path())); - $traceStack = $e->getTrace(); - $traceStr = ''; + $projectPath = \realpath(\sprintf('%s/../', \app_path())); + $traceStack = $e->getTrace(); + $traceStr = ''; $maxStackStage = 0; foreach ($traceStack as $stackStage => $stack) { $maxStackStage = $stackStage; - $traceStr .= \sprintf( + $traceStr .= \sprintf( '#%s %s(%d): ', $stackStage, str_replace($projectPath, '', $stack['file'] ?? ''), @@ -159,17 +152,17 @@ class ExceptionHandler extends Handler if (isset($stack['class'])) { $traceStr .= "{$stack['class']}->{$stack['function']}("; if (isset($stack['args'])) { - $traceStr .= $this->handleArgs($stack); + $traceStr .= self::handleArgs($stack); } $traceStr .= ")\n"; } elseif (isset($stack['function'])) { $traceStr .= "{$stack['function']}("; if (isset($stack['args'])) { - $traceStr .= $this->handleArgs($stack); + $traceStr .= self::handleArgs($stack); } $traceStr .= ")\n"; } - } + } //end foreach $maxStackStage++; $traceStr .= "#$maxStackStage {main}"; return $traceStr; @@ -181,7 +174,7 @@ class ExceptionHandler extends Handler * @param array $stack * @return string */ - private function handleArgs(array $stack): string + private static function handleArgs(array $stack): string { $traceArgs = ''; $argsCount = count($stack['args']); diff --git a/src/Exceptions/NoContactException.php b/src/Exceptions/NoContactException.php new file mode 100644 index 0000000..ba7dd95 --- /dev/null +++ b/src/Exceptions/NoContactException.php @@ -0,0 +1,7 @@ +