2019-11-02 10:38:58 +01:00
< ? php
/**
* Error Protection API : WP_Fatal_Error_Handler class
*
* @ package WordPress
2020-05-06 17:23:38 +02:00
* @ since 5.2 . 0
2019-11-02 10:38:58 +01:00
*/
/**
* Core class used as the default shutdown handler for fatal errors .
*
* A drop - in 'fatal-error-handler.php' can be used to override the instance of this class and use a custom
* implementation for the fatal error handler that WordPress registers . The custom class should extend this class and
* can override its methods individually as necessary . The file must return the instance of the class that should be
* registered .
*
* @ since 5.2 . 0
*/
class WP_Fatal_Error_Handler {
/**
* Runs the shutdown handler .
*
* This method is registered via `register_shutdown_function()` .
*
* @ since 5.2 . 0
*/
public function handle () {
if ( defined ( 'WP_SANDBOX_SCRAPING' ) && WP_SANDBOX_SCRAPING ) {
return ;
}
2020-09-15 14:29:22 +02:00
// Do not trigger the fatal error handler while updates are being installed.
if ( wp_is_maintenance_mode () ) {
return ;
}
2019-11-02 10:38:58 +01:00
try {
// Bail if no error found.
$error = $this -> detect_error ();
if ( ! $error ) {
return ;
}
if ( ! isset ( $GLOBALS [ 'wp_locale' ] ) && function_exists ( 'load_default_textdomain' ) ) {
load_default_textdomain ();
}
2019-11-15 22:59:44 +01:00
$handled = false ;
2019-11-02 10:38:58 +01:00
if ( ! is_multisite () && wp_recovery_mode () -> is_initialized () ) {
2019-11-15 22:59:44 +01:00
$handled = wp_recovery_mode () -> handle_error ( $error );
2019-11-02 10:38:58 +01:00
}
// Display the PHP error template if headers not sent.
if ( is_admin () || ! headers_sent () ) {
2019-11-15 22:59:44 +01:00
$this -> display_error_template ( $error , $handled );
2019-11-02 10:38:58 +01:00
}
} catch ( Exception $e ) {
// Catch exceptions and remain silent.
}
}
/**
* Detects the error causing the crash if it should be handled .
*
* @ since 5.2 . 0
*
* @ return array | null Error that was triggered , or null if no error received or if the error should not be handled .
*/
protected function detect_error () {
$error = error_get_last ();
// No error, just skip the error handling code.
if ( null === $error ) {
return null ;
}
// Bail if this error should not be handled.
if ( ! $this -> should_handle_error ( $error ) ) {
return null ;
}
return $error ;
}
/**
* Determines whether we are dealing with an error that WordPress should handle
* in order to protect the admin backend against WSODs .
*
* @ since 5.2 . 0
*
* @ param array $error Error information retrieved from error_get_last () .
* @ return bool Whether WordPress should handle this error .
*/
protected function should_handle_error ( $error ) {
$error_types_to_handle = array (
E_ERROR ,
E_PARSE ,
E_USER_ERROR ,
E_COMPILE_ERROR ,
E_RECOVERABLE_ERROR ,
);
if ( isset ( $error [ 'type' ] ) && in_array ( $error [ 'type' ], $error_types_to_handle , true ) ) {
return true ;
}
/**
* Filters whether a given thrown error should be handled by the fatal error handler .
*
* This filter is only fired if the error is not already configured to be handled by WordPress core . As such ,
* it exclusively allows adding further rules for which errors should be handled , but not removing existing
* ones .
*
* @ since 5.2 . 0
*
* @ param bool $should_handle_error Whether the error should be handled by the fatal error handler .
* @ param array $error Error information retrieved from error_get_last () .
*/
return ( bool ) apply_filters ( 'wp_should_handle_php_error' , false , $error );
}
/**
* Displays the PHP error template and sends the HTTP status code , typically 500.
*
* A drop - in 'php-error.php' can be used as a custom template . This drop - in should control the HTTP status code and
* print the HTML markup indicating that a PHP error occurred . Note that this drop - in may potentially be executed
* very early in the WordPress bootstrap process , so any core functions used that are not part of
* `wp-includes/load.php` should be checked for before being called .
*
* If no such drop - in is available , this will call { @ see WP_Fatal_Error_Handler :: display_default_error_template ()} .
*
* @ since 5.2 . 0
2019-11-15 22:59:44 +01:00
* @ since 5.3 . 0 The `$handled` parameter was added .
2019-11-02 10:38:58 +01:00
*
2019-11-15 22:59:44 +01:00
* @ param array $error Error information retrieved from `error_get_last()` .
* @ param true | WP_Error $handled Whether Recovery Mode handled the fatal error .
2019-11-02 10:38:58 +01:00
*/
2019-11-15 22:59:44 +01:00
protected function display_error_template ( $error , $handled ) {
2019-11-02 10:38:58 +01:00
if ( defined ( 'WP_CONTENT_DIR' ) ) {
// Load custom PHP error template, if present.
$php_error_pluggable = WP_CONTENT_DIR . '/php-error.php' ;
if ( is_readable ( $php_error_pluggable ) ) {
require_once $php_error_pluggable ;
return ;
}
}
// Otherwise, display the default error template.
2019-11-15 22:59:44 +01:00
$this -> display_default_error_template ( $error , $handled );
2019-11-02 10:38:58 +01:00
}
/**
* Displays the default PHP error template .
*
* This method is called conditionally if no 'php-error.php' drop - in is available .
*
* It calls { @ see wp_die ()} with a message indicating that the site is experiencing technical difficulties and a
* login link to the admin backend . The { @ see 'wp_php_error_message' } and { @ see 'wp_php_error_args' } filters can
* be used to modify these parameters .
*
* @ since 5.2 . 0
2019-11-15 22:59:44 +01:00
* @ since 5.3 . 0 The `$handled` parameter was added .
2019-11-02 10:38:58 +01:00
*
2019-11-15 22:59:44 +01:00
* @ param array $error Error information retrieved from `error_get_last()` .
* @ param true | WP_Error $handled Whether Recovery Mode handled the fatal error .
2019-11-02 10:38:58 +01:00
*/
2019-11-15 22:59:44 +01:00
protected function display_default_error_template ( $error , $handled ) {
2019-11-02 10:38:58 +01:00
if ( ! function_exists ( '__' ) ) {
wp_load_translations_early ();
}
if ( ! function_exists ( 'wp_die' ) ) {
require_once ABSPATH . WPINC . '/functions.php' ;
}
if ( ! class_exists ( 'WP_Error' ) ) {
require_once ABSPATH . WPINC . '/class-wp-error.php' ;
}
2019-11-15 22:59:44 +01:00
if ( true === $handled && wp_is_recovery_mode () ) {
2020-12-10 14:06:04 +01:00
$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.' );
2021-07-23 11:58:50 +02:00
} elseif ( is_protected_endpoint () && wp_recovery_mode () -> is_initialized () ) {
2020-12-10 14:06:04 +01:00
$message = __ ( 'There has been a critical error on this website. Please check your site admin email inbox for instructions.' );
2019-11-02 10:38:58 +01:00
} else {
2020-12-10 14:06:04 +01:00
$message = __ ( 'There has been a critical error on this website.' );
2019-11-02 10:38:58 +01:00
}
2019-11-15 22:59:44 +01:00
$message = sprintf (
'<p>%s</p><p><a href="%s">%s</a></p>' ,
$message ,
2021-04-27 08:32:47 +02:00
/* translators: Documentation about troubleshooting. */
__ ( 'https://wordpress.org/support/article/faq-troubleshooting/' ),
__ ( 'Learn more about troubleshooting WordPress.' )
2019-11-15 22:59:44 +01:00
);
2019-11-02 10:38:58 +01:00
$args = array (
'response' => 500 ,
'exit' => false ,
);
/**
* Filters the message that the default PHP error template displays .
*
* @ since 5.2 . 0
*
* @ param string $message HTML error message to display .
* @ param array $error Error information retrieved from `error_get_last()` .
*/
$message = apply_filters ( 'wp_php_error_message' , $message , $error );
/**
* Filters the arguments passed to { @ see wp_die ()} for the default PHP error template .
*
* @ since 5.2 . 0
*
* @ param array $args Associative array of arguments passed to `wp_die()` . By default these contain a
* 'response' key , and optionally 'link_url' and 'link_text' keys .
* @ param array $error Error information retrieved from `error_get_last()` .
*/
$args = apply_filters ( 'wp_php_error_args' , $args , $error );
$wp_error = new WP_Error (
'internal_server_error' ,
$message ,
array (
'error' => $error ,
)
);
wp_die ( $wp_error , '' , $args );
}
}