[!!!][TASK] Streamline error and exception handling 44/31844/12
authorHelmut Hummel <helmut.hummel@typo3.org>
Sat, 26 Jul 2014 11:29:24 +0000 (13:29 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Tue, 14 Jul 2015 21:42:31 +0000 (23:42 +0200)
Remove the possibility for extensions to provide
error and exception handling configuration in
ext_localconf.php of an extension. This only worked
anyway only for errors or exceptions at a later point
in the bootstrap. We now by definition make it only possible
in LocalConfiguration.php (or AdditionalConfiguration.php).

In addition make the configuration more reliable and understandable:

* Register error handler even if exception handling is not configured.
* Remove option 2 for displayErrors option
* Configure everything only once and early in the bootstrap.

Releases: master
Resolves: #68131
Change-Id: I204f17510fcb10fa8601162687793910fbcf4464
Reviewed-on: http://review.typo3.org/31844
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/Error/ErrorHandler.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-68131-StreamlineErrorAndExceptionHandling.rst [new file with mode: 0644]
typo3/sysext/core/Tests/FunctionalTestCaseBootstrapUtility.php
typo3/sysext/install/Classes/Controller/Action/AbstractAction.php
typo3/sysext/install/Classes/Service/ClearCacheService.php

index 8c88d91..ced2550 100644 (file)
@@ -63,16 +63,6 @@ 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;
-
-       /**
         * A list of all registered request handlers, see the Application class / entry points for the registration
         * @var \TYPO3\CMS\Core\Http\RequestHandlerInterface[]|\TYPO3\CMS\Core\Console\RequestHandlerInterface[]
         */
@@ -174,7 +164,6 @@ class Bootstrap {
                $this->startOutputBuffering()
                        ->loadConfigurationAndInitialize()
                        ->loadTypo3LoadedExtAndExtLocalconf(TRUE)
-                       ->initializeExceptionHandling()
                        ->setFinalCachingFrameworkCacheConfiguration()
                        ->defineLoggingAndExceptionConstants()
                        ->unsetReservedGlobalVariables()
@@ -366,7 +355,8 @@ class Bootstrap {
         * @internal This is not a public API method, do not use in own extensions
         */
        public function loadConfigurationAndInitialize($allowCaching = TRUE, $packageManagerClassName = \TYPO3\CMS\Core\Package\PackageManager::class) {
-               $this->populateLocalConfiguration();
+               $this->populateLocalConfiguration()
+                       ->initializeErrorHandling();
                if (!$allowCaching) {
                        $this->disableCoreCache();
                }
@@ -382,8 +372,6 @@ class Bootstrap {
                        ->initializeL10nLocales()
                        ->convertPageNotFoundHandlingToBoolean()
                        ->registerGlobalDebugFunctions()
-                       ->configureExceptionHandling()
-                       ->initializeExceptionHandling()
                        ->setMemoryLimit()
                        ->defineTypo3RequestTypes();
                if ($allowCaching) {
@@ -684,29 +672,52 @@ class Bootstrap {
         * Configure and set up exception and error handling
         *
         * @return Bootstrap
+        * @throws \RuntimeException
         */
-       protected function configureExceptionHandling() {
-               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'];
-               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionalErrors'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['exceptionalErrors'];
-               $doesIpMatch = GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
-               $displayErrors = (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'];
-               // Turn error logging on/off.
-               if ($displayErrors !== -1) {
-                       // Special value "2" enables this feature only if $GLOBALS['TYPO3_CONF_VARS'][SYS][devIPmask] matches
-                       if ($displayErrors === 2) {
-                               $displayErrors = (int)$doesIpMatch;
-                       }
-                       if ($displayErrors === 0) {
-                               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionalErrors'] = 0;
-                       }
-                       if ($displayErrors === 1) {
-                               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler'];
-                               define('TYPO3_ERRORHANDLER_MODE', 'debug');
+       protected function initializeErrorHandling() {
+               $productionExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'];
+               $debugExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler'];
+
+               $errorHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'];
+               $errorHandlerErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'];
+               $exceptionalErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['exceptionalErrors'];
+
+               $displayErrorsSetting = (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'];
+               switch ($displayErrorsSetting) {
+                       case 2:
+                               GeneralUtility::deprecationLog('The option "$TYPO3_CONF_VARS[SYS][displayErrors]" is set to "2" which is deprecated as of TYPO3 CMS 7, and will be removed with TYPO3 CMS 8. Please change the value to "-1"');
+                               // intentionally fall through
+                       case -1:
+                               $ipMatchesDevelopmentSystem = GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
+                               $exceptionHandlerClassName = $ipMatchesDevelopmentSystem ? $debugExceptionHandlerClassName : $productionExceptionHandlerClassName;
+                               $displayErrors = $ipMatchesDevelopmentSystem ? 1 : 0;
+                               $exceptionalErrors = $ipMatchesDevelopmentSystem ? $exceptionalErrors : 0;
+                               break;
+                       case 0:
+                               $exceptionHandlerClassName = $productionExceptionHandlerClassName;
+                               $displayErrors = 0;
+                               break;
+                       case 1:
+                               $exceptionHandlerClassName = $debugExceptionHandlerClassName;
+                               $displayErrors = 1;
+                               break;
+                       default:
+                               // Throw exception if an invalid option is set.
+                               throw new \RuntimeException('The option $TYPO3_CONF_VARS[SYS][displayErrors] is not set to "-1", "0" or "1".');
+               }
+               @ini_set('display_errors', $displayErrors);
+
+               if (!empty($errorHandlerClassName)) {
+                       // Register an error handler for the given errorHandlerError
+                       $errorHandler = GeneralUtility::makeInstance($errorHandlerClassName, $errorHandlerErrors);
+                       $errorHandler->setExceptionalErrors($exceptionalErrors);
+                       if (is_callable(array($errorHandler, 'setDebugMode'))) {
+                               $errorHandler->setDebugMode($displayErrors === 1);
                        }
-                       @ini_set('display_errors', $displayErrors);
-               } elseif ($doesIpMatch) {
-                       // With displayErrors = -1 (default), turn on debugging if devIPmask matches:
-                       $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler'];
+               }
+               if (!empty($exceptionHandlerClassName)) {
+                       // Registering the exception handler is done in the constructor
+                       GeneralUtility::makeInstance($exceptionHandlerClassName);
                }
                return $this;
        }
@@ -741,41 +752,6 @@ class Bootstrap {
        }
 
        /**
-        * Initialize exception handling
-        * This method is called twice. First when LocalConfiguration has been loaded
-        * and a second time after extension ext_localconf.php have been included to allow extensions
-        * to change the exception and error handler configuration.
-        *
-        * @return Bootstrap
-        * @internal This is not a public API method, do not use in own extensions
-        */
-       public function initializeExceptionHandling() {
-               if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['errors']['exceptionHandler'])) {
-                       if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'])) {
-                               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 = 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
-                               GeneralUtility::makeInstance($this->activeExceptionHandlerClassName);
-                       }
-               } elseif (!empty($this->activeExceptionHandlerClassName)) {
-                       // Restore exception handler in case extensions have unset the configuration in ext_localconf.php
-                       restore_exception_handler();
-               }
-               return $this;
-       }
-
-       /**
         * Extensions may register new caches, so we set the
         * global cache array to the manager again at this point
         *
index 2ac8f1d..70deb50 100644 (file)
@@ -33,6 +33,13 @@ class ErrorHandler implements ErrorHandlerInterface {
        protected $exceptionalErrors = array();
 
        /**
+        * Whether to write a flash message in case of an error
+        *
+        * @var bool
+        */
+       protected $debugMode = FALSE;
+
+       /**
         * Registers this class as default error handler
         *
         * @param int $errorHandlerErrors The integer representing the E_* error level which should be
@@ -55,6 +62,13 @@ class ErrorHandler implements ErrorHandlerInterface {
        }
 
        /**
+        * @param bool $debugMode
+        */
+       public function setDebugMode($debugMode) {
+               $this->debugMode = (bool)$debugMode;
+       }
+
+       /**
         * Handles an error.
         * If the error is registered as exceptionalError it will by converted into an exception, to be handled
         * by the configured exceptionhandler. Additionally the error message is written to the configured logs.
@@ -135,8 +149,7 @@ class ErrorHandler implements ErrorHandlerInterface {
                                // Let the internal handler continue. This will stop the script
                                return FALSE;
                        } else {
-                               // Add error message to the flashmessageQueue
-                               if (defined('TYPO3_ERRORHANDLER_MODE') && TYPO3_ERRORHANDLER_MODE == 'debug') {
+                               if ($this->debugMode) {
                                        /** @var $flashMessage \TYPO3\CMS\Core\Messaging\FlashMessage */
                                        $flashMessage = GeneralUtility::makeInstance(
                                                \TYPO3\CMS\Core\Messaging\FlashMessage::class,
index 9f53065..046a543 100644 (file)
@@ -223,7 +223,7 @@ return array(
                        ),
                ),
                'defaultCategorizedTables' => 'pages,tt_content,sys_file_metadata', // List of comma separated tables that are categorizable by default.
-               'displayErrors' => -1,          // <p>Integer (-1, 0, 1, 2). Configures whether PHP errors or Exceptions should be displayed.</p><dl><dt>0</dt><dd>Do not display any PHP error message. Sets PHP "display_errors" setting to 0. Overrides the value of [SYS][exceptionalErrors] and sets it to 0 (= no errors are turned into exceptions). The configured [SYS][productionExceptionHandler] is used as exception handler.</dd><dt>1</dt><dd>Display error messages with the registered [SYS][errorHandler]. Sets PHP "display_errors" setting to 1. The configured [SYS][debugExceptionHandler] is used as exception handler.</dd><dt>2</dt><dd>Lets the [SYS][devIPmask] decide if this setting shall be "1" (user's IP matches) or "0" (IP does not match).</dd><dt>-1</dt><dd>Default setting. TYPO3 CMS does not touch the PHP "display_errors" setting. If [SYS][devIPmask] matches the user's IP address, the configured [SYS][debugExceptionHandler] is used instead of the [SYS][productionExceptionHandler] to handle exceptions.</dd></dl>
+               'displayErrors' => -1,          // <p>Integer (-1, 0, 1). Configures whether PHP errors or Exceptions should be displayed.</p><dl><dt>0</dt><dd>Do not display any PHP error message. Sets PHP "display_errors" setting to 0. Overrides the value of [SYS][exceptionalErrors] and sets it to 0 (= no errors are turned into exceptions). The configured [SYS][productionExceptionHandler] is used as exception handler.</dd><dt>1</dt><dd>Display error messages with the registered [SYS][errorHandler]. Sets PHP "display_errors" setting to 1. The configured [SYS][debugExceptionHandler] is used as exception handler.</dd><dt>-1</dt><dd>Default setting. TYPO3 CMS does not touch the PHP "display_errors" setting. If [SYS][devIPmask] matches the user's IP address, the configured [SYS][debugExceptionHandler] is used instead of the [SYS][productionExceptionHandler] to handle exceptions.</dd></dl>
                'productionExceptionHandler' => \TYPO3\CMS\Core\Error\ProductionExceptionHandler::class,                // String: Classname to handle exceptions that might happen in the TYPO3-code. Leave empty to disable exception handling. Default: "TYPO3\\CMS\\Core\\Error\\ProductionExceptionHandler". This exception handler displays a nice error message when something went wrong. The error message is logged to the configured logs. Note: The configured "productionExceptionHandler" is used if [SYS][displayErrors] is set to "0" or is set to "-1" and [SYS][devIPmask] doesn't match the user's IP.
                'debugExceptionHandler' => \TYPO3\CMS\Core\Error\DebugExceptionHandler::class,          // String: Classname to handle exceptions that might happen in the TYPO3-code. Leave empty to disable exception handling. Default: "TYPO3\\CMS\\Core\\Error\\DebugExceptionHandler". This exception handler displays the complete stack trace of any encountered exception. The error message and the stack trace is logged to the configured logs. Note: The configured "debugExceptionHandler" is used if [SYS][displayErrors] is set to "1" or is set to "-1" or "2" and the [SYS][devIPmask] matches the user's IP.
                'errorHandler' => \TYPO3\CMS\Core\Error\ErrorHandler::class,            // String: Classname to handle PHP errors. E.g.: TYPO3\CMS\Core\Error\ErrorHandler. This class displays and logs all errors that are registered as [SYS][errorHandlerErrors]. Leave empty to disable error handling. Errors can be logged to syslog (see: [SYS][systemLog]), to the installed developer log and to the "syslog" table. If an error is registered in [SYS][exceptionalErrors] it will be turned into an exception to be handled by the configured exceptionHandler.
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-68131-StreamlineErrorAndExceptionHandling.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-68131-StreamlineErrorAndExceptionHandling.rst
new file mode 100644 (file)
index 0000000..c7487cf
--- /dev/null
@@ -0,0 +1,26 @@
+==========================================================
+Breaking: #68131 - Streamline error and exception handling
+==========================================================
+
+Description
+===========
+
+It is not possible any more to change error and exception handling configuration in an ext_localconf.php of an extension.
+
+
+Impact
+======
+
+Error or exception handling configuration overridden in ext_localonf.php files will not work any more.
+
+
+Affected Installations
+======================
+
+All installations with extension that set error or exception handling configuration in ext_localconf.php files.
+
+
+Migration
+=========
+
+Configure error and exception handling in LocalConfiguration.php or AdditionalConfiguration.php
\ No newline at end of file
index 01b15a7..3b785fe 100644 (file)
@@ -433,7 +433,6 @@ class FunctionalTestCaseBootstrapUtility {
                        ->baseSetup('')
                        ->loadConfigurationAndInitialize(TRUE)
                        ->loadTypo3LoadedExtAndExtLocalconf(TRUE)
-                       ->initializeExceptionHandling()
                        ->setFinalCachingFrameworkCacheConfiguration()
                        ->defineLoggingAndExceptionConstants()
                        ->unsetReservedGlobalVariables();
index b39378e..50aa66c 100644 (file)
@@ -248,7 +248,6 @@ abstract class AbstractAction implements ActionInterface {
                \TYPO3\CMS\Core\Core\Bootstrap::getInstance()
                        ->ensureClassLoadingInformationExists()
                        ->loadTypo3LoadedExtAndExtLocalconf(FALSE)
-                       ->initializeExceptionHandling()
                        ->defineLoggingAndExceptionConstants()
                        ->unsetReservedGlobalVariables()
                        ->initializeTypo3DbGlobal()
index f7c480e..3d0848d 100644 (file)
@@ -74,7 +74,6 @@ class ClearCacheService {
                // Use bootstrap to load all ext_localconf and ext_tables
                $bootstrap
                        ->loadTypo3LoadedExtAndExtLocalconf(FALSE)
-                       ->initializeExceptionHandling()
                        ->defineLoggingAndExceptionConstants()
                        ->unsetReservedGlobalVariables()
                        ->initializeTypo3DbGlobal()