[WordPress] 「致命的なエラーをチェックするためにサイトと通信できないため、PHP の変更は取り消されました。」

WordPress 管理画面に対して IP 制限を行っている場合に、テーマエディターやプラグインエディターなどでファイルを編集しようとすると「致命的なエラーをチェックするためにサイトと通信できないため、PHP の変更は取り消されました。」と表示されて編集できないことがあります。

このチェックをしてエラーメッセージを出しているのは `wp-admin/includes/file.php` のこの部分
https://github.com/WordPress/WordPress/blob/master/wp-admin/includes/file.php#L550-L633

WordPress は、まずループバックチェックをする対象のURLを決定します。
ループバックチェック対象のURLは、プラグインかテーマの編集いずれかによって変わります。

* プラグイン編集中の場合は `/wp-admin/plugin-editor.php?plugin=${plugin}&file=${file}`
* テーマ編集中の場合は `/wp-admin/theme-editor.php?theme=${stylesheet}&file=${file}`
* それ以外の場合は `/wp-admin/`

```PHP:wp-admin/includes/file.php#L550-L563
		// Attempt loopback request to editor to see if user just whitescreened themselves.
		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();
		}
```

次に、その URL に対して__サーバから__ `wp_remote_get()` で HTTP リクエストが行われます。

```PHP:wp-admin/includes/file.php#L571-L574
		$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 );
```

なお WordPress 管理画面に BASIC 認証が設定されている場合に関しての考慮は `wp-admin/includes/file.php#L536-L539` で行われているので安心です。

```PHP:wp-admin/includes/file.php#L536-L539
		// Include Basic auth in loopback requests.
		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'] ) );
		}
```

話がずれましたが `wp_remote_get()` の結果に `$needle_start` (`"###### wp_scraping_result_start:$scrape_key ######"`) が含まれない場合は、管理画面へのループバックチェックが失敗したとみなされて、エラーとして処理されます。

```PHP:wp-admin/includes/file.php#L586-L595
		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;
			}
		}
```  

```PHP:wp-admin/includes/file.php#L619-L632
		if ( true !== $result ) {
			// Roll-back file change.
			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 );
		}
```

なので、WordPress 管理画面に IP制限を設定している場合は、自分のサーバのIPアドレスからのリクエストも許可するように設定しましょう。
AutoScaling などで、サーバのIPが固定できない場合は `wp-admin/plugin-editor.php` , `wp-admin/theme-editor.php` へのリクエストのみ IP 制限をかけないようにするか、そもそも WordPress 管理画面からテーマやプラグインの編集をしないようにしてください。
サーバ管理してる身としては「WordPress 管理画面からテーマやプラグインの編集をしないように」してもらった方がトラブルも少ないのでありがたいです。

現場からは以上です。