ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilErrorHandling.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3/* Copyright (c) 2015 Richard Klees, Extended GPL, see docs/LICENSE */
4/* Copyright (c) 2016 Stefan Hecken, Extended GPL, see docs/LICENSE */
5
6require_once 'Services/Environment/classes/class.ilRuntime.php';
7
22require_once("Services/Exceptions/classes/class.ilDelegatingHandler.php");
23require_once("Services/Exceptions/classes/class.ilPlainTextHandler.php");
24require_once("Services/Exceptions/classes/class.ilTestingHandler.php");
25
26use Whoops\Run;
30
31class ilErrorHandling extends PEAR
32{
38 public $DEBUG_ENV;
39
45 public $FATAL;
46
52 public $WARNING;
53
59 public $MESSAGE;
60
65 protected static $whoops_handlers_registered = false;
66
71 public function __construct()
72 {
73 parent::__construct();
74
75 // init vars
76 $this->DEBUG_ENV = true;
77 $this->FATAL = 1;
78 $this->WARNING = 2;
79 $this->MESSAGE = 3;
80
81 $this->error_obj = false;
82
83 $this->initWhoopsHandlers();
84
85 // somehow we need to get rid of the whoops error handler
86 restore_error_handler();
87 set_error_handler(array($this, "handlePreWhoops"));
88 }
89
98 protected function initWhoopsHandlers()
99 {
100 if (self::$whoops_handlers_registered) {
101 // Only register whoops error handlers once.
102 return;
103 }
104
105 $ilRuntime = $this->getIlRuntime();
106 $this->whoops = $this->getWhoops();
107
108 $this->whoops->pushHandler(new ilDelegatingHandler($this));
109
110 if ($ilRuntime->shouldLogErrors()) {
111 $this->whoops->pushHandler($this->loggingHandler());
112 }
113
114 $this->whoops->register();
115
116 self::$whoops_handlers_registered = true;
117 }
118
126 public function getHandler()
127 {
128 // TODO: * Use Whoops in production mode? This would require an appropriate
129 // error-handler.
130 // * Check for context? The current implementation e.g. would output HTML for
131 // for SOAP.
132
133 if ($this->isDevmodeActive()) {
134 return $this->devmodeHandler();
135 }
136
137 return $this->defaultHandler();
138 }
139
140 public function getLastError()
141 {
142 return $this->error_obj;
143 }
144
150 public function errorHandler($a_error_obj)
151 {
152 global $log;
153
154 // see bug 18499 (some calls to raiseError do not pass a code, which leads to security issues, if these calls
155 // are done due to permission checks)
156 if ($a_error_obj->getCode() == null) {
157 $a_error_obj->code = $this->WARNING;
158 }
159
160 $this->error_obj = &$a_error_obj;
161 //echo "-".$_SESSION["referer"]."-";
162 if ($_SESSION["failure"] && substr($a_error_obj->getMessage(), 0, 22) != "Cannot find this block") {
163 $m = "Fatal Error: Called raise error two times.<br>" .
164 "First error: " . $_SESSION["failure"] . '<br>' .
165 "Last Error:" . $a_error_obj->getMessage();
166 //return;
167 $log->write($m);
168 #$log->writeWarning($m);
169 #$log->logError($a_error_obj->getCode(), $m);
170 unset($_SESSION["failure"]);
171 die($m);
172 }
173
174 if (substr($a_error_obj->getMessage(), 0, 22) == "Cannot find this block") {
175 if (DEVMODE == 1) {
176 echo "<b>DEVMODE</b><br><br>";
177 echo "<b>Template Block not found.</b><br>";
178 echo "You used a template block in your code that is not available.<br>";
179 echo "Native Messge: <b>" . $a_error_obj->getMessage() . "</b><br>";
180 if (is_array($a_error_obj->backtrace)) {
181 echo "Backtrace:<br>";
182 foreach ($a_error_obj->backtrace as $b) {
183 if ($b["function"] == "setCurrentBlock" &&
184 basename($b["file"]) != "class.ilTemplate.php") {
185 echo "<b>";
186 }
187 echo "File: " . $b["file"] . ", ";
188 echo "Line: " . $b["line"] . ", ";
189 echo $b["function"] . "()<br>";
190 if ($b["function"] == "setCurrentBlock" &&
191 basename($b["file"]) != "class.ilTemplate.php") {
192 echo "</b>";
193 }
194 }
195 }
196 exit;
197 }
198 return;
199 }
200
201 if (is_object($log) and $log->enabled == true) {
202 $log->write($a_error_obj->getMessage());
203 #$log->logError($a_error_obj->getCode(),$a_error_obj->getMessage());
204 }
205
206 //echo $a_error_obj->getCode().":"; exit;
207 if ($a_error_obj->getCode() == $this->FATAL) {
208 trigger_error(stripslashes($a_error_obj->getMessage()), E_USER_ERROR);
209 exit();
210 }
211
212 if ($a_error_obj->getCode() == $this->WARNING) {
213 if ($this->DEBUG_ENV) {
214 $message = $a_error_obj->getMessage();
215 } else {
216 $message = "Under Construction";
217 }
218
219 $_SESSION["failure"] = $message;
220
221 if (!defined("ILIAS_MODULE")) {
222 ilUtil::redirect("error.php");
223 } else {
224 ilUtil::redirect("../error.php");
225 }
226 }
227
228 if ($a_error_obj->getCode() == $this->MESSAGE) {
229 $_SESSION["failure"] = $a_error_obj->getMessage();
230 // save post vars to session in case of error
231 $_SESSION["error_post_vars"] = $_POST;
232
233 if (empty($_SESSION["referer"])) {
234 $dirname = dirname($_SERVER["PHP_SELF"]);
235 $ilurl = parse_url(ILIAS_HTTP_PATH);
236 $subdir = substr(strstr($dirname, $ilurl["path"]), strlen($ilurl["path"]));
237 $updir = "";
238
239 if ($subdir) {
240 $num_subdirs = substr_count($subdir, "/");
241
242 for ($i = 1;$i <= $num_subdirs;$i++) {
243 $updir .= "../";
244 }
245 }
246 ilUtil::redirect($updir . "index.php");
247 }
248
249 /* #12104
250 check if already GET-Parameters exists in Referer-URI
251 if (substr($_SESSION["referer"],-4) == ".php")
252 {
253 $glue = "?";
254 }
255 else
256 {
257 // this did break permanent links (".html&")
258 $glue = "&";
259 }
260 */
261 ilUtil::redirect($_SESSION["referer"]);
262 }
263 }
264
265 public function getMessage()
266 {
267 return $this->message;
268 }
269 public function setMessage($a_message)
270 {
271 $this->message = $a_message;
272 }
273 public function appendMessage($a_message)
274 {
275 if ($this->getMessage()) {
276 $this->message .= "<br /> ";
277 }
278 $this->message .= $a_message;
279 }
280
290 public static function _ilErrorWriter($errno, $errstr, $errfile, $errline)
291 {
292 global $ilLog;
293
294 switch ($errno) {
295 case E_USER_ERROR:
296 $ilLog->write('PHP errror: ' . $errstr . '. FATAL error on line ' . $errline . ' in file ' . $errfile);
297 unset($ilLog);
298 exit(1);
299
300 case E_USER_WARNING:
301 $ilLog->write('PHP warning: [' . $errno . '] ' . $errstr . ' on line ' . $errline . ' in file ' . $errfile);
302 break;
303
304 }
305 return true;
306 }
307
312 protected function getIlRuntime()
313 {
314 return ilRuntime::getInstance();
315 }
316
321 protected function getWhoops()
322 {
323 return new Run();
324 }
325
330 protected function isDevmodeActive()
331 {
332 return defined("DEVMODE") && (int) DEVMODE === 1;
333 }
334
339 protected function defaultHandler()
340 {
341 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
342 return new CallbackHandler(function ($exception, Inspector $inspector, Run $run) {
343 global $lng;
344
345 require_once("Services/Logging/classes/error/class.ilLoggingErrorSettings.php");
346 require_once("Services/Logging/classes/error/class.ilLoggingErrorFileStorage.php");
347 require_once("Services/Utilities/classes/class.ilUtil.php");
348
349 $session_id = substr(session_id(), 0, 5);
350 $random = new \ilRandom();
351 $err_num = $random->int(1, 9999);
352 $file_name = $session_id . "_" . $err_num;
353
355 if (!empty($logger->folder())) {
356 $lwriter = new ilLoggingErrorFileStorage($inspector, $logger->folder(), $file_name);
357 $lwriter->write();
358 }
359
360 //Use $lng if defined or fallback to english
361 if ($lng !== null) {
362 $lng->loadLanguageModule('logging');
363 $message = sprintf($lng->txt("log_error_message"), $file_name);
364
365 if ($logger->mail()) {
366 $message .= " " . sprintf($lng->txt("log_error_message_send_mail"), $logger->mail(), $file_name, $logger->mail());
367 }
368 } else {
369 $message = 'Sorry, an error occured. A logfile has been created which can be identified via the code "' . $file_name . '"';
370
371 if ($logger->mail()) {
372 $message .= ' ' . 'Please send a mail to <a href="mailto:' . $logger->mail() . '?subject=code: ' . $file_name . '">' . $logger->mail() . '</a>';
373 }
374 }
375
377 ilUtil::redirect("error.php");
378 });
379 }
380
385 protected function devmodeHandler()
386 {
387 global $ilLog;
388
389 switch (ERROR_HANDLER) {
390 case "TESTING":
391 return new ilTestingHandler();
392 case "PLAIN_TEXT":
393 return new ilPlainTextHandler();
394 case "PRETTY_PAGE":
395 return new PrettyPageHandler();
396 default:
397 if ($ilLog) {
398 $ilLog->write("Unknown or undefined error handler '" . ERROR_HANDLER . "'. "
399 . "Falling back to PrettyPageHandler.");
400 }
401 return new PrettyPageHandler();
402 }
403 }
404
409 protected function loggingHandler()
410 {
411 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
412 return new CallbackHandler(function ($exception, Inspector $inspector, Run $run) {
417 global $ilLog;
418
419 if (is_object($ilLog)) {
420 $message = $exception->getMessage() . ' in ' . $exception->getFile() . ":" . $exception->getLine();
421 $message .= $exception->getTraceAsString();
422 $ilLog->error($exception->getCode() . ' ' . $message);
423 }
424
425 // Send to system logger
426 error_log($exception->getMessage());
427 });
428 }
429
430 public function handlePreWhoops($level, $message, $file, $line)
431 {
432 global $ilLog;
433
434 if ($level & error_reporting()) {
435
436 // correct-with-php5-removal JL start
437 // ignore all E_STRICT that are E_NOTICE (or nothing at all) in PHP7
438 if (version_compare(PHP_VERSION, '7.0.0', '<')) {
439 if ($level == E_STRICT) {
440 if (!stristr($message, "should be compatible") &&
441 !stristr($message, "should not be called statically") &&
442 !stristr($message, "should not be abstract")) {
443 return true;
444 };
445 }
446 }
447 // correct-with-php5-removal end
448
449 if (!$this->isDevmodeActive()) {
450 // log E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED only
451 if ($level >= E_USER_NOTICE) {
452 if ($ilLog) {
453 $severity = Whoops\Util\Misc::TranslateErrorCode($level);
454 $ilLog->write("\n\n" . $severity . " - " . $message . "\n" . $file . " - line " . $line . "\n");
455 }
456 return true;
457 }
458 }
459
460 // trigger whoops error handling
461 if ($this->whoops) {
462 return $this->whoops->handleError($level, $message, $file, $line);
463 }
464 }
465
466 return false;
467 }
468} // END class.ilErrorHandling
exit
Definition: backend.php:16
$_POST["username"]
$_SESSION["AccountId"]
An exception for terminatinating execution or to throw for unit testing.
Wrapper for Closures passed as handlers.
initWhoopsHandlers()
Initialize Error and Exception Handlers.
handlePreWhoops($level, $message, $file, $line)
errorHandler($a_error_obj)
defines what has to happen in case of error @access private
devmodeHandler()
Get the handler to be used in DEVMODE.
__construct()
Constructor @access public.
getWhoops()
Get an instance of Whoops/Run.
static _ilErrorWriter($errno, $errstr, $errfile, $errline)
This is used in Soap calls to write PHP error in ILIAS Logfile Not used yet!!!
getIlRuntime()
Get ilRuntime.
isDevmodeActive()
Is the DEVMODE switched on?
getHandler()
Get a handler for an error or exception.
defaultHandler()
Get a default error handler.
Saves error informations into file.
static getInstance()
A Whoops error handler for testing.
static redirect($a_script)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
$i
Definition: disco.tpl.php:19
catch(Exception $e) $message
$log
Definition: sabredav.php:21
$lng
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']