/** * Log not-otherwise-specified errors, including HTTP 500. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process. */ public function onError(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $error = Error::decodeException($exception); $this->logger->get('php')->log($error['severity_level'], '%type: @message in %function (line %line of %file).', $error); $is_critical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500; if ($is_critical) { error_log(sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine())); } }
/** * Checks for special handling of errors inside Simpletest. * * @todo The $headers array appears to not actually get used at all in the * original code. It's quite possible that this entire method is now * vestigial and can be removed. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event */ public function on500(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $error = Error::decodeException($exception); $headers = array(); // When running inside the testing framework, we relay the errors // to the tested site by the way of HTTP headers. if (DRUPAL_TEST_IN_CHILD_SITE && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) { // $number does not use drupal_static as it should not be reset // as it uniquely identifies each PHP error. static $number = 0; $assertion = array($error['@message'], $error['%type'], array('function' => $error['%function'], 'file' => $error['%file'], 'line' => $error['%line'])); $headers['X-Drupal-Assertion-' . $number] = rawurlencode(serialize($assertion)); $number++; } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $io = new DrupalStyle($input, $output); $state = $this->getService('state'); $io->info($this->trans('commands.site.maintenance.messages.maintenance-on')); $io->info($this->trans('commands.update.entities.messages.start')); $state->set('system.maintenance_mode', true); try { $this->getService('entity.definition_update_manager')->applyUpdates(); } catch (EntityStorageException $e) { $variables = Error::decodeException($e); $io->info($this->trans('commands.update.entities.messages.error')); $io->info($variables); } $state->set('system.maintenance_mode', false); $io->info($this->trans('commands.update.entities.messages.end')); $this->getChain()->addCommand('cache:rebuild', ['cache' => 'all']); $io->info($this->trans('commands.site.maintenance.messages.maintenance-off')); }
/** * Handles any exception as a generic error page for JSON. * * @todo This should probably check the error reporting level. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process. */ protected function onJson(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $error = Error::decodeException($exception); // Display the message if the current error reporting level allows this type // of message to be displayed, $data = NULL; if (error_displayable($error) && ($message = $exception->getMessage())) { $data = ['message' => sprintf('A fatal error occurred: %s', $message)]; } $response = new JsonResponse($data, Response::HTTP_INTERNAL_SERVER_ERROR); if ($exception instanceof HttpExceptionInterface) { $response->setStatusCode($exception->getStatusCode()); $response->headers->add($exception->getHeaders()); } $event->setResponse($response); }
/** * Takes an Exception object and both saves and displays it. * * Pulls in additional information on the location triggering the exception. * * @param \Exception $exception * Object representing the exception. * @param bool $save * (optional) Whether to save the message in the migration's mapping table. * Set to FALSE in contexts where this doesn't make sense. */ protected function handleException(\Exception $exception, $save = TRUE) { $result = Error::decodeException($exception); $message = $result['@message'] . ' (' . $result['%file'] . ':' . $result['%line'] . ')'; if ($save) { $this->saveMessage($message); } $this->message->display($message, 'error'); }
/** * Handle exceptions. * * @see set_exception_handler */ protected function exceptionHandler($exception) { $backtrace = $exception->getTrace(); $verbose_backtrace = $backtrace; // Push on top of the backtrace the call that generated the exception. array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile())); $decoded_exception = Error::decodeException($exception); unset($decoded_exception['backtrace']); $message = SafeMarkup::format('%type: @message in %function (line %line of %file). <pre class="backtrace">@backtrace</pre>', $decoded_exception + array('@backtrace' => Error::formatBacktrace($verbose_backtrace))); $this->error($message, 'Uncaught exception', Error::getLastCaller($backtrace)); }
/** * Makes a subrequest to retrieve the default error page. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process * @param string $url * The path/url to which to make a subrequest for this error message. * @param int $status_code * The status code for the error being handled. */ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $status_code) { $request = $event->getRequest(); $exception = $event->getException(); if (!($url && $url[0] == '/')) { $url = $request->getBasePath() . '/' . $url; } $current_url = $request->getBasePath() . $request->getPathInfo(); if ($url != $request->getBasePath() . '/' && $url != $current_url) { if ($request->getMethod() === 'POST') { $sub_request = Request::create($url, 'POST', $this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code] + $request->request->all(), $request->cookies->all(), [], $request->server->all()); } else { $sub_request = Request::create($url, 'GET', $request->query->all() + $this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code], $request->cookies->all(), [], $request->server->all()); } try { // Persist the 'exception' attribute to the subrequest. $sub_request->attributes->set('exception', $request->attributes->get('exception')); // Persist the access result attribute to the subrequest, so that the // error page inherits the access result of the master request. $sub_request->attributes->set(AccessAwareRouterInterface::ACCESS_RESULT, $request->attributes->get(AccessAwareRouterInterface::ACCESS_RESULT)); // Carry over the session to the subrequest. if ($session = $request->getSession()) { $sub_request->setSession($session); } $response = $this->httpKernel->handle($sub_request, HttpKernelInterface::SUB_REQUEST); // Only 2xx responses should have their status code overridden; any // other status code should be passed on: redirects (3xx), error (5xx)… // @see https://www.drupal.org/node/2603788#comment-10504916 if ($response->isSuccessful()) { $response->setStatusCode($status_code); } // Persist any special HTTP headers that were set on the exception. if ($exception instanceof HttpExceptionInterface) { $response->headers->add($exception->getHeaders()); } $event->setResponse($response); } catch (\Exception $e) { // If an error happened in the subrequest we can't do much else. Instead, // just log it. The DefaultExceptionSubscriber will catch the original // exception and handle it normally. $error = Error::decodeException($e); $this->logger->log($error['severity_level'], '%type: @message in %function (line %line of %file).', $error); } } }
/** * Handle exceptions. * * @see set_exception_handler */ protected function exceptionHandler($exception) { require_once DRUPAL_ROOT . '/core/includes/errors.inc'; $backtrace = $exception->getTrace(); $verbose_backtrace = $backtrace; // Push on top of the backtrace the call that generated the exception. array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile())); // \Drupal\Core\Utility\Error::decodeException() runs the exception // message through \Drupal\Component\Utility\String::checkPlain(). $decoded_exception = Error::decodeException($exception); unset($decoded_exception['backtrace']); $message = String::format('%type: !message in %function (line %line of %file). <pre class="backtrace">!backtrace</pre>', $decoded_exception + array('!backtrace' => Error::formatBacktrace($verbose_backtrace))); $this->error($message, 'Uncaught exception', Error::getLastCaller($backtrace)); }
/** * Makes a subrequest to retrieve the default error page. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process * @param string $path * The path to which to make a subrequest for this error message. * @param int $status_code * The status code for the error being handled. */ protected function makeSubrequest(GetResponseForExceptionEvent $event, $path, $status_code) { $request = $event->getRequest(); // @todo Remove dependency on the internal _system_path attribute: // https://www.drupal.org/node/2293523. $system_path = $request->attributes->get('_system_path'); if ($path && $path != $system_path) { if ($request->getMethod() === 'POST') { $sub_request = Request::create($request->getBaseUrl() . '/' . $path, 'POST', ['destination' => $system_path, '_exception_statuscode' => $status_code] + $request->request->all(), $request->cookies->all(), [], $request->server->all()); } else { $sub_request = Request::create($request->getBaseUrl() . '/' . $path, 'GET', $request->query->all() + ['destination' => $system_path, '_exception_statuscode' => $status_code], $request->cookies->all(), [], $request->server->all()); } try { // Persist the 'exception' attribute to the subrequest. $sub_request->attributes->set('exception', $request->attributes->get('exception')); $response = $this->httpKernel->handle($sub_request, HttpKernelInterface::SUB_REQUEST); $response->setStatusCode($status_code); $event->setResponse($response); } catch (\Exception $e) { // If an error happened in the subrequest we can't do much else. Instead, // just log it. The DefaultExceptionSubscriber will catch the original // exception and handle it normally. $error = Error::decodeException($e); $this->logger->log($error['severity_level'], '%type: !message in %function (line %line of %file).', $error); } } }
/** * Makes a subrequest to retrieve the default error page. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process. * @param string $url * The path/url to which to make a subrequest for this error message. * @param int $status_code * The status code for the error being handled. */ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $status_code) { $request = $event->getRequest(); $exception = $event->getException(); try { // Reuse the exact same request (so keep the same URL, keep the access // result, the exception, et cetera) but override the routing information. // This means that aside from routing, this is identical to the master // request. This allows us to generate a response that is executed on // behalf of the master request, i.e. for the original URL. This is what // allows us to e.g. generate a 404 response for the original URL; if we // would execute a subrequest with the 404 route's URL, then it'd be // generated for *that* URL, not the *original* URL. $sub_request = clone $request; $sub_request->attributes->add($this->accessUnawareRouter->match($url)); // Add to query (GET) or request (POST) parameters: // - 'destination' (to ensure e.g. the login form in a 403 response // redirects to the original URL) // - '_exception_statuscode' $parameters = $sub_request->isMethod('GET') ? $sub_request->query : $sub_request->request; $parameters->add($this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code]); $response = $this->httpKernel->handle($sub_request, HttpKernelInterface::SUB_REQUEST); // Only 2xx responses should have their status code overridden; any // other status code should be passed on: redirects (3xx), error (5xx)… // @see https://www.drupal.org/node/2603788#comment-10504916 if ($response->isSuccessful()) { $response->setStatusCode($status_code); } // Persist any special HTTP headers that were set on the exception. if ($exception instanceof HttpExceptionInterface) { $response->headers->add($exception->getHeaders()); } $event->setResponse($response); } catch (\Exception $e) { // If an error happened in the subrequest we can't do much else. Instead, // just log it. The DefaultExceptionSubscriber will catch the original // exception and handle it normally. $error = Error::decodeException($e); $this->logger->log($error['severity_level'], '%type: @message in %function (line %line of %file).', $error); } }
/** * Makes a subrequest to retrieve the default error page. * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event * The event to process * @param string $url * The path/url to which to make a subrequest for this error message. * @param int $status_code * The status code for the error being handled. */ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $status_code) { $request = $event->getRequest(); if (!($url && $url[0] == '/')) { $url = $request->getBasePath() . '/' . $url; } $current_url = $request->getBasePath() . $request->getPathInfo(); if ($url != $request->getBasePath() . '/' && $url != $current_url) { if ($request->getMethod() === 'POST') { $sub_request = Request::create($url, 'POST', $this->drupalGetDestination() + ['_exception_statuscode' => $status_code] + $request->request->all(), $request->cookies->all(), [], $request->server->all()); } else { $sub_request = Request::create($url, 'GET', $request->query->all() + $this->drupalGetDestination() + ['_exception_statuscode' => $status_code], $request->cookies->all(), [], $request->server->all()); } try { // Persist the 'exception' attribute to the subrequest. $sub_request->attributes->set('exception', $request->attributes->get('exception')); // Carry over the session to the subrequest. if ($session = $request->getSession()) { $sub_request->setSession($session); } $response = $this->httpKernel->handle($sub_request, HttpKernelInterface::SUB_REQUEST); $response->setStatusCode($status_code); $event->setResponse($response); } catch (\Exception $e) { // If an error happened in the subrequest we can't do much else. Instead, // just log it. The DefaultExceptionSubscriber will catch the original // exception and handle it normally. $error = Error::decodeException($e); $this->logger->log($error['severity_level'], '%type: !message in %function (line %line of %file).', $error); } } }