ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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{
42
48 var $FATAL;
49
56
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 if (self::$whoops_handlers_registered) {
103 // Only register whoops error handlers once.
104 return;
105 }
106
107 $ilRuntime = $this->getIlRuntime();
108 $this->whoops = $this->getWhoops();
109
110 $this->whoops->pushHandler(new ilDelegatingHandler($this));
111
112 if ($ilRuntime->shouldLogErrors()) {
113 $this->whoops->pushHandler($this->loggingHandler());
114 }
115
116 $this->whoops->register();
117
118 self::$whoops_handlers_registered = true;
119 }
120
128 public function getHandler() {
129 // TODO: * Use Whoops in production mode? This would require an appropriate
130 // error-handler.
131 // * Check for context? The current implementation e.g. would output HTML for
132 // for SOAP.
133
134 if ($this->isDevmodeActive()) {
135 return $this->devmodeHandler();
136 }
137
138 return $this->defaultHandler();
139 }
140
141 function getLastError()
142 {
143 return $this->error_obj;
144 }
145
151 function errorHandler($a_error_obj)
152 {
153 global $log;
154
155 // see bug 18499 (some calls to raiseError do not pass a code, which leads to security issues, if these calls
156 // are done due to permission checks)
157 if ($a_error_obj->getCode() == null)
158 {
159 $a_error_obj->code = $this->WARNING;
160 }
161
162 $this->error_obj =& $a_error_obj;
163//echo "-".$_SESSION["referer"]."-";
164 if ($_SESSION["failure"] && substr($a_error_obj->getMessage(), 0, 22) != "Cannot find this block")
165 {
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 {
179 if (DEVMODE == 1)
180 {
181 echo "<b>DEVMODE</b><br><br>";
182 echo "<b>Template Block not found.</b><br>";
183 echo "You used a template block in your code that is not available.<br>";
184 echo "Native Messge: <b>".$a_error_obj->getMessage()."</b><br>";
185 if (is_array($a_error_obj->backtrace))
186 {
187 echo "Backtrace:<br>";
188 foreach ($a_error_obj->backtrace as $b)
189 {
190 if ($b["function"] == "setCurrentBlock" &&
191 basename($b["file"]) != "class.ilTemplate.php")
192 {
193 echo "<b>";
194 }
195 echo "File: ".$b["file"].", ";
196 echo "Line: ".$b["line"].", ";
197 echo $b["function"]."()<br>";
198 if ($b["function"] == "setCurrentBlock" &&
199 basename($b["file"]) != "class.ilTemplate.php")
200 {
201 echo "</b>";
202 }
203 }
204 }
205 exit;
206 }
207 return;
208 }
209
210 if (is_object($log) and $log->enabled == true)
211 {
212 $log->write($a_error_obj->getMessage());
213 #$log->logError($a_error_obj->getCode(),$a_error_obj->getMessage());
214 }
215
216//echo $a_error_obj->getCode().":"; exit;
217 if ($a_error_obj->getCode() == $this->FATAL)
218 {
219 trigger_error(stripslashes($a_error_obj->getMessage()), E_USER_ERROR);
220 exit();
221 }
222
223 if ($a_error_obj->getCode() == $this->WARNING)
224 {
225 if ($this->DEBUG_ENV)
226 {
227 $message = $a_error_obj->getMessage();
228 }
229 else
230 {
231 $message = "Under Construction";
232 }
233
234 $_SESSION["failure"] = $message;
235
236 if (!defined("ILIAS_MODULE"))
237 {
238 ilUtil::redirect("error.php");
239 }
240 else
241 {
242 ilUtil::redirect("../error.php");
243 }
244 }
245
246 if ($a_error_obj->getCode() == $this->MESSAGE)
247 {
248 $_SESSION["failure"] = $a_error_obj->getMessage();
249 // save post vars to session in case of error
250 $_SESSION["error_post_vars"] = $_POST;
251
252 if (empty($_SESSION["referer"]))
253 {
254 $dirname = dirname($_SERVER["PHP_SELF"]);
255 $ilurl = parse_url(ILIAS_HTTP_PATH);
256 $subdir = substr(strstr($dirname,$ilurl["path"]),strlen($ilurl["path"]));
257 $updir = "";
258
259 if ($subdir)
260 {
261 $num_subdirs = substr_count($subdir,"/");
262
263 for ($i=1;$i<=$num_subdirs;$i++)
264 {
265 $updir .= "../";
266 }
267 }
268 ilUtil::redirect($updir."index.php");
269 }
270
271 /* #12104
272 check if already GET-Parameters exists in Referer-URI
273 if (substr($_SESSION["referer"],-4) == ".php")
274 {
275 $glue = "?";
276 }
277 else
278 {
279 // this did break permanent links (".html&")
280 $glue = "&";
281 }
282 */
283 ilUtil::redirect($_SESSION["referer"]);
284 }
285 }
286
287 function getMessage()
288 {
289 return $this->message;
290 }
291 function setMessage($a_message)
292 {
293 $this->message = $a_message;
294 }
295 function appendMessage($a_message)
296 {
297 if($this->getMessage())
298 {
299 $this->message .= "<br /> ";
300 }
301 $this->message .= $a_message;
302 }
303
313 public static function _ilErrorWriter($errno, $errstr, $errfile, $errline)
314 {
315 global $ilLog;
316
317 switch($errno)
318 {
319 case E_USER_ERROR:
320 $ilLog->write('PHP errror: '.$errstr.'. FATAL error on line '.$errline.' in file '.$errfile);
321 unset($ilLog);
322 exit(1);
323
324 case E_USER_WARNING:
325 $ilLog->write('PHP warning: ['.$errno.'] '.$errstr.' on line '.$errline.' in file '.$errfile);
326 break;
327
328 }
329 return true;
330 }
331
336 protected function getIlRuntime() {
337 return ilRuntime::getInstance();
338 }
339
344 protected function getWhoops() {
345 return new Run();
346 }
347
352 protected function isDevmodeActive() {
353 return DEVMODE == 1;
354 }
355
360 protected function defaultHandler() {
361 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
362 return new CallbackHandler(function($exception, Inspector $inspector, Run $run) {
363 global $lng;
364
365 require_once("Services/Logging/classes/error/class.ilLoggingErrorSettings.php");
366 require_once("Services/Logging/classes/error/class.ilLoggingErrorFileStorage.php");
367 require_once("Services/Utilities/classes/class.ilUtil.php");
368
369 $session_id = substr(session_id(),0,5);
370 $err_num = rand(1, 9999);
371 $file_name = $session_id."_".$err_num;
372
374 if(!empty($logger->folder())) {
375 $lwriter = new ilLoggingErrorFileStorage($inspector, $logger->folder(), $file_name);
376 $lwriter->write();
377 }
378
379 //Use $lng if defined or fallback to english
380 if($lng !== null) {
381 $lng->loadLanguageModule('logging');
382 $message = sprintf($lng->txt("log_error_message"), $file_name);
383
384 if($logger->mail()) {
385 $message .= " ".sprintf($lng->txt("log_error_message_send_mail"), $logger->mail(), $file_name, $logger->mail());
386 }
387 } else {
388 $message = "Error ".$file_name." occurred.";
389
390 if($logger->mail()) {
391 $message .= ' '.'Please send a mail to <a href="mailto:'.$logger->mail().'?subject=code: '.$file_name.'">'.$logger->mail().'%s</a>';
392 }
393 }
394
395 ilUtil::sendFailure($message, true);
396 ilUtil::redirect("error.php");
397 });
398 }
399
404 protected function devmodeHandler() {
405 global $ilLog;
406
407 switch (ERROR_HANDLER) {
408 case "TESTING":
409 return new ilTestingHandler();
410 case "PLAIN_TEXT":
411 return new ilPlainTextHandler();
412 case "PRETTY_PAGE":
413 return new PrettyPageHandler();
414 default:
415 if ($ilLog) {
416 $ilLog->write("Unknown or undefined error handler '".ERROR_HANDLER."'. "
417 ."Falling back to PrettyPageHandler.");
418 }
419 return new PrettyPageHandler();
420 }
421 }
422
427 protected function loggingHandler() {
428 // php7-todo : alex, 1.3.2016: Exception -> Throwable, please check
429 return new CallbackHandler(function($exception, Inspector $inspector, Run $run) {
434 global $ilLog;
435
436 if(is_object($ilLog)) {
437 $message = $exception->getMessage().' in '.$exception->getFile().":".$exception->getLine();
438 $ilLog->error($exception->getCode().' '.$message);
439 }
440
441 // Send to system logger
442 error_log($exception->getMessage());
443 });
444 }
445
446 public function handlePreWhoops($level, $message, $file, $line)
447 {
448 global $ilLog;
449
450 if ($level & error_reporting()) {
451
452 // correct-with-php5-removal JL start
453 // ignore all E_STRICT that are E_NOTICE (or nothing at all) in PHP7
454 if (version_compare(PHP_VERSION, '7.0.0', '<')) {
455 if ($level == E_STRICT) {
456 if (!stristr($message, "should be compatible") &&
457 !stristr($message, "should not be called statically") &&
458 !stristr($message, "should not be abstract")) {
459 return true;
460 };
461 }
462 }
463 // correct-with-php5-removal end
464
465 if (!$this->isDevmodeActive()) {
466 // log E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED only
467 if ($level >= E_USER_NOTICE) {
468
469 if ($ilLog) {
470 $severity = Whoops\Util\Misc::TranslateErrorCode($level);
471 $ilLog->write("\n\n".$severity." - ".$message."\n".$file." - line ".$line."\n");
472 }
473 return true;
474 }
475 }
476
477 // trigger whoops error handling
478 if($this->whoops)
479 {
480 return $this->whoops->handleError($level, $message, $file, $line);
481 }
482 }
483
484 return false;
485 }
486
487} // 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)
http redirect to other script
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
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']