WordPress.org

Make WordPress Core

Changeset 41805


Ignore:
Timestamp:
10/10/17 05:26:53 (3 months ago)
Author:
westonruter
Message:

File Editor: Increase robustness of fatal error checking when saving PHP file edits.

  • Increase PHP execution time limit prior to issuing loopback requests where are themselves given timeouts to ensure PHP file can be reverted.
  • Output scrape messages on success and failure so that absence of either can also be flagged as an error condition.
  • Forward browser's HTTP Basic Auth credentials in loopback requests to admin and home URL.
  • Display more helpful message when loopback request fails.

Amends [41721].
See #21622.
Fixes #42102.

Location:
trunk/src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r41721 r41805  
    487487        ); 
    488488 
    489         $needle = "###### begin_scraped_error:$scrape_key ######"; 
     489        // Include Basic auth in loopback requests. 
     490        if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) { 
     491            $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) ); 
     492        } 
     493 
     494        // Make sure PHP process doesn't die before loopback requests complete. 
     495        @set_time_limit( 300 ); 
     496 
     497        // Time to wait for loopback requests to finish. 
     498        $timeout = 100; 
     499 
     500        $needle_start = "###### wp_scraping_result_start:$scrape_key ######"; 
     501        $needle_end = "###### wp_scraping_result_end:$scrape_key ######"; 
    490502 
    491503        // Attempt loopback request to editor to see if user just whitescreened themselves. 
     
    504516        } 
    505517        $url = add_query_arg( $scrape_params, $url ); 
    506         $r = wp_remote_get( $url, compact( 'cookies', 'headers' ) ); 
     518        $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) ); 
    507519        $body = wp_remote_retrieve_body( $r ); 
    508         $error_position = strpos( $body, $needle ); 
     520        $scrape_result_position = strpos( $body, $needle_start ); 
     521 
     522        $loopback_request_failure = array( 
     523            'code' => 'loopback_request_failed', 
     524            'message' => __( 'Unable to communicate back with site to check for fatal errors, so the PHP change was reverted. You will need to upload your PHP file change by some other means, such as by using SFTP.' ), 
     525        ); 
     526        $json_parse_failure = array( 
     527            'code' => 'json_parse_error', 
     528        ); 
     529 
     530        $result = null; 
     531        if ( false === $scrape_result_position ) { 
     532            $result = $loopback_request_failure; 
     533        } else { 
     534            $error_output = substr( $body, $scrape_result_position + strlen( $needle_start ) ); 
     535            $error_output = substr( $error_output, 0, strpos( $error_output, $needle_end ) ); 
     536            $result = json_decode( trim( $error_output ), true ); 
     537            if ( empty( $result ) ) { 
     538                $result = $json_parse_failure; 
     539            } 
     540        } 
    509541 
    510542        // Try making request to homepage as well to see if visitors have been whitescreened. 
    511         if ( false === $error_position ) { 
     543        if ( true === $result ) { 
    512544            $url = home_url( '/' ); 
    513545            $url = add_query_arg( $scrape_params, $url ); 
    514             $r = wp_remote_get( $url, compact( 'cookies', 'headers' ) ); 
     546            $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) ); 
    515547            $body = wp_remote_retrieve_body( $r ); 
    516             $error_position = strpos( $body, $needle ); 
     548            $scrape_result_position = strpos( $body, $needle_start ); 
     549 
     550            if ( false === $scrape_result_position ) { 
     551                $result = $loopback_request_failure; 
     552            } else { 
     553                $error_output = substr( $body, $scrape_result_position + strlen( $needle_start ) ); 
     554                $error_output = substr( $error_output, 0, strpos( $error_output, $needle_end ) ); 
     555                $result = json_decode( trim( $error_output ), true ); 
     556                if ( empty( $result ) ) { 
     557                    $result = $json_parse_failure; 
     558                } 
     559            } 
    517560        } 
    518561 
    519562        delete_transient( $transient ); 
    520563 
    521         if ( false !== $error_position ) { 
     564        if ( true !== $result ) { 
     565 
     566            // Roll-back file change. 
    522567            file_put_contents( $real_file, $previous_content ); 
    523568            if ( function_exists( 'opcache_invalidate' ) ) { 
     
    525570            } 
    526571 
    527             $error_output = trim( substr( $body, $error_position + strlen( $needle ) ) ); 
    528             $error = json_decode( $error_output, true ); 
    529             if ( ! isset( $error['message'] ) ) { 
    530                 $message = $error_output; 
     572            if ( ! isset( $result['message'] ) ) { 
     573                $message = __( 'An unidentified error has occurred.' ); 
    531574            } else { 
    532                 $message = $error['message']; 
    533                 unset( $error['message'] ); 
     575                $message = $result['message']; 
     576                unset( $result['message'] ); 
    534577            } 
    535             return new WP_Error( 'php_error', $message, $error ); 
     578            return new WP_Error( 'php_error', $message, $result ); 
    536579        } 
    537580    } 
  • trunk/src/wp-admin/js/theme-plugin-editor.js

    r41775 r41805  
    1414                plural: '' 
    1515            }, 
    16             saveAlert: '' 
     16            saveAlert: '', 
     17            saveError: '' 
    1718        }, 
    1819        codeEditor: {}, 
     
    162163            var notice = $.extend( 
    163164                { 
    164                     code: 'save_error' 
     165                    code: 'save_error', 
     166                    message: component.l10n.saveError 
    165167                }, 
    166168                response, 
  • trunk/src/wp-includes/load.php

    r41721 r41805  
    11271127 
    11281128    if ( get_transient( 'scrape_key_' . $key ) !== $nonce ) { 
    1129         echo "###### begin_scraped_error:$key ######"; 
     1129        echo "###### wp_scraping_result_start:$key ######"; 
    11301130        echo wp_json_encode( array( 
    11311131            'code' => 'scrape_nonce_failure', 
    11321132            'message' => __( 'Scrape nonce check failed. Please try again.' ), 
    11331133        ) ); 
     1134        echo "###### wp_scraping_result_end:$key ######"; 
    11341135        die(); 
    11351136    } 
     
    11461147function wp_finalize_scraping_edited_file_errors( $scrape_key ) { 
    11471148    $error = error_get_last(); 
    1148     if ( empty( $error ) ) { 
    1149         return; 
    1150     } 
    1151     if ( ! in_array( $error['type'], array( E_CORE_ERROR, E_COMPILE_ERROR, E_ERROR, E_PARSE, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) { 
    1152         return; 
    1153     } 
    1154     $error = str_replace( ABSPATH, '', $error ); 
    1155     echo "###### begin_scraped_error:$scrape_key ######"; 
    1156     echo wp_json_encode( $error ); 
    1157 } 
     1149    echo "\n###### wp_scraping_result_start:$scrape_key ######\n"; 
     1150    if ( ! empty( $error ) && in_array( $error['type'], array( E_CORE_ERROR, E_COMPILE_ERROR, E_ERROR, E_PARSE, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) { 
     1151        $error = str_replace( ABSPATH, '', $error ); 
     1152        echo wp_json_encode( $error ); 
     1153    } else { 
     1154        echo wp_json_encode( true ); 
     1155    } 
     1156    echo "\n###### wp_scraping_result_end:$scrape_key ######\n"; 
     1157} 
  • trunk/src/wp-includes/script-loader.php

    r41797 r41805  
    473473    did_action( 'init' ) && $scripts->add_inline_script( 'wp-theme-plugin-editor', sprintf( 'wp.themePluginEditor.l10n = %s;', wp_json_encode( array( 
    474474        'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ), 
     475        'saveError' => __( 'Something went wrong. Your change may not have been saved. Please try again. There is also a chance that you may need to manually fix and upload the file over FTP.' ), 
    475476        'lintError' => wp_array_slice_assoc( 
    476477            /* translators: %d: error count */ 
Note: See TracChangeset for help on using the changeset viewer.