[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> class-wp-fatal-error-handler.php (source)

   1  <?php
   2  /**
   3   * Error Protection API: WP_Fatal_Error_Handler class
   4   *
   5   * @package WordPress
   6   * @since 5.2.0
   7   */
   8  
   9  /**
  10   * Core class used as the default shutdown handler for fatal errors.
  11   *
  12   * A drop-in 'fatal-error-handler.php' can be used to override the instance of this class and use a custom
  13   * implementation for the fatal error handler that WordPress registers. The custom class should extend this class and
  14   * can override its methods individually as necessary. The file must return the instance of the class that should be
  15   * registered.
  16   *
  17   * @since 5.2.0
  18   */
  19  class WP_Fatal_Error_Handler {
  20  
  21      /**
  22       * Runs the shutdown handler.
  23       *
  24       * This method is registered via `register_shutdown_function()`.
  25       *
  26       * @since 5.2.0
  27       */
  28  	public function handle() {
  29          if ( defined( 'WP_SANDBOX_SCRAPING' ) && WP_SANDBOX_SCRAPING ) {
  30              return;
  31          }
  32  
  33          // Do not trigger the fatal error handler while updates are being installed.
  34          if ( wp_is_maintenance_mode() ) {
  35              return;
  36          }
  37  
  38          try {
  39              // Bail if no error found.
  40              $error = $this->detect_error();
  41              if ( ! $error ) {
  42                  return;
  43              }
  44  
  45              if ( ! isset( $GLOBALS['wp_locale'] ) && function_exists( 'load_default_textdomain' ) ) {
  46                  load_default_textdomain();
  47              }
  48  
  49              $handled = false;
  50  
  51              if ( ! is_multisite() && wp_recovery_mode()->is_initialized() ) {
  52                  $handled = wp_recovery_mode()->handle_error( $error );
  53              }
  54  
  55              // Display the PHP error template if headers not sent.
  56              if ( is_admin() || ! headers_sent() ) {
  57                  $this->display_error_template( $error, $handled );
  58              }
  59          } catch ( Exception $e ) {
  60              // Catch exceptions and remain silent.
  61          }
  62      }
  63  
  64      /**
  65       * Detects the error causing the crash if it should be handled.
  66       *
  67       * @since 5.2.0
  68       *
  69       * @return array|null Error information returned by `error_get_last()`, or null
  70       *                    if none was recorded or the error should not be handled.
  71       */
  72  	protected function detect_error() {
  73          $error = error_get_last();
  74  
  75          // No error, just skip the error handling code.
  76          if ( null === $error ) {
  77              return null;
  78          }
  79  
  80          // Bail if this error should not be handled.
  81          if ( ! $this->should_handle_error( $error ) ) {
  82              return null;
  83          }
  84  
  85          return $error;
  86      }
  87  
  88      /**
  89       * Determines whether we are dealing with an error that WordPress should handle
  90       * in order to protect the admin backend against WSODs.
  91       *
  92       * @since 5.2.0
  93       *
  94       * @param array $error Error information retrieved from `error_get_last()`.
  95       * @return bool Whether WordPress should handle this error.
  96       */
  97  	protected function should_handle_error( $error ) {
  98          $error_types_to_handle = array(
  99              E_ERROR,
 100              E_PARSE,
 101              E_USER_ERROR,
 102              E_COMPILE_ERROR,
 103              E_RECOVERABLE_ERROR,
 104          );
 105  
 106          if ( isset( $error['type'] ) && in_array( $error['type'], $error_types_to_handle, true ) ) {
 107              return true;
 108          }
 109  
 110          /**
 111           * Filters whether a given thrown error should be handled by the fatal error handler.
 112           *
 113           * This filter is only fired if the error is not already configured to be handled by WordPress core. As such,
 114           * it exclusively allows adding further rules for which errors should be handled, but not removing existing
 115           * ones.
 116           *
 117           * @since 5.2.0
 118           *
 119           * @param bool  $should_handle_error Whether the error should be handled by the fatal error handler.
 120           * @param array $error               Error information retrieved from `error_get_last()`.
 121           */
 122          return (bool) apply_filters( 'wp_should_handle_php_error', false, $error );
 123      }
 124  
 125      /**
 126       * Displays the PHP error template and sends the HTTP status code, typically 500.
 127       *
 128       * A drop-in 'php-error.php' can be used as a custom template. This drop-in should control the HTTP status code and
 129       * print the HTML markup indicating that a PHP error occurred. Note that this drop-in may potentially be executed
 130       * very early in the WordPress bootstrap process, so any core functions used that are not part of
 131       * `wp-includes/load.php` should be checked for before being called.
 132       *
 133       * If no such drop-in is available, this will call {@see WP_Fatal_Error_Handler::display_default_error_template()}.
 134       *
 135       * @since 5.2.0
 136       * @since 5.3.0 The `$handled` parameter was added.
 137       *
 138       * @param array         $error   Error information retrieved from `error_get_last()`.
 139       * @param true|WP_Error $handled Whether Recovery Mode handled the fatal error.
 140       */
 141  	protected function display_error_template( $error, $handled ) {
 142          if ( defined( 'WP_CONTENT_DIR' ) ) {
 143              // Load custom PHP error template, if present.
 144              $php_error_pluggable = WP_CONTENT_DIR . '/php-error.php';
 145              if ( is_readable( $php_error_pluggable ) ) {
 146                  require_once $php_error_pluggable;
 147  
 148                  return;
 149              }
 150          }
 151  
 152          // Otherwise, display the default error template.
 153          $this->display_default_error_template( $error, $handled );
 154      }
 155  
 156      /**
 157       * Displays the default PHP error template.
 158       *
 159       * This method is called conditionally if no 'php-error.php' drop-in is available.
 160       *
 161       * It calls {@see wp_die()} with a message indicating that the site is experiencing technical difficulties and a
 162       * login link to the admin backend. The {@see 'wp_php_error_message'} and {@see 'wp_php_error_args'} filters can
 163       * be used to modify these parameters.
 164       *
 165       * @since 5.2.0
 166       * @since 5.3.0 The `$handled` parameter was added.
 167       *
 168       * @param array         $error   Error information retrieved from `error_get_last()`.
 169       * @param true|WP_Error $handled Whether Recovery Mode handled the fatal error.
 170       */
 171  	protected function display_default_error_template( $error, $handled ) {
 172          if ( ! function_exists( '__' ) ) {
 173              wp_load_translations_early();
 174          }
 175  
 176          if ( ! function_exists( 'wp_die' ) ) {
 177              require_once  ABSPATH . WPINC . '/functions.php';
 178          }
 179  
 180          if ( ! class_exists( 'WP_Error' ) ) {
 181              require_once  ABSPATH . WPINC . '/class-wp-error.php';
 182          }
 183  
 184          if ( true === $handled && wp_is_recovery_mode() ) {
 185              $message = __( 'There has been a critical error on this website, putting it in recovery mode. Please check the Themes and Plugins screens for more details. If you just installed or updated a theme or plugin, check the relevant page for that first.' );
 186          } elseif ( is_protected_endpoint() && wp_recovery_mode()->is_initialized() ) {
 187              $message = __( 'There has been a critical error on this website. Please check your site admin email inbox for instructions.' );
 188          } else {
 189              $message = __( 'There has been a critical error on this website.' );
 190          }
 191  
 192          $message = sprintf(
 193              '<p>%s</p><p><a href="%s">%s</a></p>',
 194              $message,
 195              /* translators: Documentation about troubleshooting. */
 196              __( 'https://wordpress.org/support/article/faq-troubleshooting/' ),
 197              __( 'Learn more about troubleshooting WordPress.' )
 198          );
 199  
 200          $args = array(
 201              'response' => 500,
 202              'exit'     => false,
 203          );
 204  
 205          /**
 206           * Filters the message that the default PHP error template displays.
 207           *
 208           * @since 5.2.0
 209           *
 210           * @param string $message HTML error message to display.
 211           * @param array  $error   Error information retrieved from `error_get_last()`.
 212           */
 213          $message = apply_filters( 'wp_php_error_message', $message, $error );
 214  
 215          /**
 216           * Filters the arguments passed to {@see wp_die()} for the default PHP error template.
 217           *
 218           * @since 5.2.0
 219           *
 220           * @param array $args Associative array of arguments passed to `wp_die()`. By default these contain a
 221           *                    'response' key, and optionally 'link_url' and 'link_text' keys.
 222           * @param array $error Error information retrieved from `error_get_last()`.
 223           */
 224          $args = apply_filters( 'wp_php_error_args', $args, $error );
 225  
 226          $wp_error = new WP_Error(
 227              'internal_server_error',
 228              $message,
 229              array(
 230                  'error' => $error,
 231              )
 232          );
 233  
 234          wp_die( $wp_error, '', $args );
 235      }
 236  }


Generated: Tue Jun 28 01:00:03 2022 Cross-referenced by PHPXref 0.7.1