Source
File: wp-admin/includes/file.php
function wp_edit_theme_plugin_file( $args ) {
if ( empty( $args['file'] ) ) {
return new WP_Error( 'missing_file' );
}
$file = $args['file'];
if ( 0 !== validate_file( $file ) ) {
return new WP_Error( 'bad_file' );
}
if ( ! isset( $args['newcontent'] ) ) {
return new WP_Error( 'missing_content' );
}
$content = $args['newcontent'];
if ( ! isset( $args['nonce'] ) ) {
return new WP_Error( 'missing_nonce' );
}
$plugin = null;
$theme = null;
$real_file = null;
if ( ! empty( $args['plugin'] ) ) {
$plugin = $args['plugin'];
if ( ! current_user_can( 'edit_plugins' ) ) {
return new WP_Error( 'unauthorized', __( 'Sorry, you are not allowed to edit plugins for this site.' ) );
}
if ( ! wp_verify_nonce( $args['nonce'], 'edit-plugin_' . $file ) ) {
return new WP_Error( 'nonce_failure' );
}
if ( ! array_key_exists( $plugin, get_plugins() ) ) {
return new WP_Error( 'invalid_plugin' );
}
if ( 0 !== validate_file( $file, get_plugin_files( $plugin ) ) ) {
return new WP_Error( 'bad_plugin_file_path', __( 'Sorry, that file cannot be edited.' ) );
}
$editable_extensions = wp_get_plugin_file_editable_extensions( $plugin );
$real_file = WP_PLUGIN_DIR . '/' . $file;
$is_active = in_array(
$plugin,
(array) get_option( 'active_plugins', array() ),
true
);
} elseif ( ! empty( $args['theme'] ) ) {
$stylesheet = $args['theme'];
if ( 0 !== validate_file( $stylesheet ) ) {
return new WP_Error( 'bad_theme_path' );
}
if ( ! current_user_can( 'edit_themes' ) ) {
return new WP_Error( 'unauthorized', __( 'Sorry, you are not allowed to edit templates for this site.' ) );
}
$theme = wp_get_theme( $stylesheet );
if ( ! $theme->exists() ) {
return new WP_Error( 'non_existent_theme', __( 'The requested theme does not exist.' ) );
}
if ( ! wp_verify_nonce( $args['nonce'], 'edit-theme_' . $stylesheet . '_' . $file ) ) {
return new WP_Error( 'nonce_failure' );
}
if ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) {
return new WP_Error(
'theme_no_stylesheet',
__( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message()
);
}
$editable_extensions = wp_get_theme_file_editable_extensions( $theme );
$allowed_files = array();
foreach ( $editable_extensions as $type ) {
switch ( $type ) {
case 'php':
$allowed_files = array_merge( $allowed_files, $theme->get_files( 'php', -1 ) );
break;
case 'css':
$style_files = $theme->get_files( 'css', -1 );
$allowed_files['style.css'] = $style_files['style.css'];
$allowed_files = array_merge( $allowed_files, $style_files );
break;
default:
$allowed_files = array_merge( $allowed_files, $theme->get_files( $type, -1 ) );
break;
}
}
if ( 0 !== validate_file( $file, array_keys( $allowed_files ) ) ) {
return new WP_Error( 'disallowed_theme_file', __( 'Sorry, that file cannot be edited.' ) );
}
$real_file = $theme->get_stylesheet_directory() . '/' . $file;
$is_active = ( get_stylesheet() === $stylesheet || get_template() === $stylesheet );
} else {
return new WP_Error( 'missing_theme_or_plugin' );
}
if ( ! is_file( $real_file ) ) {
return new WP_Error( 'file_does_not_exist', __( 'File does not exist! Please double check the name and try again.' ) );
}
$extension = null;
if ( preg_match( '/\.([^.]+)$/', $real_file, $matches ) ) {
$extension = strtolower( $matches[1] );
if ( ! in_array( $extension, $editable_extensions, true ) ) {
return new WP_Error( 'illegal_file_type', __( 'Files of this type are not editable.' ) );
}
}
$previous_content = file_get_contents( $real_file );
if ( ! is_writeable( $real_file ) ) {
return new WP_Error( 'file_not_writable' );
}
$f = fopen( $real_file, 'w+' );
if ( false === $f ) {
return new WP_Error( 'file_not_writable' );
}
$written = fwrite( $f, $content );
fclose( $f );
if ( false === $written ) {
return new WP_Error( 'unable_to_write', __( 'Unable to write to file.' ) );
}
wp_opcache_invalidate( $real_file, true );
if ( $is_active && 'php' === $extension ) {
$scrape_key = md5( rand() );
$transient = 'scrape_key_' . $scrape_key;
$scrape_nonce = strval( rand() );
set_transient( $transient, $scrape_nonce, 60 );
$cookies = wp_unslash( $_COOKIE );
$scrape_params = array(
'wp_scrape_key' => $scrape_key,
'wp_scrape_nonce' => $scrape_nonce,
);
$headers = array(
'Cache-Control' => 'no-cache',
);
$sslverify = apply_filters( 'https_local_ssl_verify', false );
if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
$headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
}
set_time_limit( 300 );
$timeout = 100;
$needle_start = "###### wp_scraping_result_start:$scrape_key ######";
$needle_end = "###### wp_scraping_result_end:$scrape_key ######";
if ( $plugin ) {
$url = add_query_arg( compact( 'plugin', 'file' ), admin_url( 'plugin-editor.php' ) );
} elseif ( isset( $stylesheet ) ) {
$url = add_query_arg(
array(
'theme' => $stylesheet,
'file' => $file,
),
admin_url( 'theme-editor.php' )
);
} else {
$url = admin_url();
}
if ( function_exists( 'session_status' ) && PHP_SESSION_ACTIVE === session_status() ) {
session_write_close();
}
$url = add_query_arg( $scrape_params, $url );
$r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
$body = wp_remote_retrieve_body( $r );
$scrape_result_position = strpos( $body, $needle_start );
$loopback_request_failure = array(
'code' => 'loopback_request_failed',
'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.' ),
);
$json_parse_failure = array(
'code' => 'json_parse_error',
);
$result = null;
if ( false === $scrape_result_position ) {
$result = $loopback_request_failure;
} else {
$error_output = substr( $body, $scrape_result_position + strlen( $needle_start ) );
$error_output = substr( $error_output, 0, strpos( $error_output, $needle_end ) );
$result = json_decode( trim( $error_output ), true );
if ( empty( $result ) ) {
$result = $json_parse_failure;
}
}
if ( true === $result ) {
$url = home_url( '/' );
$url = add_query_arg( $scrape_params, $url );
$r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
$body = wp_remote_retrieve_body( $r );
$scrape_result_position = strpos( $body, $needle_start );
if ( false === $scrape_result_position ) {
$result = $loopback_request_failure;
} else {
$error_output = substr( $body, $scrape_result_position + strlen( $needle_start ) );
$error_output = substr( $error_output, 0, strpos( $error_output, $needle_end ) );
$result = json_decode( trim( $error_output ), true );
if ( empty( $result ) ) {
$result = $json_parse_failure;
}
}
}
delete_transient( $transient );
if ( true !== $result ) {
file_put_contents( $real_file, $previous_content );
wp_opcache_invalidate( $real_file, true );
if ( ! isset( $result['message'] ) ) {
$message = __( 'Something went wrong.' );
} else {
$message = $result['message'];
unset( $result['message'] );
}
return new WP_Error( 'php_error', $message, $result );
}
}
if ( $theme instanceof WP_Theme ) {
$theme->cache_delete();
}
return true;
}