[BUGFIX] Register the exception handler early in bootstrap 55/31555/4
authorHelmut Hummel <helmut.hummel@typo3.org>
Thu, 10 Jul 2014 13:42:13 +0000 (15:42 +0200)
committerMarkus Klein <klein.t3@reelworx.at>
Sat, 1 Nov 2014 18:50:28 +0000 (19:50 +0100)
Currently registering the exception handler is done
after extensions are loaded to allow extensions to
modify configuration to override the exception handler
defined in LocalConfiguration or DefaultConfiguration.

Registering the exception handler so late has however
the drawback that exceptions throw before, lack proper
handling (and maybe in production even disclose more information
than needed).

Change that and register error handling much earlier
in the bootstrap so that exceptions thrown e.g. while
loading ext_localconf.php can show a proper stack trace
to give developers more useful information why the exception occurred.

To still allow extensions to override configuration,
we now remember the early exception and error handler classes
and potentially register a new exception handler after extensions
have been loaded.

Resolves: #60235
Releases: 6.2, master
Change-Id: I087173073ba75a54be14ca4f40f90c0e5304892d
Reviewed-on: http://review.typo3.org/31555
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
typo3/sysext/core/Classes/Core/Bootstrap.php

index 7718801..9729f4a 100644 (file)
@@ -63,6 +63,16 @@ class Bootstrap {
        protected $installToolPath;
 
        /**
+        * @var string The currently active exception handling class. It is set after LocalConfiguration is included and might be changed after ex_localconf.php are loaded.
+        */
+       protected $activeExceptionHandlerClassName;
+
+       /**
+        * @var string The currently active error handling class. It is set after LocalConfiguration is included and might be changed after ex_localconf.php are loaded.
+        */
+       protected $activeErrorHandlerClassName;
+
+       /**
         * Disable direct creation of this object.
         * Set unique requestId and the application context
         *
@@ -232,6 +242,7 @@ class Bootstrap {
                        ->convertPageNotFoundHandlingToBoolean()
                        ->registerGlobalDebugFunctions()
                        ->configureExceptionHandling()
+                       ->initializeExceptionHandling()
                        ->setMemoryLimit()
                        ->defineTypo3RequestTypes();
                return $this;
@@ -635,20 +646,34 @@ class Bootstrap {
 
        /**
         * Initialize exception handling
+        * This method is called twice. First when LocalConfiguration has been loaded
+        * and a second time after extension ext_loclconf.php have been included to allow extensions
+        * to change the exception and error handler configuration.
         *
         * @return Bootstrap
         */
        protected function initializeExceptionHandling() {
                if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'])) {
                        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'])) {
-                               // Register an error handler for the given errorHandlerErrors
-                               $errorHandler = Utility\GeneralUtility::makeInstance($GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors']);
-                               // Set errors which will be converted in an exception
-                               $errorHandler->setExceptionalErrors($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionalErrors']);
+                               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'] !== $this->activeErrorHandlerClassName) {
+                                       $this->activeErrorHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'];
+                                       // Register an error handler for the given errorHandlerErrors
+                                       $errorHandler = Utility\GeneralUtility::makeInstance($this->activeErrorHandlerClassName, $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors']);
+                                       // Set errors which will be converted in an exception
+                                       $errorHandler->setExceptionalErrors($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionalErrors']);
+                               }
+                       } elseif (!empty($this->activeErrorHandlerClassName)) {
+                               // Restore error handler in case extensions have unset the configuration in ext_localconf.php
+                               restore_error_handler();
+                       }
+                       if ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'] !== $this->activeExceptionHandlerClassName) {
+                               $this->activeExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'];
+                               // Registering the exception handler is done in the constructor
+                               Utility\GeneralUtility::makeInstance($this->activeExceptionHandlerClassName);
                        }
-                       // Instantiate the exception handler once to make sure object is registered
-                       // @TODO: Figure out if this is really needed
-                       Utility\GeneralUtility::makeInstance($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler']);
+               } elseif (!empty($this->activeExceptionHandlerClassName)) {
+                       // Restore exception handler in case extensions have unset the configuration in ext_localconf.php
+                       restore_exception_handler();
                }
                return $this;
        }