ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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");
25set_include_path("./Services/Database/lib/PEAR" . PATH_SEPARATOR . ini_get('include_path'));
26if (!class_exists('PEAR')) {
27 require_once 'PEAR.php';
28}
29use Whoops\Run;
33
34class ilErrorHandling extends PEAR
35{
41 public $DEBUG_ENV;
42
48 public $FATAL;
49
55 public $WARNING;
56
62 public $MESSAGE;
63
68 protected static $whoops_handlers_registered = false;
69
74 public function __construct()
75 {
76 parent::__construct();
77
78 // init vars
79 $this->DEBUG_ENV = true;
80 $this->FATAL = 1;
81 $this->WARNING = 2;
82 $this->MESSAGE = 3;
83
84 $this->error_obj = false;
85
86 $this->initWhoopsHandlers();
87
88 // somehow we need to get rid of the whoops error handler
89 restore_error_handler();
90 set_error_handler(array($this, "handlePreWhoops"));
91 }
92
101 protected function initWhoopsHandlers()
102 {
103 if (self::$whoops_handlers_registered) {
104 // Only register whoops error handlers once.
105 return;
106 }
107
108 $ilRuntime = $this->getIlRuntime();
109 $this->whoops = $this->getWhoops();
110
111 $this->whoops->pushHandler(new ilDelegatingHandler($this));
112
113 if ($ilRuntime->shouldLogErrors()) {
114 $this->whoops->pushHandler($this->loggingHandler());
115 }
116
117 $this->whoops->register();
118
119 self::$whoops_handlers_registered = true;
120 }
121
129 public function getHandler()
130 {
131 // TODO: * Use Whoops in production mode? This would require an appropriate
132 // error-handler.
133 // * Check for context? The current implementation e.g. would output HTML for
134 // for SOAP.
135
136 if ($this->isDevmodeActive()) {
137 return $this->devmodeHandler();
138 }
139
140 return $this->defaultHandler();
141 }
142
143 public function getLastError()
144 {
145 return $this->error_obj;
146 }
147
153 public function errorHandler($a_error_obj)
154 {
155 global $log;
156
157 // see bug 18499 (some calls to raiseError do not pass a code, which leads to security issues, if these calls
158 // are done due to permission checks)
159 if ($a_error_obj->getCode() == null) {
160 $a_error_obj->code = $this->WARNING;
161 }
162
163 $this->error_obj =&$a_error_obj;
164 //echo "-".$_SESSION["referer"]."-";
165 if ($_SESSION["failure"] && substr($a_error_obj->getMessage(), 0, 22) != "Cannot find this block") {
166 $m = "Fatal Error: Called raise error two times.<br>" .
167 "First error: " . $_SESSION["failure"] . '<br>' .
168 "Last Error:" . $a_error_obj->getMessage();
169 //return;
170 $log->write($m);
171 #$log->writeWarning($m);
172 #$log->logError($a_error_obj->getCode(), $m);
173 unset($_SESSION["failure"]);
174 die($m);
175 }
176
177 if (substr($a_error_obj->getMessage(), 0, 22) == "Cannot find this block") {
178 if (DEVMODE == 1) {
179 echo "<b>DEVMODE</b><br><br>";
180 echo "<b>Template Block not found.</b><br>";
181 echo "You used a template block in your code that is not available.<br>";
182 echo "Native Messge: <b>" . $a_error_obj->getMessage() . "</b><br>";
183 if (is_array($a_error_obj->backtrace)) {
184 echo "Backtrace:<br>";
185 foreach ($a_error_obj->backtrace as $b) {
186 if ($b["function"] == "setCurrentBlock" &&
187 basename($b["file"]) != "class.ilTemplate.php") {
188 echo "<b>";
189 }
190 echo "File: " . $b["file"] . ", ";
191 echo "Line: " . $b["line"] . ", ";
192 echo $b["function"] . "()<br>";
193 if ($b["function"] == "setCurrentBlock" &&
194 basename($b["file"]) != "class.ilTemplate.php") {
195 echo "</b>";
196 }
197 }
198 }
199 exit;
200 }
201 return;
202 }
203
204 if (is_object($log) and $log->enabled == true) {
205 $log->write($a_error_obj->getMessage());
206 #$log->logError($a_error_obj->getCode(),$a_error_obj->getMessage());
207 }
208
209 //echo $a_error_obj->getCode().":"; exit;
210 if ($a_error_obj->getCode() == $this->FATAL) {
211 trigger_error(stripslashes($a_error_obj->getMessage()), E_USER_ERROR);
212 exit();
213 }
214
215 if ($a_error_obj->getCode() == $this->WARNING) {
216 if ($this->DEBUG_ENV) {
217 $message = $a_error_obj->getMessage();
218 } else {
219 $message = "Under Construction";
220 }
221
222 $_SESSION["failure"] = $message;
223
224 if (!defined("ILIAS_MODULE")) {
225 ilUtil::redirect("error.php");
226 } else {
227 ilUtil::redirect("../error.php");
228 }
229 }
230
231 if ($a_error_obj->getCode() == $this->MESSAGE) {
232 $_SESSION["failure"] = $a_error_obj->getMessage();
233 // save post vars to session in case of error
234 $_SESSION["error_post_vars"] = $_POST;
235
236 if (empty($_SESSION["referer"])) {
237 $dirname = dirname($_SERVER["PHP_SELF"]);
238 $ilurl = parse_url(ILIAS_HTTP_PATH);
239 $subdir = substr(strstr($dirname, $ilurl["path"]), strlen($ilurl["path"]));
240 $updir = "";
241
242 if ($subdir) {
243 $num_subdirs = substr_count($subdir, "/");
244
245 for ($i=1;$i<=$num_subdirs;$i++) {
246 $updir .= "../";
247 }
248 }
249 ilUtil::redirect($updir . "index.php");
250 }
251
252 /* #12104
253 check if already GET-Parameters exists in Referer-URI
254 if (substr($_SESSION["referer"],-4) == ".php")
255 {
256 $glue = "?";
257 }
258 else
259 {
260 // this did break permanent links (".html&")
261 $glue = "&";
262 }
263 */
264 ilUtil::redirect($_SESSION["referer"]);
265 }
266 }
267
268 public function getMessage()
269 {
270 return $this->message;
271 }
272 public function setMessage($a_message)
273 {
274 $this->message = $a_message;
275 }
276 public function appendMessage($a_message)
277 {
278 if ($this->getMessage()) {
279 $this->message .= "<br /> ";
280 }
281 $this->message .= $a_message;
282 }
283
293 public static function _ilErrorWriter($errno, $errstr, $errfile, $errline)
294 {
295 global $ilLog;
296
297 switch ($errno) {
298 case E_USER_ERROR:
299 $ilLog->write('PHP errror: ' . $errstr . '. FATAL error on line ' . $errline . ' in file ' . $errfile);
300 unset($ilLog);
301 exit(1);
302
303 case E_USER_WARNING:
304 $ilLog->write('PHP warning: [' . $errno . '] ' . $errstr . ' on line ' . $errline . ' in file ' . $errfile);
305 break;
306
307 }
308 return true;
309 }
310
315 protected function getIlRuntime()
316 {
317 return ilRuntime::getInstance();
318 }
319
324 protected function getWhoops()
325 {
326 return new Run();
327 }
328
333 protected function isDevmodeActive()
334 {
335 return defined("DEVMODE") && (int) DEVMODE === 1;
336 }
337
342 protected function defaultHandler()
343 {
344 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
345 return new CallbackHandler(function ($exception, Inspector $inspector, Run $run) {
346 global $lng;
347
348 require_once("Services/Logging/classes/error/class.ilLoggingErrorSettings.php");
349 require_once("Services/Logging/classes/error/class.ilLoggingErrorFileStorage.php");
350 require_once("Services/Utilities/classes/class.ilUtil.php");
351
352 $session_id = substr(session_id(), 0, 5);
353 $random = new \ilRandom();
354 $err_num = $random->int(1, 9999);
355 $file_name = $session_id . "_" . $err_num;
356
358 if (!empty($logger->folder())) {
359 $lwriter = new ilLoggingErrorFileStorage($inspector, $logger->folder(), $file_name);
360 $lwriter->write();
361 }
362
363 //Use $lng if defined or fallback to english
364 if ($lng !== null) {
365 $lng->loadLanguageModule('logging');
366 $message = sprintf($lng->txt("log_error_message"), $file_name);
367
368 if ($logger->mail()) {
369 $message .= " " . sprintf($lng->txt("log_error_message_send_mail"), $logger->mail(), $file_name, $logger->mail());
370 }
371 } else {
372 $message = "Error " . $file_name . " occurred.";
373
374 if ($logger->mail()) {
375 $message .= ' ' . 'Please send a mail to <a href="mailto:' . $logger->mail() . '?subject=code: ' . $file_name . '">' . $logger->mail() . '%s</a>';
376 }
377 }
378
380 ilUtil::redirect("error.php");
381 });
382 }
383
388 protected function devmodeHandler()
389 {
390 global $ilLog;
391
392 switch (ERROR_HANDLER) {
393 case "TESTING":
394 return new ilTestingHandler();
395 case "PLAIN_TEXT":
396 return new ilPlainTextHandler();
397 case "PRETTY_PAGE":
398 return new PrettyPageHandler();
399 default:
400 if ($ilLog) {
401 $ilLog->write("Unknown or undefined error handler '" . ERROR_HANDLER . "'. "
402 . "Falling back to PrettyPageHandler.");
403 }
404 return new PrettyPageHandler();
405 }
406 }
407
412 protected function loggingHandler()
413 {
414 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
415 return new CallbackHandler(function ($exception, Inspector $inspector, Run $run) {
420 global $ilLog;
421
422 if (is_object($ilLog)) {
423 $message = $exception->getMessage() . ' in ' . $exception->getFile() . ":" . $exception->getLine();
424 $ilLog->error($exception->getCode() . ' ' . $message);
425 }
426
427 // Send to system logger
428 error_log($exception->getMessage());
429 });
430 }
431
432 public function handlePreWhoops($level, $message, $file, $line)
433 {
434 global $ilLog;
435
436 if ($level & error_reporting()) {
437
438 // correct-with-php5-removal JL start
439 // ignore all E_STRICT that are E_NOTICE (or nothing at all) in PHP7
440 if (version_compare(PHP_VERSION, '7.0.0', '<')) {
441 if ($level == E_STRICT) {
442 if (!stristr($message, "should be compatible") &&
443 !stristr($message, "should not be called statically") &&
444 !stristr($message, "should not be abstract")) {
445 return true;
446 };
447 }
448 }
449 // correct-with-php5-removal end
450
451 if (!$this->isDevmodeActive()) {
452 // log E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED only
453 if ($level >= E_USER_NOTICE) {
454 if ($ilLog) {
455 $severity = Whoops\Util\Misc::TranslateErrorCode($level);
456 $ilLog->write("\n\n" . $severity . " - " . $message . "\n" . $file . " - line " . $line . "\n");
457 }
458 return true;
459 }
460 }
461
462 // trigger whoops error handling
463 if ($this->whoops) {
464 return $this->whoops->handleError($level, $message, $file, $line);
465 }
466 }
467
468 return false;
469 }
470} // END class.ilErrorHandling
sprintf('%.4f', $callTime)
$_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
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'
Definition: bootstrap.php:27
global $lng
Definition: privfeed.php:17
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']