From 922d26d3acea23913e551a08634ae82ef255cd84 Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Tue, 16 Aug 2022 11:08:05 +0200 Subject: [PATCH] catch all possible exceptions and errors --- Application/Models/DebugBarHandler.php | 90 ++++++++++++++ Core/DebugBarErrorHandler.php | 99 ++++++++++++++++ Core/DebugBarExceptionHandler.php | 53 ++++----- Modules/Core/ShopControl_DebugBar.php | 158 ++++++++----------------- 4 files changed, 263 insertions(+), 137 deletions(-) create mode 100644 Application/Models/DebugBarHandler.php create mode 100644 Core/DebugBarErrorHandler.php diff --git a/Application/Models/DebugBarHandler.php b/Application/Models/DebugBarHandler.php new file mode 100644 index 0000000..3a1ee7c --- /dev/null +++ b/Application/Models/DebugBarHandler.php @@ -0,0 +1,90 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\DebugBar\Application\Models; + +use D3\DebugBar\Application\Component\DebugBarComponent; +use D3\DebugBar\Core\DebugBarErrorHandler; +use D3\DebugBar\Core\DebugBarExceptionHandler; +use OxidEsales\Eshop\Core\Registry; + +class DebugBarHandler +{ + /** + * @return void + */ + public function setErrorHandler(): void + { + if ($this->d3CanActivateDebugBar()) { + set_error_handler( + [ + new DebugBarErrorHandler(), + 'callback' + ], + $this->getHandledErrorTypes() + ); + } + } + + /** + * @return int + */ + protected function getHandledErrorTypes(): int + { + return E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_PARSE; + } + + /** + * @return void + */ + public function setExceptionHandler(): void + { + if ($this->d3CanActivateDebugBar()) { + set_exception_handler( [ + new DebugBarExceptionHandler(), + 'handleUncaughtException' + ] ); + } + } + + /** + * @return void + */ + public function addDebugBarComponent(): void + { + if ($this->d3CanActivateDebugBar()) { + $userComponentNames = Registry::getConfig()->getConfigParam( 'aUserComponentNames' ); + $d3CmpName = DebugBarComponent::class; + $blDontUseCache = 1; + + if ( ! is_array( $userComponentNames ) ) { + $userComponentNames = []; + } + + if ( ! in_array( $d3CmpName, array_keys( $userComponentNames ) ) ) { + $userComponentNames[ $d3CmpName ] = $blDontUseCache; + Registry::getConfig()->setConfigParam( 'aUserComponentNames', $userComponentNames ); + } + } + } + + /** + * @return bool + */ + protected function d3CanActivateDebugBar(): bool + { + return false === isAdmin(); + } +} \ No newline at end of file diff --git a/Core/DebugBarErrorHandler.php b/Core/DebugBarErrorHandler.php new file mode 100644 index 0000000..dd93849 --- /dev/null +++ b/Core/DebugBarErrorHandler.php @@ -0,0 +1,99 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\DebugBar\Core; + +use D3\DebugBar\Application\Models\Exceptions\CompileErrorException; +use D3\DebugBar\Application\Models\Exceptions\CoreErrorException; +use D3\DebugBar\Application\Models\Exceptions\ParseException; +use D3\DebugBar\Application\Models\Exceptions\UserErrorException; +use ErrorException; +use OxidEsales\Eshop\Core\Registry; + +class DebugBarErrorHandler +{ + /** + * @param $severity + * @param $message + * @param $file + * @param $line + * + * @return void|false + * @throws CompileErrorException + * @throws CoreErrorException + * @throws ErrorException + * @throws ParseException + * @throws UserErrorException + */ + public function callback( $severity, $message, $file, $line ) + { + global $debugBarErrorOccured; + $debugBarErrorOccured = 1; + + if ( 0 === error_reporting() || !( error_reporting() & $severity ) ) { + // This error code is not included in error_reporting. + return false; + } + + $smartyTemplate = $this->getSmartyTemplateLocationFromError( $message ); + if ( is_array( $smartyTemplate ) ) { + [ $file, $line ] = $smartyTemplate; + } + + switch($severity) { + case E_CORE_ERROR: + throw new CoreErrorException($message, 0, $severity, $file, $line); + case E_COMPILE_ERROR: + throw new CompileErrorException($message, 0, $severity, $file, $line); + case E_USER_ERROR: + throw new UserErrorException($message, 0, $severity, $file, $line); + case E_PARSE: + throw new ParseException($message, 0, $severity, $file, $line); + case E_ERROR: + throw new ErrorException($message, 0, $severity, $file, $line); + default: + $this->handleUnregisteredErrorTypes($message, $severity, $file, $line); + } + } + + /** + * @param $messsage + * @return array|null + */ + protected function getSmartyTemplateLocationFromError($messsage): ?array + { + if (stristr($messsage, 'Smarty error: [in ')) { + $start = strpos($messsage, '[')+1; + $end = strpos($messsage, ']'); + $parts = explode(' ', substr($messsage, $start, $end - $start)); + return [Registry::getConfig()->getTemplateDir(isAdmin()).$parts[1], (int) $parts[3]]; + } + + return null; + } + + /** + * @param string $message + * @param int|null $severity + * @param string|null $file + * @param int|null $line + * + * @throws ErrorException + */ + protected function handleUnregisteredErrorTypes(string $message = '', int $severity = null, string $file = null, int $line = null) + { + throw new ErrorException($message, 0, $severity, $file, $line); + } +} \ No newline at end of file diff --git a/Core/DebugBarExceptionHandler.php b/Core/DebugBarExceptionHandler.php index 2f377cd..dbfda52 100644 --- a/Core/DebugBarExceptionHandler.php +++ b/Core/DebugBarExceptionHandler.php @@ -18,8 +18,7 @@ namespace D3\DebugBar\Core; use D3\DebugBar\Application\Component\DebugBarComponent; use DebugBar\DataCollector\ExceptionsCollector; use DebugBar\DebugBarException; -use OxidEsales\Eshop\Application\Controller\FrontendController; -use OxidEsales\Eshop\Core\Exception\DatabaseException; +use OxidEsales\Eshop\Core\ConfigFile; use OxidEsales\Eshop\Core\Exception\ExceptionHandler; use OxidEsales\Eshop\Core\Registry; use OxidEsales\EshopCommunity\Internal\Framework\Logger\LoggerServiceFactory; @@ -32,12 +31,11 @@ class DebugBarExceptionHandler * Handler for uncaught exceptions. * * @param Throwable $exception exception object - * @throws DebugBarException */ public function handleUncaughtException(Throwable $exception) { try { - $debugMode = (bool) \OxidEsales\Eshop\Core\Registry::get(\OxidEsales\Eshop\Core\ConfigFile::class)->getVar('iDebug'); + $debugMode = (bool) Registry::get( ConfigFile::class)->getVar( 'iDebug'); $defaultExceptionHandler = new ExceptionHandler($debugMode); $defaultExceptionHandler->writeExceptionToLog($exception); } catch (Throwable $loggerException) { @@ -46,7 +44,7 @@ class DebugBarExceptionHandler * Try again to log original exception (without DI container) in order to show the root cause of a problem. */ try { - $loggerServiceFactory = new LoggerServiceFactory(new Context(Registry::getConfig())); + $loggerServiceFactory = new LoggerServiceFactory(new Context()); $logger = $loggerServiceFactory->getLogger(); $logger->error($exception->getTraceAsString()); } catch (Throwable $throwableWithoutPossibilityToWriteToLogFile) { @@ -55,41 +53,38 @@ class DebugBarExceptionHandler } global $debugBarSet; + if ($debugBarSet !== 1 && false === isAdmin()) { - /** @var DebugBarComponent $debugBarComponent */ - $debugBarComponent = oxNew( DebugBarComponent::class ); + try { + /** @var DebugBarComponent $debugBarComponent */ + $debugBarComponent = oxNew( DebugBarComponent::class ); - /** @var ExceptionsCollector $excCollector */ - $excCollector = $debugBarComponent->getDebugBar()->getCollector('exceptions'); - $excCollector->addThrowable($exception); + /** @var ExceptionsCollector $excCollector */ + $excCollector = $debugBarComponent->getDebugBar()->getCollector( 'exceptions' ); + $excCollector->addThrowable( $exception ); - echo << - + echo << + + HTML; - echo $debugBarComponent->getRenderer()->renderHead(); - $debugBarComponent->addTimelineMessures(); - echo <<getRenderer()->renderHead(); + $debugBarComponent->addTimelineMessures(); + echo << HTML; - $debugBarSet = 1; - echo $debugBarComponent->getRenderer()->render(); - echo <<getRenderer()->render(); + echo << HTML; + } catch (DebugBarException $e) { + Registry::getLogger()->error($e); + Registry::getUtilsView()->addErrorToDisplay($e); + } } } - - /** - * @param DatabaseException $exception - * @return void - * @throws DebugBarException - */ - public function handleDatabaseException(DatabaseException $exception) - { - $this->handleUncaughtException($exception); - } } \ No newline at end of file diff --git a/Modules/Core/ShopControl_DebugBar.php b/Modules/Core/ShopControl_DebugBar.php index a9da785..9d95d1e 100644 --- a/Modules/Core/ShopControl_DebugBar.php +++ b/Modules/Core/ShopControl_DebugBar.php @@ -16,138 +16,80 @@ declare(strict_types=1); namespace D3\DebugBar\Modules\Core; use D3\DebugBar\Application\Component\DebugBarComponent; -use D3\DebugBar\Application\Models\Exceptions\CompileErrorException; -use D3\DebugBar\Application\Models\Exceptions\CoreErrorException; -use D3\DebugBar\Application\Models\Exceptions\ParseException; -use D3\DebugBar\Application\Models\Exceptions\UserErrorException; +use D3\DebugBar\Application\Models\DebugBarHandler; use D3\DebugBar\Core\DebugBarExceptionHandler; -use DebugBar\DataCollector\ExceptionsCollector; -use ErrorException; -use OxidEsales\Eshop\Application\Controller\FrontendController; +use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Registry; +use Throwable; class ShopControl_DebugBar extends ShopControl_DebugBar_parent { - /** - * @throws ErrorException - */ public function __construct() { - $this->d3DebugBarSetErrorHandler();; - $this->d3DebugBarSetExceptionHandler(); - $this->d3AddDebugBarComponent(); + $handler = oxNew(DebugBarHandler::class); + + $handler->setErrorHandler(); + $handler->setExceptionHandler(); + $handler->addDebugBarComponent(); parent::__construct(); } /** - * @return void - * @throws ErrorException + * @param string|null $controllerKey + * @param string|null $function + * @param string|null $parameters + * @param string|null $viewsChain */ - public function d3DebugBarSetErrorHandler() + public function start($controllerKey = null, $function = null, $parameters = null, $viewsChain = null) { - if ($this->d3CanActivateDebugBar()) { - set_error_handler( - function( $severity, $message, $file, $line ) { - if ( 0 === error_reporting() || !( error_reporting() & $severity ) ) { - // This error code is not included in error_reporting. - return false; - } + parent::start(); - $smartyTemplate = $this->getSmartyTemplateLocationFromError( $message ); - if ( is_array( $smartyTemplate ) ) { - [ $file, $line ] = $smartyTemplate; - } + global $debugBarSet, $debugBarErrorOccured; - switch($severity) { - case E_CORE_ERROR: - throw new CoreErrorException($message, 0, $severity, $file, $line); - case E_COMPILE_ERROR: - throw new CompileErrorException($message, 0, $severity, $file, $line); - case E_USER_ERROR: - throw new UserErrorException($message, 0, $severity, $file, $line); - case E_PARSE: - throw new ParseException($message, 0, $severity, $file, $line); - case E_ERROR: - default: - throw new ErrorException($message, 0, $severity, $file, $line); - } - }, - E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_PARSE - ); - } - } - - /** - * @return void - */ - protected function d3DebugBarSetExceptionHandler(): void - { - if ($this->d3CanActivateDebugBar()) { - set_exception_handler( [ - new DebugBarExceptionHandler(), - 'handleUncaughtException' - ] ); - } - } - - /** - * @param $messsage - * @return array|null - */ - protected function getSmartyTemplateLocationFromError($messsage) - { - if (stristr($messsage, 'Smarty error: [in ')) { - $start = strpos($messsage, '[')+1; - $end = strpos($messsage, ']'); - $parts = explode(' ', substr($messsage, $start, $end - $start)); - return [Registry::getConfig()->getTemplateDir(isAdmin()).$parts[1], (int) $parts[3]]; - } - - return null; - } - - /** - * @return void - */ - protected function d3AddDebugBarComponent(): void - { - if ($this->d3CanActivateDebugBar()) { - $userComponentNames = Registry::getConfig()->getConfigParam( 'aUserComponentNames' ); - $d3CmpName = DebugBarComponent::class; - $blDontUseCache = 1; - - if ( ! is_array( $userComponentNames ) ) { - $userComponentNames = []; - } - - if ( ! in_array( $d3CmpName, array_keys( $userComponentNames ) ) ) { - $userComponentNames[ $d3CmpName ] = $blDontUseCache; - Registry::getConfig()->setConfigParam( 'aUserComponentNames', $userComponentNames ); - } - } - } - - /** - * @return bool - */ - protected function d3CanActivateDebugBar(): bool - { - return false === isAdmin(); - } - - public function __destruct() - { - global $debugBarSet; - if (!isAdmin() && $debugBarSet !== 1) { + if (!isAdmin() && $debugBarSet !== 1 && $debugBarErrorOccured !== 1) { $activeView = Registry::getConfig()->getTopActiveView(); /** @var DebugBarComponent|null $debugBarComponent */ $debugBarComponent = $activeView->getComponent(DebugBarComponent::class); if ($debugBarComponent) { + $debugBarSet = 1; echo $debugBarComponent->getRenderer()->renderHead(); $debugBarComponent->addTimelineMessures(); echo $debugBarComponent->getRenderer()->render(); } } } + + /** + * @param Throwable $exception + */ + protected function debugBarHandleException(Throwable $exception) + { + $exceptionHandler = new DebugBarExceptionHandler(); + $exceptionHandler->handleUncaughtException($exception); + } + + /** + * @param StandardException $exception + */ + protected function _handleSystemException($exception) + { + $this->debugBarHandleException($exception); + } + + /** + * @param StandardException $exception + */ + protected function _handleCookieException($exception) + { + $this->debugBarHandleException($exception); + } + + /** + * @param StandardException $exception + */ + protected function _handleBaseException($exception) + { + $this->debugBarHandleException($exception); + } }