diff --git a/core/lib/Drupal/Core/Controller/ExceptionController.php b/core/lib/Drupal/Core/Controller/ExceptionController.php index c8da4bc38fd243aa7e65deb51b312967718ad02f..d79567c3ba938610a91e73e10df465721ae14bb6 100644 --- a/core/lib/Drupal/Core/Controller/ExceptionController.php +++ b/core/lib/Drupal/Core/Controller/ExceptionController.php @@ -317,13 +317,40 @@ public function on500Html(FlattenException $exception, Request $request) { $class = 'error'; // If error type is 'User notice' then treat it as debug information - // instead of an error message, see dd(). + // instead of an error message. + // @see debug() if ($error['%type'] == 'User notice') { $error['%type'] = 'Debug'; $class = 'status'; } - drupal_set_message(t('%type: !message in %function (line %line of %file).', $error), $class); + // Attempt to reduce verbosity by removing DRUPAL_ROOT from the file path + // in the message. This does not happen for (false) security. + $root_length = strlen(DRUPAL_ROOT); + if (substr($error['%file'], 0, $root_length) == DRUPAL_ROOT) { + $error['%file'] = substr($error['%file'], $root_length + 1); + } + // Should not translate the string to avoid errors producing more errors. + $message = String::format('%type: !message in %function (line %line of %file).', $error); + + // Check if verbose error reporting is on. + $error_level = $this->container->get('config.factory')->get('system.logging')->get('error_level'); + + if ($error_level == ERROR_REPORTING_DISPLAY_VERBOSE) { + $backtrace_exception = $exception; + while ($backtrace_exception->getPrevious()) { + $backtrace_exception = $backtrace_exception->getPrevious(); + } + $backtrace = $backtrace_exception->getTrace(); + // First trace is the error itself, already contained in the message. + // While the second trace is the error source and also contained in the + // message, the message doesn't contain argument values, so we output it + // once more in the backtrace. + array_shift($backtrace); + // Generate a backtrace containing only scalar argument values. + $message .= '
' . Error::formatFlattenedBacktrace($backtrace) . '
'; + } + drupal_set_message($message, $class, TRUE); } $page_content = array( diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php index 669cca03a89d9b0f4f6eebfd83611380b7b32e2a..e3b084f15f8ef90a0aded259fa08e468cf9fefea 100644 --- a/core/lib/Drupal/Core/Utility/Error.php +++ b/core/lib/Drupal/Core/Utility/Error.php @@ -185,4 +185,56 @@ public static function formatBacktrace(array $backtrace) { return $return; } + /** + * Formats a flattened backtrace into a plain-text string. + * + * The calls show values for scalar arguments and type names for complex ones. + * + * @param array $backtrace + * The backtrace of a Symfony\Component\Debug\Exception\FlattenException. + * + * @return string + * A plain-text line-wrapped string ready to be put inside
.
+   */
+  public static function formatFlattenedBacktrace(array $backtrace) {
+    $return = '';
+
+    foreach ($backtrace as $trace) {
+      $call = array('function' => '', 'args' => array());
+
+      if (isset($trace['class'])) {
+        $call['function'] = $trace['class'] . $trace['type'] . $trace['function'];
+      }
+      elseif (isset($trace['function'])) {
+        $call['function'] = $trace['function'];
+      }
+      else {
+        $call['function'] = 'main';
+      }
+
+      if (isset($trace['args'])) {
+        foreach ($trace['args'] as $arg) {
+          $type = $arg[0];
+          $value = $arg[1];
+          if ($type == 'array') {
+            $call['args'][] = '[' . ucfirst($type) . ']';
+          }
+          elseif ($type == 'null') {
+            $call['args'][] = strtoupper($type);
+          }
+          elseif ($type == 'boolean') {
+            $call['args'][] = $value ? 'TRUE' : 'FALSE';
+          }
+          else {
+            $call['args'][] = $value;
+          }
+        }
+      }
+
+      $return .= $call['function'] . '(' . implode(', ', $call['args']) . ")\n";
+    }
+
+    return $return;
+  }
+
 }