[TASK] Doctrine: Migrate error handlers
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Error / AbstractExceptionHandler.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
17 use TYPO3\CMS\Core\Database\ConnectionPool;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * An abstract exception handler
22 *
23 * This file is a backport from TYPO3 Flow
24 */
25 abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \TYPO3\CMS\Core\SingletonInterface
26 {
27 const CONTEXT_WEB = 'WEB';
28 const CONTEXT_CLI = 'CLI';
29
30 /**
31 * Displays the given exception
32 *
33 * @param \Throwable $exception The throwable object.
34 *
35 * @throws \Exception
36 */
37 public function handleException(\Throwable $exception)
38 {
39 switch (PHP_SAPI) {
40 case 'cli':
41 $this->echoExceptionCLI($exception);
42 break;
43 default:
44 $this->echoExceptionWeb($exception);
45 }
46 }
47
48 /**
49 * Writes exception to different logs
50 *
51 * @param \Throwable $exception The throwable object.
52 * @param string $context The context where the exception was thrown, WEB or CLI
53 * @return void
54 * @see \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(), \TYPO3\CMS\Core\Utility\GeneralUtility::devLog()
55 */
56 protected function writeLogEntries(\Throwable $exception, $context)
57 {
58 // Do not write any logs for this message to avoid filling up tables or files with illegal requests
59 if ($exception->getCode() === 1396795884) {
60 return;
61 }
62 $filePathAndName = $exception->getFile();
63 $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : '';
64 $logTitle = 'Core: Exception handler (' . $context . ')';
65 $logMessage = 'Uncaught TYPO3 Exception: ' . $exceptionCodeNumber . $exception->getMessage() . ' | '
66 . get_class($exception) . ' thrown in file ' . $filePathAndName . ' in line ' . $exception->getLine();
67 if ($context === 'WEB') {
68 $logMessage .= '. Requested URL: ' . GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
69 }
70 $backtrace = $exception->getTrace();
71 // Write error message to the configured syslogs
72 GeneralUtility::sysLog($logMessage, $logTitle, GeneralUtility::SYSLOG_SEVERITY_FATAL);
73 // When database credentials are wrong, the exception is probably
74 // caused by this. Therefor we cannot do any database operation,
75 // otherwise this will lead into recurring exceptions.
76 try {
77 // Write error message to devlog
78 // see: $TYPO3_CONF_VARS['SYS']['enable_exceptionDLOG']
79 if (TYPO3_EXCEPTION_DLOG) {
80 GeneralUtility::devLog($logMessage, $logTitle, 3, array(
81 'TYPO3_MODE' => TYPO3_MODE,
82 'backtrace' => $backtrace
83 ));
84 }
85 // Write error message to sys_log table
86 $this->writeLog($logTitle . ': ' . $logMessage);
87 } catch (\Exception $exception) {
88 }
89 }
90
91 /**
92 * Writes an exception in the sys_log table
93 *
94 * @param string $logMessage Default text that follows the message.
95 * @return void
96 */
97 protected function writeLog($logMessage)
98 {
99 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
100 ->getConnectionForTable('sys_log');
101
102 if (!$connection->isConnected()) {
103 return;
104 }
105 $userId = 0;
106 $workspace = 0;
107 $data = array();
108 $backendUser = $this->getBackendUser();
109 if (is_object($backendUser)) {
110 if (isset($backendUser->user['uid'])) {
111 $userId = $backendUser->user['uid'];
112 }
113 if (isset($backendUser->workspace)) {
114 $workspace = $backendUser->workspace;
115 }
116 if (!empty($backendUser->user['ses_backuserid'])) {
117 $data['originalUser'] = $backendUser->user['ses_backuserid'];
118 }
119 }
120
121 $connection->insert(
122 'sys_log',
123 [
124 'userid' => $userId,
125 'type' => 5,
126 'action' => 0,
127 'error' => 2,
128 'details_nr' => 0,
129 'details' => str_replace('%', '%%', $logMessage),
130 'log_data' => empty($data) ? '' : serialize($data),
131 'IP' => (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'),
132 'tstamp' => $GLOBALS['EXEC_TIME'],
133 'workspace' => $workspace
134 ]
135 );
136 }
137
138 /**
139 * Sends the HTTP Status 500 code, if $exception is *not* a
140 * TYPO3\CMS\Core\Error\Http\StatusException and headers are not sent, yet.
141 *
142 * @param \Throwable $exception The throwable object.
143 * @return void
144 */
145 protected function sendStatusHeaders(\Throwable $exception)
146 {
147 if (method_exists($exception, 'getStatusHeaders')) {
148 $headers = $exception->getStatusHeaders();
149 } else {
150 $headers = array(\TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_500);
151 }
152 if (!headers_sent()) {
153 foreach ($headers as $header) {
154 header($header);
155 }
156 }
157 }
158
159 /**
160 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
161 */
162 protected function getBackendUser()
163 {
164 return $GLOBALS['BE_USER'];
165 }
166 }