ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
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
5require_once 'Services/Environment/classes/class.ilRuntime.php';
6
19include_once 'PEAR.php';
20
21// TODO: This would clearly benefit from Autoloading...
22require_once("./Services/Exceptions/lib/Whoops/Run.php");
23require_once("./Services/Exceptions/lib/Whoops/Handler/HandlerInterface.php");
24require_once("./Services/Exceptions/lib/Whoops/Handler/Handler.php");
25require_once("./Services/Exceptions/lib/Whoops/Handler/CallbackHandler.php");
26require_once("./Services/Exceptions/lib/Whoops/Handler/PrettyPageHandler.php");
27require_once("./Services/Exceptions/lib/Whoops/Exception/Inspector.php");
28require_once("./Services/Exceptions/lib/Whoops/Exception/ErrorException.php");
29require_once("./Services/Exceptions/lib/Whoops/Exception/FrameCollection.php");
30require_once("./Services/Exceptions/lib/Whoops/Exception/Frame.php");
31require_once("./Services/Exceptions/lib/Whoops/Exception/Inspector.php");
32require_once("./Services/Exceptions/lib/Whoops/Exception/Formatter.php");
33require_once("./Services/Exceptions/lib/Whoops/Util/TemplateHelper.php");
34require_once("./Services/Exceptions/lib/Whoops/Util/Misc.php");
35
36require_once("Services/Exceptions/classes/class.ilDelegatingHandler.php");
37require_once("Services/Exceptions/classes/class.ilPlainTextHandler.php");
38require_once("Services/Exceptions/classes/class.ilTestingHandler.php");
39
40use Whoops\Run;
44
45class ilErrorHandling extends PEAR
46{
53
59 var $FATAL;
60
67
74
79 protected static $handlers_registered = false;
80
85 function ilErrorHandling()
86 {
87 $this->PEAR();
88
89 // init vars
90 $this->DEBUG_ENV = true;
91 $this->FATAL = 1;
92 $this->WARNING = 2;
93 $this->MESSAGE = 3;
94
95 $this->error_obj = false;
96
97 $this->initHandlers();
98 }
99
108 protected function initHandlers() {
109 if (self::$handlers_registered) {
110 // Only register whoops error handlers once.
111 return;
112 }
113
114 $ilRuntime = $this->getIlRuntime();
115 $whoops = $this->getWhoops();
116
117 $whoops->pushHandler(new ilDelegatingHandler($this));
118
119 if ($ilRuntime->shouldLogErrors()) {
120 $whoops->pushHandler($this->loggingHandler());
121 }
122
123 $whoops->register();
124
125 self::$handlers_registered = true;
126 }
127
135 public function getHandler() {
136 // TODO: * Use Whoops in production mode? This would require an appropriate
137 // error-handler.
138 // * Check for context? The current implementation e.g. would output HTML for
139 // for SOAP.
140
141 if ($this->isDevmodeActive()) {
142 return $this->devmodeHandler();
143 }
144
145 return $this->defaultHandler();
146 }
147
148 function getLastError()
149 {
150 return $this->error_obj;
151 }
152
158 function errorHandler($a_error_obj)
159 {
160 global $log;
161
162 // see bug 18499 (some calls to raiseError do not pass a code, which leads to security issues, if these calls
163 // are done due to permission checks)
164 if ($a_error_obj->getCode() == null)
165 {
166 $a_error_obj->code = $this->WARNING;
167 }
168
169 $this->error_obj =& $a_error_obj;
170//echo "-".$_SESSION["referer"]."-";
171 if ($_SESSION["failure"] && substr($a_error_obj->getMessage(), 0, 22) != "Cannot find this block")
172 {
173 $m = "Fatal Error: Called raise error two times.<br>".
174 "First error: ".$_SESSION["failure"].'<br>'.
175 "Last Error:". $a_error_obj->getMessage();
176 //return;
177 $log->write($m);
178 #$log->writeWarning($m);
179 #$log->logError($a_error_obj->getCode(), $m);
180 unset($_SESSION["failure"]);
181 die ($m);
182 }
183
184 if (substr($a_error_obj->getMessage(), 0, 22) == "Cannot find this block")
185 {
186 if (DEVMODE == 1)
187 {
188 echo "<b>DEVMODE</b><br><br>";
189 echo "<b>Template Block not found.</b><br>";
190 echo "You used a template block in your code that is not available.<br>";
191 echo "Native Messge: <b>".$a_error_obj->getMessage()."</b><br>";
192 if (is_array($a_error_obj->backtrace))
193 {
194 echo "Backtrace:<br>";
195 foreach ($a_error_obj->backtrace as $b)
196 {
197 if ($b["function"] == "setCurrentBlock" &&
198 basename($b["file"]) != "class.ilTemplate.php")
199 {
200 echo "<b>";
201 }
202 echo "File: ".$b["file"].", ";
203 echo "Line: ".$b["line"].", ";
204 echo $b["function"]."()<br>";
205 if ($b["function"] == "setCurrentBlock" &&
206 basename($b["file"]) != "class.ilTemplate.php")
207 {
208 echo "</b>";
209 }
210 }
211 }
212 exit;
213 }
214 return;
215 }
216
217 if (is_object($log) and $log->enabled == true)
218 {
219 $log->write($a_error_obj->getMessage());
220 #$log->logError($a_error_obj->getCode(),$a_error_obj->getMessage());
221 }
222
223//echo $a_error_obj->getCode().":"; exit;
224 if ($a_error_obj->getCode() == $this->FATAL)
225 {
226 trigger_error(stripslashes($a_error_obj->getMessage()), E_USER_ERROR);
227 exit();
228 }
229
230 if ($a_error_obj->getCode() == $this->WARNING)
231 {
232 if ($this->DEBUG_ENV)
233 {
234 $message = $a_error_obj->getMessage();
235 }
236 else
237 {
238 $message = "Under Construction";
239 }
240
241 $_SESSION["failure"] = $message;
242
243 if (!defined("ILIAS_MODULE"))
244 {
245 ilUtil::redirect("error.php");
246 }
247 else
248 {
249 ilUtil::redirect("../error.php");
250 }
251 }
252
253 if ($a_error_obj->getCode() == $this->MESSAGE)
254 {
255 $_SESSION["failure"] = $a_error_obj->getMessage();
256 // save post vars to session in case of error
257 $_SESSION["error_post_vars"] = $_POST;
258
259 if (empty($_SESSION["referer"]))
260 {
261 $dirname = dirname($_SERVER["PHP_SELF"]);
262 $ilurl = parse_url(ILIAS_HTTP_PATH);
263 $subdir = substr(strstr($dirname,$ilurl["path"]),strlen($ilurl["path"]));
264 $updir = "";
265
266 if ($subdir)
267 {
268 $num_subdirs = substr_count($subdir,"/");
269
270 for ($i=1;$i<=$num_subdirs;$i++)
271 {
272 $updir .= "../";
273 }
274 }
275 ilUtil::redirect($updir."index.php");
276 }
277
278 /* #12104
279 check if already GET-Parameters exists in Referer-URI
280 if (substr($_SESSION["referer"],-4) == ".php")
281 {
282 $glue = "?";
283 }
284 else
285 {
286 // this did break permanent links (".html&")
287 $glue = "&";
288 }
289 */
290 ilUtil::redirect($_SESSION["referer"]);
291 }
292 }
293
294 function getMessage()
295 {
296 return $this->message;
297 }
298 function setMessage($a_message)
299 {
300 $this->message = $a_message;
301 }
302 function appendMessage($a_message)
303 {
304 if($this->getMessage())
305 {
306 $this->message .= "<br /> ";
307 }
308 $this->message .= $a_message;
309 }
310
320 public static function _ilErrorWriter($errno, $errstr, $errfile, $errline)
321 {
322 global $ilLog;
323
324 switch($errno)
325 {
326 case E_USER_ERROR:
327 $ilLog->write('PHP errror: '.$errstr.'. FATAL error on line '.$errline.' in file '.$errfile);
328 unset($ilLog);
329 exit(1);
330
331 case E_USER_WARNING:
332 $ilLog->write('PHP warning: ['.$errno.'] '.$errstr.' on line '.$errline.' in file '.$errfile);
333 break;
334
335 }
336 return true;
337 }
338
343 protected function getIlRuntime() {
344 return ilRuntime::getInstance();
345 }
346
351 protected function getWhoops() {
352 return new Run();
353 }
354
359 protected function isDevmodeActive() {
360 return DEVMODE == 1;
361 }
362
367 protected function defaultHandler() {
368 return new CallbackHandler(function(Exception $exception, Inspector $inspector, Run $run) {
369 if ($exception instanceof \Whoops\Exception\ErrorException
370 and $exception->getCode() == E_ERROR) {
371 global $tpl, $lng, $tree;
372 $_SESSION["failure"] = $exception->getMessage();
373 include("error.php");
374 exit();
375 }
376
377 require_once("Services/Utilities/classes/class.ilUtil.php");
378 ilUtil::sendFailure($exception->getMessage(), true);
379 // many test installation have display_errors on, we do not need additional information in this case
380 // however in cases of warnings, whoops seems to get rid of these messages, but not in the case of fatals
381 // so we do not check for ini_get("display_errors"), but for headers_sent()
382 if (!headers_sent())
383 {
384 // #0019268, when not in setup
385 if (class_exists("ilInitialisation"))
386 {
387 ilInitialisation::initHTML();
388 global $tpl, $lng, $tree;
389 include("error.php"); // redirect will not display fatal error messages, since writing to session (sendFailure) will not work at this point
390 }
391 else // when in setup...
392 {
393 ilUtil::redirect("error.php");
394 }
395 }
396 });
397 }
398
403 protected function devmodeHandler() {
404 global $ilLog;
405
406 switch (ERROR_HANDLER) {
407 case "TESTING":
408 return new ilTestingHandler();
409 case "PLAIN_TEXT":
410 return new ilPlainTextHandler();
411 case "PRETTY_PAGE":
412 return new PrettyPageHandler();
413 default:
414 if ($ilLog) {
415 $ilLog->write("Unknown or undefined error handler '".ERROR_HANDLER."'. "
416 ."Falling back to PrettyPageHandler.");
417 }
418 return new PrettyPageHandler();
419 }
420 }
421
426 protected function loggingHandler() {
427 // TODO: remove this, when PHP 5.3 support is dropped. Make logMessageFor protected then as well.
428 $self = $this;
429 return new CallbackHandler(function(Exception $exception, Inspector $inspector, Run $run) use ($self) {
434 global $ilLog;
435
436 $log_message = $self->logMessageFor($exception, (bool)LOG_ERROR_TRACE);
437 if(is_object($ilLog)) {
438 // ak: default log level of write() is INFO, which is not appropriate -> set this to warning
439 // include_once './Services/Logging/classes/public/class.ilLogLevel.php'; // include may fail, see 19837 (maybe due to temp changed dir)
440 $ilLog->write($log_message, 300);
441 }
442
443 // Send to system logger
444 error_log($log_message);
445 });
446 }
447
457 public function logMessageFor(Exception $exception, $log_trace) {
458 assert('is_bool($log_trace)');
459 $prefix = "PHP Error: ";
460 if ($exception instanceof \Whoops\Exception\ErrorException) {
461 switch ($exception->getCode()) {
462 case E_ERROR:
463 case E_USER_ERROR:
464 $prefix = "PHP Fatal error: ";
465 }
466 }
467
468 $msg = $prefix.$exception->getMessage()." in ".$exception->getFile()." on line ".$exception->getLine();
469
470 if ($log_trace) {
471 $msg .= "\n".$exception->getTraceAsString();
472 }
473
474 return $msg;
475 }
476
477} // END class.ilErrorHandling
478?>
global $tpl
Definition: ilias.php:8
$_SESSION["AccountId"]
PEAR($error_class=null)
Constructor.
Definition: PEAR.php:170
Wrapper for Closures passed as handlers.
ilErrorHandling()
Constructor @access public.
logMessageFor(Exception $exception, $log_trace)
Get the error message to be logged.
errorHandler($a_error_obj)
defines what has to happen in case of error @access private
devmodeHandler()
Get the handler to be used in DEVMODE.
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.
initHandlers()
Initialize Error and Exception Handlers.
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.
$_POST['username']
Definition: cron.php:12
exit
Definition: login.php:54
Whoops - php errors for cool kids.
global $lng
Definition: privfeed.php:40
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']