PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/web/core/lib/Drupal/Core/Utility/Error.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 184 lines | 93 code | 24 blank | 67 comment | 16 complexity | 291feaa7fac5ef010b522cdd7be577bb MD5 | raw file
  1. <?php
  2. namespace Drupal\Core\Utility;
  3. use Drupal\Component\Render\FormattableMarkup;
  4. use Drupal\Component\Utility\Xss;
  5. use Drupal\Core\Database\Database;
  6. use Drupal\Core\Database\DatabaseExceptionWrapper;
  7. use Drupal\Core\Database\Log;
  8. /**
  9. * Drupal error utility class.
  10. */
  11. class Error {
  12. /**
  13. * The error severity level.
  14. *
  15. * @var int
  16. */
  17. const ERROR = 3;
  18. /**
  19. * An array of ignored functions.
  20. *
  21. * @var array
  22. */
  23. protected static $ignoredFunctions = ['debug', '_drupal_error_handler', '_drupal_exception_handler'];
  24. /**
  25. * Decodes an exception and retrieves the correct caller.
  26. *
  27. * @param \Exception|\Throwable $exception
  28. * The exception object that was thrown.
  29. *
  30. * @return array
  31. * An error in the format expected by _drupal_log_error().
  32. */
  33. public static function decodeException($exception) {
  34. $message = $exception->getMessage();
  35. $backtrace = $exception->getTrace();
  36. // Add the line throwing the exception to the backtrace.
  37. array_unshift($backtrace, ['line' => $exception->getLine(), 'file' => $exception->getFile()]);
  38. // For PDOException errors, we try to return the initial caller,
  39. // skipping internal functions of the database layer.
  40. if ($exception instanceof \PDOException || $exception instanceof DatabaseExceptionWrapper) {
  41. $driver_namespace = Database::getConnectionInfo()['default']['namespace'];
  42. $backtrace = Log::removeDatabaseEntries($backtrace, $driver_namespace);
  43. if (isset($exception->query_string, $exception->args)) {
  44. $message .= ": " . $exception->query_string . "; " . print_r($exception->args, TRUE);
  45. }
  46. }
  47. $caller = static::getLastCaller($backtrace);
  48. return [
  49. '%type' => get_class($exception),
  50. // The standard PHP exception handler considers that the exception message
  51. // is plain-text. We mimic this behavior here.
  52. '@message' => $message,
  53. '%function' => $caller['function'],
  54. '%file' => $caller['file'],
  55. '%line' => $caller['line'],
  56. 'severity_level' => static::ERROR,
  57. 'backtrace' => $backtrace,
  58. '@backtrace_string' => $exception->getTraceAsString(),
  59. 'exception' => $exception,
  60. ];
  61. }
  62. /**
  63. * Renders an exception error message without further exceptions.
  64. *
  65. * @param \Exception|\Throwable $exception
  66. * The exception object that was thrown.
  67. *
  68. * @return string
  69. * An error message.
  70. */
  71. public static function renderExceptionSafe($exception) {
  72. $decode = static::decodeException($exception);
  73. $backtrace = $decode['backtrace'];
  74. unset($decode['backtrace'], $decode['exception']);
  75. // Remove 'main()'.
  76. array_shift($backtrace);
  77. // Even though it is possible that this method is called on a public-facing
  78. // site, it is only called when the exception handler itself threw an
  79. // exception, which normally means that a code change caused the system to
  80. // no longer function correctly (as opposed to a user-triggered error), so
  81. // we assume that it is safe to include a verbose backtrace.
  82. $decode['@backtrace'] = Error::formatBacktrace($backtrace);
  83. return new FormattableMarkup('%type: @message in %function (line %line of %file). <pre class="backtrace">@backtrace</pre>', $decode);
  84. }
  85. /**
  86. * Gets the last caller from a backtrace.
  87. *
  88. * @param array $backtrace
  89. * A standard PHP backtrace. Passed by reference.
  90. *
  91. * @return array
  92. * An associative array with keys 'file', 'line' and 'function'.
  93. */
  94. public static function getLastCaller(array &$backtrace) {
  95. // Errors that occur inside PHP internal functions do not generate
  96. // information about file and line. Ignore the ignored functions.
  97. while (($backtrace && !isset($backtrace[0]['line'])) ||
  98. (isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], static::$ignoredFunctions))) {
  99. array_shift($backtrace);
  100. }
  101. // The first trace is the call itself.
  102. // It gives us the line and the file of the last call.
  103. $call = $backtrace[0];
  104. // The second call gives us the function where the call originated.
  105. if (isset($backtrace[1])) {
  106. if (isset($backtrace[1]['class'])) {
  107. $call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
  108. }
  109. else {
  110. $call['function'] = $backtrace[1]['function'] . '()';
  111. }
  112. }
  113. else {
  114. $call['function'] = 'main()';
  115. }
  116. return $call;
  117. }
  118. /**
  119. * Formats a backtrace into a plain-text string.
  120. *
  121. * The calls show values for scalar arguments and type names for complex ones.
  122. *
  123. * @param array $backtrace
  124. * A standard PHP backtrace.
  125. *
  126. * @return string
  127. * A plain-text line-wrapped string ready to be put inside <pre>.
  128. */
  129. public static function formatBacktrace(array $backtrace) {
  130. $return = '';
  131. foreach ($backtrace as $trace) {
  132. $call = ['function' => '', 'args' => []];
  133. if (isset($trace['class'])) {
  134. $call['function'] = $trace['class'] . $trace['type'] . $trace['function'];
  135. }
  136. elseif (isset($trace['function'])) {
  137. $call['function'] = $trace['function'];
  138. }
  139. else {
  140. $call['function'] = 'main';
  141. }
  142. if (isset($trace['args'])) {
  143. foreach ($trace['args'] as $arg) {
  144. if (is_scalar($arg)) {
  145. $call['args'][] = is_string($arg) ? '\'' . Xss::filter($arg) . '\'' : $arg;
  146. }
  147. else {
  148. $call['args'][] = ucfirst(gettype($arg));
  149. }
  150. }
  151. }
  152. $line = '';
  153. if (isset($trace['line'])) {
  154. $line = " (Line: {$trace['line']})";
  155. }
  156. $return .= $call['function'] . '(' . implode(', ', $call['args']) . ")$line\n";
  157. }
  158. return $return;
  159. }
  160. }