Translated using Weblate (Chinese (Traditional))
[phpmyadmin.git] / libraries / Error.php
blob879be92c643fe9551a9d269fa732ec3f3a571549
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Holds class PMA\libraries\Error
6 * @package PhpMyAdmin
7 */
8 namespace PMA\libraries;
10 use Exception;
12 /**
13 * a single error
15 * @package PhpMyAdmin
17 class Error extends Message
19 /**
20 * Error types
22 * @var array
24 static public $errortype = array (
25 0 => 'Internal error',
26 E_ERROR => 'Error',
27 E_WARNING => 'Warning',
28 E_PARSE => 'Parsing Error',
29 E_NOTICE => 'Notice',
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',
42 /**
43 * Error levels
45 * @var array
47 static public $errorlevel = array (
48 0 => 'error',
49 E_ERROR => 'error',
50 E_WARNING => 'error',
51 E_PARSE => 'error',
52 E_NOTICE => 'notice',
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',
60 E_STRICT => 'notice',
61 E_DEPRECATED => 'notice',
62 E_RECOVERABLE_ERROR => 'error',
65 /**
66 * The file in which the error occurred
68 * @var string
70 protected $file = '';
72 /**
73 * The line in which the error occurred
75 * @var integer
77 protected $line = 0;
79 /**
80 * Holds the backtrace for this error
82 * @var array
84 protected $backtrace = array();
86 /**
87 * Hide location of errors
89 protected $hide_location = false;
91 /**
92 * Constructor
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
119 * @return array
121 public static function processBacktrace($backtrace)
123 $result = array();
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']);
151 return $result;
155 * Toggles location hiding
157 * @param boolean $hide Whether to hide
159 * @return void
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
173 * @return void
175 public function setBacktrace($backtrace)
177 $this->backtrace = self::processBacktrace($backtrace);
181 * sets PMA\libraries\Error::$_line
183 * @param integer $line the line
185 * @return void
187 public function setLine($line)
189 $this->line = $line;
193 * sets PMA\libraries\Error::$_file
195 * @param string $file the file
197 * @return void
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()
212 try {
213 $backtrace = serialize($this->getBacktrace());
214 } catch(Exception $e) {
215 $backtrace = '';
217 if ($this->hash === null) {
218 $this->hash = md5(
219 $this->getNumber() .
220 $this->getMessage() .
221 $this->getFile() .
222 $this->getLine() .
223 $backtrace
227 return $this->hash;
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)
241 if ($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()
254 return $this->file;
258 * returns PMA\libraries\Error::$line
260 * @return integer PMA\libraries\Error::$line
262 public function getLine()
264 return $this->line;
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
302 * @return string
304 public function getTitle()
306 return $this->getType() . ': ' . $this->getMessage();
310 * Get HTML backtrace
312 * @return string
314 public function getBacktraceDisplay()
316 return self::formatBacktrace(
317 $this->getBacktrace(),
318 "<br />\n",
319 "<br />\n"
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)
334 $retval = '';
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);
345 $retval .= $lines;
348 return $retval;
352 * Formats function call in a backtrace
354 * @param array $step backtrace step
355 * @param string $separator Arguments separator to use
357 * @return string
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) {
366 $retval .= "\t";
367 $retval .= $arg;
368 $retval .= ',' . $separator;
370 } elseif (count($step['args']) > 0) {
371 foreach ($step['args'] as $arg) {
372 $retval .= $arg;
376 $retval .= ')';
377 return $retval;
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
389 * @return string
391 public static function getArg($arg, $function)
393 $retval = '';
394 $include_functions = array(
395 'include',
396 'include_once',
397 'require',
398 'require_once',
400 $connect_functions = array(
401 'mysql_connect',
402 'mysql_pconnect',
403 'mysqli_connect',
404 'mysqli_real_connect',
405 'connect',
406 '_realConnect'
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) . '>';
420 } else {
421 $retval .= getType($arg);
424 return $retval;
428 * Gets the error as string of HTML
430 * @return string
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();
449 $retval .= '</div>';
451 return $retval;
455 * whether this error is a user error
457 * @return boolean
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);
484 $Ahere = explode(
485 DIRECTORY_SEPARATOR,
486 realpath(__DIR__ . DIRECTORY_SEPARATOR . '..')
488 $Adest = explode(DIRECTORY_SEPARATOR, $dest);
490 $result = '.';
491 // && count ($Adest)>0 && count($Ahere)>0 )
492 while (implode(DIRECTORY_SEPARATOR, $Adest) != implode(DIRECTORY_SEPARATOR, $Ahere)) {
493 if (count($Ahere) > count($Adest)) {
494 array_pop($Ahere);
495 $result .= DIRECTORY_SEPARATOR . '..';
496 } else {
497 array_pop($Adest);
500 $path = $result . str_replace(implode(DIRECTORY_SEPARATOR, $Adest), '', $dest);
501 return str_replace(
502 DIRECTORY_SEPARATOR . PATH_SEPARATOR,
503 DIRECTORY_SEPARATOR,
504 $path