Version 2.0.0

This commit is contained in:
Jérémy Munsch 2023-05-23 19:48:40 +02:00
parent 40e172d5d1
commit 7a70b70931
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
10 changed files with 206 additions and 154 deletions

View file

@ -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).

View file

@ -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
}
}
}

View file

@ -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(),
];

View file

@ -1,11 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="RealWorld" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<ruleset name="LDC Laravel"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<description>Created with the PHP Coding Standard Generator. http://edorian.github.com/php-coding-standard-generator/</description>
<arg name="colors" />
<arg name="extensions" value="php" />
<file>src/</file>
<file>tests/</file>
<description>Created with the PHP Coding Standard Generator. http://edorian.github.com/php-coding-standard-generator/
</description>
<rule ref="PSR1" />
<rule ref="PSR12" />
<rule ref="Generic.Classes.DuplicateClassName"/>
<rule ref="Generic.CodeAnalysis.EmptyStatement"/>
<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop"/>
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
@ -14,18 +17,15 @@
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<rule ref="Generic.Commenting.DocComment.SpacingBeforeTags"/>
<rule ref="Generic.Commenting.Todo"/>
<rule ref="Generic.Commenting.Fixme"/>
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
<rule ref="Generic.Files.ByteOrderMark"/>
<rule ref="Generic.Files.LineEndings"/>
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="120"/>
<property name="absoluteLineLimit" value="0"/>
</properties>
</rule>
<rule ref="Generic.Files.LineLength"/>
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<rule ref="Generic.Formatting.MultipleStatementAlignment"/>
<rule ref="Generic.Formatting.NoSpaceAfterCast"/>
<rule ref="Generic.Functions.CallTimePassByReference"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
@ -37,7 +37,6 @@
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.PHP.ForbiddenFunctions"/>
<rule ref="Generic.PHP.LowerCaseConstant" />
<rule ref="Generic.PHP.NoSilencedErrors"/>
<rule ref="Generic.Strings.UnnecessaryStringConcat"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
@ -49,8 +48,20 @@
<rule ref="PEAR.Commenting.InlineComment"/>
<rule ref="PSR1.Classes.ClassDeclaration"/>
<rule ref="PSR1.Files.SideEffects"/>
<rule ref="PSR2.Classes.ClassDeclaration"/>
<rule ref="PSR2.Classes.PropertyDeclaration"/>
<rule ref="PSR2.ControlStructures.ElseIfDeclaration"/>
<rule ref="PSR2.ControlStructures.SwitchDeclaration"/>
<rule ref="PSR2.Files.EndFileNewline"/>
<rule ref="PSR2.Methods.MethodDeclaration"/>
<rule ref="PSR2.Namespaces.NamespaceDeclaration"/>
<rule ref="PSR2.Namespaces.UseDeclaration"/>
<rule ref="Squiz.PHP.CommentedOutCode"/>
<rule ref="Squiz.PHP.DisallowMultipleAssignments">
<exclude name="Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure" />
</rule>
<rule ref="Squiz.PHP.DisallowSizeFunctionsInLoops"/>
<rule ref="Squiz.PHP.DiscouragedFunctions">
<properties>
<property name="error" value="true"/>
@ -65,10 +76,11 @@
<rule ref="Squiz.Scope.MemberVarScope"/>
<rule ref="Squiz.Scope.MethodScope"/>
<rule ref="Squiz.Scope.StaticThisUsage"/>
<rule ref="Squiz.WhiteSpace.MemberVarSpacing" />
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
<property name="spacingBeforeFirst " value="false"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
@ -76,12 +88,39 @@
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<rule ref="Squiz.Commenting.BlockComment">
<exclude name="Squiz.Commenting.BlockComment.WrongStart" />
</rule>
<rule ref="Squiz.Commenting.ClassComment">
<exclude name="Squiz.Commenting.ClassComment.Missing" />
<exclude name="Squiz.Commenting.ClassComment.TagNotAllowed" />
</rule>
<rule ref="Squiz.Commenting.DocCommentAlignment"/>
<rule ref="Squiz.Commenting.EmptyCatchComment"/>
<rule ref="Squiz.Commenting.FunctionComment">
<exclude name="Squiz.Commenting.FunctionComment.MissingParamComment" />
</rule>
<rule ref="Squiz.Commenting.FunctionCommentThrowTag"/>
<rule ref="Squiz.Commenting.InlineComment">
<exclude name="Squiz.Commenting.InlineComment.DocBlock" />
</rule>
<rule ref="Squiz.Commenting.LongConditionClosingComment">
<exclude name="Squiz.Commenting.LongConditionClosingComment.SpacingBefore" />
</rule>
<rule ref="Squiz.Commenting.PostStatementComment"/>
<rule ref="Squiz.Commenting.VariableComment"/>
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse" />
<!-- For Laravel migrations -->
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
<exclude-pattern>*/database/migrations/*</exclude-pattern>
</rule>
</ruleset>

View file

@ -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.

View file

@ -7,7 +7,6 @@ use Illuminate\Support\Facades\File;
class InstallHandler extends Command
{
/**
* The name and signature of the console command.
*

View file

@ -7,7 +7,6 @@ use Illuminate\Support\Facades\File;
class RemoveHandler extends Command
{
/**
* The name and signature of the console command.
*

View file

@ -6,7 +6,6 @@ use Illuminate\Support\ServiceProvider;
class ExceptionHandlerServiceProvider extends ServiceProvider
{
protected $commands = [
'Kwaadpepper\ExceptionHandler\Console\Commands\InstallHandler',
'Kwaadpepper\ExceptionHandler\Console\Commands\RemoveHandler'

View file

@ -9,7 +9,6 @@ use Illuminate\Support\Facades\Mail;
class ExceptionHandler extends Handler
{
/**
* Create a new exception handler instance.
*
@ -19,34 +18,20 @@ class ExceptionHandler extends Handler
public function __construct(Container $container)
{
parent::__construct($container);
if (
\strpos(app()->version(), '8') === 0 or
\strpos(app()->version(), '9') === 0
) {
$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,12 +65,26 @@ 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;
}
// * 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'
@ -94,33 +93,24 @@ class ExceptionHandler extends Handler
'code' => $e->getCode(),
'line' => $e->getLine(),
'ename' => \get_class($e),
'emessage' => $this->getAnonymizedMessage($e->getMessage()),
'emessage' => self::getAnonymizedMessage($e->getMessage()),
'file' => str_replace(\realpath(\sprintf('%s/../', \app_path())), '', $e->getFile()),
'stackTrace' => $this->getAnonymizedStackTrace($e),
'stackTrace' => self::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,
$dest->all(),
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]);
}
} catch (\Error $reportE) {
parent::report($e);
Log::critical('Handler could not send Exception email', ['exception' => $reportE]);
}//end try
};
}
@ -130,19 +120,22 @@ 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();
@ -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']);

View file

@ -0,0 +1,7 @@
<?php
namespace Kwaadpepper\ExceptionHandler\Exceptions;
class NoContactException extends \RuntimeException
{
}