[TASK] Cleanup error handling code and settings description
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Error / ErrorHandler.php
1 <?php
2 namespace TYPO3\CMS\Core\Error;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 use TYPO3\CMS\Core\Utility\GeneralUtility;
17
18 /**
19 * Global error handler for TYPO3
20 *
21 * This file is a backport from FLOW3
22 *
23 * @author Rupert Germann <rupi@gmx.li>
24 */
25 class ErrorHandler implements ErrorHandlerInterface {
26
27 /**
28 * Error levels which should result in an exception thrown.
29 *
30 * @var array
31 */
32 protected $exceptionalErrors = array();
33
34 /**
35 * Registers this class as default error handler
36 *
37 * @param int $errorHandlerErrors The integer representing the E_* error level which should be
38 */
39 public function __construct($errorHandlerErrors) {
40 $excludedErrors = E_COMPILE_WARNING | E_COMPILE_ERROR | E_CORE_WARNING | E_CORE_ERROR | E_PARSE | E_ERROR;
41 // reduces error types to those a custom error handler can process
42 $errorHandlerErrors = $errorHandlerErrors & ~$excludedErrors;
43 set_error_handler(array($this, 'handleError'), $errorHandlerErrors);
44 }
45
46 /**
47 * Defines which error levels should result in an exception thrown.
48 *
49 * @param int $exceptionalErrors The integer representing the E_* error level to handle as exceptions
50 * @return void
51 */
52 public function setExceptionalErrors($exceptionalErrors) {
53 $this->exceptionalErrors = (int)$exceptionalErrors;
54 }
55
56 /**
57 * Handles an error.
58 * If the error is registered as exceptionalError it will by converted into an exception, to be handled
59 * by the configured exceptionhandler. Additionally the error message is written to the configured logs.
60 * If TYPO3_MODE is 'BE' the error message is also added to the flashMessageQueue, in FE the error message
61 * is displayed in the admin panel (as TsLog message)
62 *
63 * @param int $errorLevel The error level - one of the E_* constants
64 * @param string $errorMessage The error message
65 * @param string $errorFile Name of the file the error occurred in
66 * @param int $errorLine Line number where the error occurred
67 * @return bool
68 * @throws Exception with the data passed to this method if the error is registered as exceptionalError
69 */
70 public function handleError($errorLevel, $errorMessage, $errorFile, $errorLine) {
71 // Don't do anything if error_reporting is disabled by an @ sign
72 if (error_reporting() === 0) {
73 return TRUE;
74 }
75 $errorLevels = array(
76 E_WARNING => 'Warning',
77 E_NOTICE => 'Notice',
78 E_USER_ERROR => 'User Error',
79 E_USER_WARNING => 'User Warning',
80 E_USER_NOTICE => 'User Notice',
81 E_STRICT => 'Runtime Notice',
82 E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
83 E_DEPRECATED => 'Runtime Deprecation Notice'
84 );
85 $message = 'PHP ' . $errorLevels[$errorLevel] . ': ' . $errorMessage . ' in ' . $errorFile . ' line ' . $errorLine;
86 if ($errorLevel & $this->exceptionalErrors) {
87 // handle error raised at early parse time
88 // autoloader not available & built-in classes not resolvable
89 if (!class_exists('stdClass', FALSE)) {
90 $message = 'PHP ' . $errorLevels[$errorLevel] . ': ' . $errorMessage . ' in ' . basename($errorFile) .
91 'line ' . $errorLine;
92 die($message);
93 }
94 // We need to manually require the exception classes in case
95 // the autoloader is not available at this point yet.
96 // @see http://forge.typo3.org/issues/23444
97 if (!class_exists('TYPO3\\CMS\\Core\\Error\\Exception', FALSE)) {
98 require_once PATH_site . 'typo3/sysext/core/Classes/Exception.php';
99 require_once PATH_site . 'typo3/sysext/core/Classes/Error/Exception.php';
100 }
101 throw new Exception($message, 1);
102 } else {
103 switch ($errorLevel) {
104 case E_USER_ERROR:
105
106 case E_RECOVERABLE_ERROR:
107 $severity = 2;
108 break;
109 case E_USER_WARNING:
110
111 case E_WARNING:
112 $severity = 1;
113 break;
114 default:
115 $severity = 0;
116 }
117 $logTitle = 'Core: Error handler (' . TYPO3_MODE . ')';
118 // Write error message to the configured syslogs,
119 // see: $TYPO3_CONF_VARS['SYS']['systemLog']
120 if ($errorLevel & $GLOBALS['TYPO3_CONF_VARS']['SYS']['syslogErrorReporting']) {
121 GeneralUtility::sysLog($message, $logTitle, $severity);
122 }
123 // Write error message to devlog extension(s),
124 // see: $TYPO3_CONF_VARS['SYS']['enable_errorDLOG']
125 if (TYPO3_ERROR_DLOG) {
126 GeneralUtility::devLog($message, $logTitle, $severity + 1);
127 }
128 // Write error message to TSlog (admin panel)
129 if (is_object($GLOBALS['TT'])) {
130 $GLOBALS['TT']->setTSlogMessage($logTitle . ': ' . $message, $severity + 1);
131 }
132 // Write error message to sys_log table (ext: belog, Tools->Log)
133 if ($errorLevel & $GLOBALS['TYPO3_CONF_VARS']['SYS']['belogErrorReporting']) {
134 // Silently catch in case an error occurs before a database connection exists,
135 // but DatabaseConnection fails to connect.
136 try {
137 $this->writeLog($logTitle . ': ' . $message, $severity);
138 } catch (\Exception $e) {
139 }
140 }
141 // Add error message to the flashmessageQueue
142 if (defined('TYPO3_ERRORHANDLER_MODE') && TYPO3_ERRORHANDLER_MODE == 'debug') {
143 /** @var $flashMessage \TYPO3\CMS\Core\Messaging\FlashMessage */
144 $flashMessage = GeneralUtility::makeInstance(
145 'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
146 $message,
147 'PHP ' . $errorLevels[$errorLevel],
148 $severity
149 );
150 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
151 $flashMessageService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService');
152 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
153 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
154 $defaultFlashMessageQueue->enqueue($flashMessage);
155 }
156 }
157 // Don't execute PHP internal error handler
158 return TRUE;
159 }
160
161 /**
162 * Writes an error in the sys_log table
163 *
164 * @param string $logMessage Default text that follows the message (in english!).
165 * @param int $severity The error level of the message (0 = OK, 1 = warning, 2 = error)
166 * @return void
167 */
168 protected function writeLog($logMessage, $severity) {
169 if (is_object($GLOBALS['TYPO3_DB']) && $GLOBALS['TYPO3_DB']->isConnected()) {
170 $userId = 0;
171 $workspace = 0;
172 if (is_object($GLOBALS['BE_USER'])) {
173 if (isset($GLOBALS['BE_USER']->user['uid'])) {
174 $userId = $GLOBALS['BE_USER']->user['uid'];
175 }
176 if (isset($GLOBALS['BE_USER']->workspace)) {
177 $workspace = $GLOBALS['BE_USER']->workspace;
178 }
179 }
180 $fields_values = array(
181 'userid' => $userId,
182 'type' => 5,
183 'action' => 0,
184 'error' => $severity,
185 'details_nr' => 0,
186 'details' => $logMessage,
187 'IP' => (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'),
188 'tstamp' => $GLOBALS['EXEC_TIME'],
189 'workspace' => $workspace
190 );
191 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_log', $fields_values);
192 }
193 }
194
195 }