WordPress.org

Make WordPress Core

Ticket #46047: 46047.2.diff

File 46047.2.diff, 17.2 KB (added by flixos90, 13 months ago)
  • src/wp-admin/includes/plugin.php

     
    468468 */
    469469function _get_dropins() {
    470470        $dropins = array(
    471                 'advanced-cache.php'   => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
    472                 'db.php'               => array( __( 'Custom database class.' ), true ), // auto on load
    473                 'db-error.php'         => array( __( 'Custom database error message.' ), true ), // auto on error
    474                 'install.php'          => array( __( 'Custom installation script.' ), true ), // auto on installation
    475                 'maintenance.php'      => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
    476                 'object-cache.php'     => array( __( 'External object cache.' ), true ), // auto on load
    477                 'php-error.php'        => array( __( 'Custom PHP error message.' ), true ), // auto on error
    478                 'shutdown-handler.php' => array( __( 'Custom PHP shutdown handler.' ), true ), // auto on error
     471                'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
     472                'db.php'                  => array( __( 'Custom database class.' ), true ), // auto on load
     473                'db-error.php'            => array( __( 'Custom database error message.' ), true ), // auto on error
     474                'install.php'             => array( __( 'Custom installation script.' ), true ), // auto on installation
     475                'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
     476                'object-cache.php'        => array( __( 'External object cache.' ), true ), // auto on load
     477                'php-error.php'           => array( __( 'Custom PHP error message.' ), true ), // auto on error
     478                'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // auto on error
    479479        );
    480480
    481481        if ( is_multisite() ) {
  • src/wp-includes/class-wp-fatal-error-handler.php

     
     1<?php
     2/**
     3 * Error Protection API: WP_Fatal_Error_Handler class
     4 *
     5 * @package WordPress
     6 * @since 5.1.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.1.0
     18 */
     19class 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.1.0
     27         */
     28        public function handle() {
     29                // Bail if WordPress executed successfully.
     30                if ( defined( 'WP_EXECUTION_SUCCEEDED' ) && WP_EXECUTION_SUCCEEDED ) {
     31                        return;
     32                }
     33
     34                try {
     35                        // Bail if no error found.
     36                        $error = $this->detect_error();
     37                        if ( ! $error ) {
     38                                return;
     39                        }
     40
     41                        // If the error was stored and thus the extension paused,
     42                        // redirect the request to catch multiple errors in one go.
     43                        if ( $this->store_error( $error ) ) {
     44                                $this->redirect_protected();
     45                        }
     46
     47                        // Display the PHP error template.
     48                        $this->display_error_template();
     49                } catch ( Exception $e ) {
     50                        // Catch exceptions and remain silent.
     51                }
     52        }
     53
     54        /**
     55         * Detects the error causing the crash if it should be handled.
     56         *
     57         * @since 5.1.0
     58         *
     59         * @return array|null Error that was triggered, or null if no error received or if the error should not be handled.
     60         */
     61        protected function detect_error() {
     62                $error = error_get_last();
     63
     64                // No error, just skip the error handling code.
     65                if ( null === $error ) {
     66                        return null;
     67                }
     68
     69                // Bail if this error should not be handled.
     70                if ( ! wp_should_handle_error( $error ) ) {
     71                        return null;
     72                }
     73
     74                return $error;
     75        }
     76
     77        /**
     78         * Stores the given error so that the extension causing it is paused.
     79         *
     80         * @since 5.1.0
     81         *
     82         * @param array $error Error that was triggered.
     83         * @return bool True if the error was stored successfully, false otherwise.
     84         */
     85        protected function store_error( $error ) {
     86                // Do not pause extensions if they only crash on a non-protected endpoint.
     87                if ( ! is_protected_endpoint() ) {
     88                        return false;
     89                }
     90
     91                return wp_record_extension_error( $error );
     92        }
     93
     94        /**
     95         * Redirects the current request to allow recovering multiple errors in one go.
     96         *
     97         * The redirection will only happen when on a protected endpoint.
     98         *
     99         * It must be ensured that this method is only called when an error actually occurred and will not occur on the
     100         * next request again. Otherwise it will create a redirect loop.
     101         *
     102         * @since 5.1.0
     103         */
     104        protected function redirect_protected() {
     105                // Do not redirect requests on non-protected endpoints.
     106                if ( ! is_protected_endpoint() ) {
     107                        return;
     108                }
     109
     110                // Pluggable is usually loaded after plugins, so we manually include it here for redirection functionality.
     111                if ( ! function_exists( 'wp_redirect' ) ) {
     112                        include ABSPATH . WPINC . '/pluggable.php';
     113                }
     114
     115                $scheme = is_ssl() ? 'https://' : 'http://';
     116
     117                $url = "{$scheme}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
     118                wp_redirect( $url );
     119                exit;
     120        }
     121
     122        /**
     123         * Displays the PHP error template and sends the HTTP status code, typically 500.
     124         *
     125         * A drop-in 'php-error.php' can be used as a custom template. This drop-in should control the HTTP status code and
     126         * print the HTML markup indicating that a PHP error occurred. Note that this drop-in may potentially be executed
     127         * very early in the WordPress bootstrap process, so any core functions used that are not part of
     128         * `wp-includes/load.php` should be checked for before being called.
     129         *
     130         * If no such drop-in is available, this will call {@see WP_Fatal_Error_Handler::display_default_error_template()}.
     131         *
     132         * @since 5.1.0
     133         */
     134        protected function display_error_template() {
     135                if ( defined( 'WP_CONTENT_DIR' ) ) {
     136                        // Load custom PHP error template, if present.
     137                        $php_error_pluggable = WP_CONTENT_DIR . '/php-error.php';
     138                        if ( is_readable( $php_error_pluggable ) ) {
     139                                require_once $php_error_pluggable;
     140                                return;
     141                        }
     142                }
     143
     144                // Otherwise, display the default error template.
     145                $this->display_default_error_template();
     146        }
     147
     148        /**
     149         * Displays the default PHP error template.
     150         *
     151         * This method is called conditionally if no 'php-error.php' drop-in is available.
     152         *
     153         * It calls {@see wp_die()} with a message indicating that the site is experiencing technical difficulties and a
     154         * login link to the admin backend. The {@see 'wp_php_error_message'} and {@see 'wp_php_error_args'} filters can
     155         * be used to modify these parameters.
     156         *
     157         * @since 5.1.0
     158         */
     159        protected function display_default_error_template() {
     160                if ( ! function_exists( '__' ) ) {
     161                        wp_load_translations_early();
     162                }
     163
     164                if ( ! function_exists( 'wp_die' ) ) {
     165                        require_once ABSPATH . WPINC . '/functions.php';
     166                }
     167
     168                $message = __( 'The site is experiencing technical difficulties.' );
     169
     170                $args = array(
     171                        'response' => 500,
     172                        'exit'     => false,
     173                );
     174                if ( function_exists( 'admin_url' ) ) {
     175                        $args['link_url']  = admin_url();
     176                        $args['link_text'] = __( 'Log into the admin backend to fix this.' );
     177                }
     178
     179                /**
     180                 * Filters the message that the default PHP error template displays.
     181                 *
     182                 * @since 5.1.0
     183                 *
     184                 * @param string $message HTML error message to display.
     185                 */
     186                $message = apply_filters( 'wp_php_error_message', $message );
     187
     188                /**
     189                 * Filters the arguments passed to {@see wp_die()} for the default PHP error template.
     190                 *
     191                 * @since 5.1.0
     192                 *
     193                 * @param array $args Associative array of arguments passed to `wp_die()`. By default these contain a
     194                 *                    'response' key, and optionally 'link_url' and 'link_text' keys.
     195                 */
     196                $args = apply_filters( 'wp_php_error_args', $args );
     197
     198                wp_die( $message, '', $args );
     199        }
     200}
  • src/wp-includes/class-wp-shutdown-handler.php

     
    1 <?php
    2 /**
    3  * Error Protection API: WP_Shutdown_Handler class
    4  *
    5  * @package WordPress
    6  * @since 5.1.0
    7  */
    8 
    9 /**
    10  * Core class used as the default shutdown handler.
    11  *
    12  * A drop-in 'shutdown-handler.php' can be used to override the instance of this class and use a custom implementation
    13  * for the shutdown handler that WordPress registers. The custom class should extend this class and can override its
    14  * methods individually as necessary. The file must return the instance of the class that should be registered.
    15  *
    16  * @since 5.1.0
    17  */
    18 class WP_Shutdown_Handler {
    19 
    20         /**
    21          * Runs the shutdown handler.
    22          *
    23          * This method is registered via `register_shutdown_function()`.
    24          *
    25          * @since 5.1.0
    26          */
    27         public function handle() {
    28                 // Bail if WordPress executed successfully.
    29                 if ( defined( 'WP_EXECUTION_SUCCEEDED' ) && WP_EXECUTION_SUCCEEDED ) {
    30                         return;
    31                 }
    32 
    33                 try {
    34                         // Bail if no error found.
    35                         $error = $this->detect_error();
    36                         if ( ! $error ) {
    37                                 return;
    38                         }
    39 
    40                         // If the error was stored and thus the extension paused,
    41                         // redirect the request to catch multiple errors in one go.
    42                         if ( $this->store_error( $error ) ) {
    43                                 $this->redirect_protected();
    44                         }
    45 
    46                         // Display the PHP error template.
    47                         $this->display_error_template();
    48                 } catch ( Exception $e ) {
    49                         // Catch exceptions and remain silent.
    50                 }
    51         }
    52 
    53         /**
    54          * Detects the error causing the crash if it should be handled.
    55          *
    56          * @since 5.1.0
    57          *
    58          * @return array|null Error that was triggered, or null if no error received or if the error should not be handled.
    59          */
    60         protected function detect_error() {
    61                 $error = error_get_last();
    62 
    63                 // No error, just skip the error handling code.
    64                 if ( null === $error ) {
    65                         return null;
    66                 }
    67 
    68                 // Bail if this error should not be handled.
    69                 if ( ! wp_should_handle_error( $error ) ) {
    70                         return null;
    71                 }
    72 
    73                 return $error;
    74         }
    75 
    76         /**
    77          * Stores the given error so that the extension causing it is paused.
    78          *
    79          * @since 5.1.0
    80          *
    81          * @param array $error Error that was triggered.
    82          * @return bool True if the error was stored successfully, false otherwise.
    83          */
    84         protected function store_error( $error ) {
    85                 // Do not pause extensions if they only crash on a non-protected endpoint.
    86                 if ( ! is_protected_endpoint() ) {
    87                         return false;
    88                 }
    89 
    90                 return wp_record_extension_error( $error );
    91         }
    92 
    93         /**
    94          * Redirects the current request to allow recovering multiple errors in one go.
    95          *
    96          * The redirection will only happen when on a protected endpoint.
    97          *
    98          * It must be ensured that this method is only called when an error actually occurred and will not occur on the
    99          * next request again. Otherwise it will create a redirect loop.
    100          *
    101          * @since 5.1.0
    102          */
    103         protected function redirect_protected() {
    104                 // Do not redirect requests on non-protected endpoints.
    105                 if ( ! is_protected_endpoint() ) {
    106                         return;
    107                 }
    108 
    109                 // Pluggable is usually loaded after plugins, so we manually include it here for redirection functionality.
    110                 if ( ! function_exists( 'wp_redirect' ) ) {
    111                         include ABSPATH . WPINC . '/pluggable.php';
    112                 }
    113 
    114                 $scheme = is_ssl() ? 'https://' : 'http://';
    115 
    116                 $url = "{$scheme}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
    117                 wp_redirect( $url );
    118                 exit;
    119         }
    120 
    121         /**
    122          * Displays the PHP error template and sends the HTTP status code, typically 500.
    123          *
    124          * A drop-in 'php-error.php' can be used as a custom template. This drop-in should control the HTTP status code and
    125          * print the HTML markup indicating that a PHP error occurred. Note that this drop-in may potentially be executed
    126          * very early in the WordPress bootstrap process, so any core functions used that are not part of
    127          * `wp-includes/load.php` should be checked for before being called.
    128          *
    129          * If no such drop-in is available, this will call {@see WP_Shutdown_Handler::display_default_error_template()}.
    130          *
    131          * @since 5.1.0
    132          */
    133         protected function display_error_template() {
    134                 if ( defined( 'WP_CONTENT_DIR' ) ) {
    135                         // Load custom PHP error template, if present.
    136                         $php_error_pluggable = WP_CONTENT_DIR . '/php-error.php';
    137                         if ( is_readable( $php_error_pluggable ) ) {
    138                                 require_once $php_error_pluggable;
    139                                 return;
    140                         }
    141                 }
    142 
    143                 // Otherwise, display the default error template.
    144                 $this->display_default_error_template();
    145         }
    146 
    147         /**
    148          * Displays the default PHP error template.
    149          *
    150          * This method is called conditionally if no 'php-error.php' drop-in is available.
    151          *
    152          * It calls {@see wp_die()} with a message indicating that the site is experiencing technical difficulties and a
    153          * login link to the admin backend. The {@see 'wp_php_error_message'} and {@see 'wp_php_error_args'} filters can
    154          * be used to modify these parameters.
    155          *
    156          * @since 5.1.0
    157          */
    158         protected function display_default_error_template() {
    159                 if ( ! function_exists( '__' ) ) {
    160                         wp_load_translations_early();
    161                 }
    162 
    163                 if ( ! function_exists( 'wp_die' ) ) {
    164                         require_once ABSPATH . WPINC . '/functions.php';
    165                 }
    166 
    167                 $message = __( 'The site is experiencing technical difficulties.' );
    168 
    169                 $args = array(
    170                         'response' => 500,
    171                         'exit'     => false,
    172                 );
    173                 if ( function_exists( 'admin_url' ) ) {
    174                         $args['link_url']  = admin_url();
    175                         $args['link_text'] = __( 'Log into the admin backend to fix this.' );
    176                 }
    177 
    178                 /**
    179                  * Filters the message that the default PHP error template displays.
    180                  *
    181                  * @since 5.1.0
    182                  *
    183                  * @param string $message HTML error message to display.
    184                  */
    185                 $message = apply_filters( 'wp_php_error_message', $message );
    186 
    187                 /**
    188                  * Filters the arguments passed to {@see wp_die()} for the default PHP error template.
    189                  *
    190                  * @since 5.1.0
    191                  *
    192                  * @param array $args Associative array of arguments passed to `wp_die()`. By default these contain a
    193                  *                    'response' key, and optionally 'link_url' and 'link_text' keys.
    194                  */
    195                 $args = apply_filters( 'wp_php_error_args', $args );
    196 
    197                 wp_die( $message, '', $args );
    198         }
    199 }
  • src/wp-includes/error-protection.php

     
    148148}
    149149
    150150/**
    151  * Registers the WordPress premature shutdown handler.
     151 * Registers the shutdown handler for fatal errors.
    152152 *
     153 * The handler will only be registered if {@see wp_is_fatal_error_handler_enabled()} returns true.
     154 *
    153155 * @since 5.1.0
    154156 */
    155 function wp_register_premature_shutdown_handler() {
     157function wp_register_fatal_error_handler() {
     158        if ( ! wp_is_fatal_error_handler_enabled() ) {
     159                return;
     160        }
     161
    156162        $handler = null;
    157         if ( defined( 'WP_CONTENT_DIR' ) && is_readable( WP_CONTENT_DIR . '/shutdown-handler.php' ) ) {
    158                 $handler = include WP_CONTENT_DIR . '/shutdown-handler.php';
     163        if ( defined( 'WP_CONTENT_DIR' ) && is_readable( WP_CONTENT_DIR . '/fatal-error-handler.php' ) ) {
     164                $handler = include WP_CONTENT_DIR . '/fatal-error-handler.php';
    159165        }
    160166
    161167        if ( ! is_object( $handler ) || ! is_callable( array( $handler, 'handle' ) ) ) {
    162                 $handler = new WP_Shutdown_Handler();
     168                $handler = new WP_Fatal_Error_Handler();
    163169        }
    164170
    165171        register_shutdown_function( array( $handler, 'handle' ) );
    166172}
     173
     174/**
     175 * Checks whether the fatal error handler is enabled.
     176 *
     177 * A constant `WP_DISABLE_FATAL_ERROR_HANDLER` can be set in `wp-config.php` to disable it, or alternatively the
     178 * {@see 'wp_fatal_error_handler_enabled'} filter can be used to modify the return value.
     179 *
     180 * @since 5.1.0
     181 *
     182 * @return bool True if the fatal error handler is enabled, false otherwise.
     183 */
     184function wp_is_fatal_error_handler_enabled() {
     185        $enabled = ! defined( 'WP_DISABLE_FATAL_ERROR_HANDLER' ) || ! WP_DISABLE_FATAL_ERROR_HANDLER;
     186
     187        /**
     188         * Filters whether the fatal error handler is enabled.
     189         *
     190         * @since 5.1.0
     191         *
     192         * @param bool $enabled True if the fatal error handler is enabled, false otherwise.
     193         */
     194        return apply_filters( 'wp_fatal_error_handler_enabled', $enabled );
     195}
  • src/wp-settings.php

     
    1818// Include files required for initialization.
    1919require( ABSPATH . WPINC . '/load.php' );
    2020require( ABSPATH . WPINC . '/class-wp-paused-extensions-storage.php' );
    21 require( ABSPATH . WPINC . '/class-wp-shutdown-handler.php' );
     21require( ABSPATH . WPINC . '/class-wp-fatal-error-handler.php' );
    2222require( ABSPATH . WPINC . '/error-protection.php' );
    2323require( ABSPATH . WPINC . '/default-constants.php' );
    2424require_once( ABSPATH . WPINC . '/plugin.php' );
    2525
    26 // Make sure we register the premature shutdown handler as soon as possible.
    27 wp_register_premature_shutdown_handler();
     26// Make sure we register the shutdown handler for fatal errors as soon as possible.
     27wp_register_fatal_error_handler();
    2828
    2929/*
    3030 * These can't be directly globalized in version.php. When updating,