2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Holds class PMA\libraries\Error
8 namespace PMA\libraries
;
17 class Error
extends Message
24 static public $errortype = array (
25 0 => 'Internal error',
27 E_WARNING
=> 'Warning',
28 E_PARSE
=> 'Parsing Error',
30 E_CORE_ERROR
=> 'Core Error',
31 E_CORE_WARNING
=> 'Core Warning',
32 E_COMPILE_ERROR
=> 'Compile Error',
33 E_COMPILE_WARNING
=> 'Compile Warning',
34 E_USER_ERROR
=> 'User Error',
35 E_USER_WARNING
=> 'User Warning',
36 E_USER_NOTICE
=> 'User Notice',
37 E_STRICT
=> 'Runtime Notice',
38 E_DEPRECATED
=> 'Deprecation Notice',
39 E_RECOVERABLE_ERROR
=> 'Catchable Fatal Error',
47 static public $errorlevel = array (
53 E_CORE_ERROR
=> 'error',
54 E_CORE_WARNING
=> 'error',
55 E_COMPILE_ERROR
=> 'error',
56 E_COMPILE_WARNING
=> 'error',
57 E_USER_ERROR
=> 'error',
58 E_USER_WARNING
=> 'error',
59 E_USER_NOTICE
=> 'notice',
61 E_DEPRECATED
=> 'notice',
62 E_RECOVERABLE_ERROR
=> 'error',
66 * The file in which the error occurred
73 * The line in which the error occurred
80 * Holds the backtrace for this error
84 protected $backtrace = array();
87 * Hide location of errors
89 protected $hide_location = false;
94 * @param integer $errno error number
95 * @param string $errstr error message
96 * @param string $errfile file
97 * @param integer $errline line
99 public function __construct($errno, $errstr, $errfile, $errline)
101 $this->setNumber($errno);
102 $this->setMessage($errstr, false);
103 $this->setFile($errfile);
104 $this->setLine($errline);
106 $backtrace = debug_backtrace();
107 // remove last three calls:
108 // debug_backtrace(), handleError() and addError()
109 $backtrace = array_slice($backtrace, 3);
111 $this->setBacktrace($backtrace);
115 * Process backtrace to avoid path disclossures, objects and so on
117 * @param array $backtrace backtrace
121 public static function processBacktrace($backtrace)
125 $members = array('line', 'function', 'class', 'type');
127 foreach ($backtrace as $idx => $step) {
128 /* Create new backtrace entry */
129 $result[$idx] = array();
131 /* Make path relative */
132 if (isset($step['file'])) {
133 $result[$idx]['file'] = self
::relPath($step['file']);
136 /* Store members we want */
137 foreach ($members as $name) {
138 if (isset($step[$name])) {
139 $result[$idx][$name] = $step[$name];
143 /* Store simplified args */
144 if (isset($step['args'])) {
145 foreach ($step['args'] as $key => $arg) {
146 $result[$idx]['args'][$key] = self
::getArg($arg, $step['function']);
155 * Toggles location hiding
157 * @param boolean $hide Whether to hide
161 public function setHideLocation($hide)
163 $this->hide_location
= $hide;
167 * sets PMA\libraries\Error::$_backtrace
169 * We don't store full arguments to avoid wakeup or memory problems.
171 * @param array $backtrace backtrace
175 public function setBacktrace($backtrace)
177 $this->backtrace
= self
::processBacktrace($backtrace);
181 * sets PMA\libraries\Error::$_line
183 * @param integer $line the line
187 public function setLine($line)
193 * sets PMA\libraries\Error::$_file
195 * @param string $file the file
199 public function setFile($file)
201 $this->file
= self
::relPath($file);
206 * returns unique PMA\libraries\Error::$hash, if not exists it will be created
208 * @return string PMA\libraries\Error::$hash
210 public function getHash()
213 $backtrace = serialize($this->getBacktrace());
214 } catch(Exception
$e) {
217 if ($this->hash
=== null) {
220 $this->getMessage() .
231 * returns PMA\libraries\Error::$_backtrace for first $count frames
232 * pass $count = -1 to get full backtrace.
233 * The same can be done by not passing $count at all.
235 * @param integer $count Number of stack frames.
237 * @return array PMA\libraries\Error::$_backtrace
239 public function getBacktrace($count = -1)
242 return array_slice($this->backtrace
, 0, $count);
244 return $this->backtrace
;
248 * returns PMA\libraries\Error::$file
250 * @return string PMA\libraries\Error::$file
252 public function getFile()
258 * returns PMA\libraries\Error::$line
260 * @return integer PMA\libraries\Error::$line
262 public function getLine()
268 * returns type of error
270 * @return string type of error
272 public function getType()
274 return self
::$errortype[$this->getNumber()];
278 * returns level of error
280 * @return string level of error
282 public function getLevel()
284 return self
::$errorlevel[$this->getNumber()];
288 * returns title prepared for HTML Title-Tag
290 * @return string HTML escaped and truncated title
292 public function getHtmlTitle()
294 return htmlspecialchars(
295 mb_substr($this->getTitle(), 0, 100)
300 * returns title for error
304 public function getTitle()
306 return $this->getType() . ': ' . $this->getMessage();
314 public function getBacktraceDisplay()
316 return self
::formatBacktrace(
317 $this->getBacktrace(),
324 * return formatted backtrace field
326 * @param array $backtrace Backtrace data
327 * @param string $separator Arguments separator to use
328 * @param string $lines Lines separator to use
330 * @return string formatted backtrace
332 public static function formatBacktrace($backtrace, $separator, $lines)
336 foreach ($backtrace as $step) {
337 if (isset($step['file']) && isset($step['line'])) {
338 $retval .= self
::relPath($step['file'])
339 . '#' . $step['line'] . ': ';
341 if (isset($step['class'])) {
342 $retval .= $step['class'] . $step['type'];
344 $retval .= self
::getFunctionCall($step, $separator);
352 * Formats function call in a backtrace
354 * @param array $step backtrace step
355 * @param string $separator Arguments separator to use
359 public static function getFunctionCall($step, $separator)
361 $retval = $step['function'] . '(';
362 if (isset($step['args'])) {
363 if (count($step['args']) > 1) {
364 $retval .= $separator;
365 foreach ($step['args'] as $arg) {
368 $retval .= ',' . $separator;
370 } elseif (count($step['args']) > 0) {
371 foreach ($step['args'] as $arg) {
381 * Get a single function argument
383 * if $function is one of include/require
384 * the $arg is converted to a relative path
386 * @param string $arg argument to process
387 * @param string $function function name
391 public static function getArg($arg, $function)
394 $include_functions = array(
400 $connect_functions = array(
404 'mysqli_real_connect',
409 if (in_array($function, $include_functions)) {
410 $retval .= self
::relPath($arg);
411 } elseif (in_array($function, $connect_functions)
412 && getType($arg) === 'string'
414 $retval .= getType($arg) . ' ********';
415 } elseif (is_scalar($arg)) {
416 $retval .= getType($arg) . ' '
417 . htmlspecialchars(var_export($arg, true));
418 } elseif (is_object($arg)) {
419 $retval .= '<Class:' . get_class($arg) . '>';
421 $retval .= getType($arg);
428 * Gets the error as string of HTML
432 public function getDisplay()
434 $this->isDisplayed(true);
435 $retval = '<div class="' . $this->getLevel() . '">';
436 if (! $this->isUserError()) {
437 $retval .= '<strong>' . $this->getType() . '</strong>';
438 $retval .= ' in ' . $this->getFile() . '#' . $this->getLine();
439 $retval .= "<br />\n";
441 $retval .= $this->getMessage();
442 if (! $this->isUserError()) {
443 $retval .= "<br />\n";
444 $retval .= "<br />\n";
445 $retval .= "<strong>Backtrace</strong><br />\n";
446 $retval .= "<br />\n";
447 $retval .= $this->getBacktraceDisplay();
455 * whether this error is a user error
459 public function isUserError()
461 return $this->hide_location ||
462 ($this->getNumber() & (E_USER_WARNING | E_USER_ERROR | E_USER_NOTICE
));
466 * return short relative path to phpMyAdmin basedir
468 * prevent path disclosure in error message,
469 * and make users feel safe to submit error reports
471 * @param string $path path to be shorten
473 * @return string shortened path
475 public static function relPath($path)
477 $dest = @realpath
($path);
479 /* Probably affected by open_basedir */
480 if ($dest === FALSE) {
481 return basename($path);
486 realpath(__DIR__
. DIRECTORY_SEPARATOR
. '..')
488 $Adest = explode(DIRECTORY_SEPARATOR
, $dest);
491 // && count ($Adest)>0 && count($Ahere)>0 )
492 while (implode(DIRECTORY_SEPARATOR
, $Adest) != implode(DIRECTORY_SEPARATOR
, $Ahere)) {
493 if (count($Ahere) > count($Adest)) {
495 $result .= DIRECTORY_SEPARATOR
. '..';
500 $path = $result . str_replace(implode(DIRECTORY_SEPARATOR
, $Adest), '', $dest);
502 DIRECTORY_SEPARATOR
. PATH_SEPARATOR
,