wp/wp-admin/includes/file.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
--- a/wp/wp-admin/includes/file.php	Tue Oct 22 16:11:46 2019 +0200
+++ b/wp/wp-admin/includes/file.php	Tue Dec 15 13:49:49 2020 +0100
@@ -21,7 +21,7 @@
 	'searchform.php'        => __( 'Search Form' ),
 	'404.php'               => __( '404 Template' ),
 	'link.php'              => __( 'Links Template' ),
-	// Archives
+	// Archives.
 	'index.php'             => __( 'Main Index Template' ),
 	'archive.php'           => __( 'Archives' ),
 	'author.php'            => __( 'Author Template' ),
@@ -31,33 +31,33 @@
 	'home.php'              => __( 'Posts Page' ),
 	'search.php'            => __( 'Search Results' ),
 	'date.php'              => __( 'Date Template' ),
-	// Content
+	// Content.
 	'singular.php'          => __( 'Singular Template' ),
 	'single.php'            => __( 'Single Post' ),
 	'page.php'              => __( 'Single Page' ),
 	'front-page.php'        => __( 'Homepage' ),
 	'privacy-policy.php'    => __( 'Privacy Policy Page' ),
-	// Attachments
+	// Attachments.
 	'attachment.php'        => __( 'Attachment Template' ),
 	'image.php'             => __( 'Image Attachment Template' ),
 	'video.php'             => __( 'Video Attachment Template' ),
 	'audio.php'             => __( 'Audio Attachment Template' ),
 	'application.php'       => __( 'Application Attachment Template' ),
-	// Embeds
+	// Embeds.
 	'embed.php'             => __( 'Embed Template' ),
 	'embed-404.php'         => __( 'Embed 404 Template' ),
 	'embed-content.php'     => __( 'Embed Content Template' ),
 	'header-embed.php'      => __( 'Embed Header Template' ),
 	'footer-embed.php'      => __( 'Embed Footer Template' ),
-	// Stylesheets
+	// Stylesheets.
 	'style.css'             => __( 'Stylesheet' ),
 	'editor-style.css'      => __( 'Visual Editor Stylesheet' ),
 	'editor-style-rtl.css'  => __( 'Visual Editor RTL Stylesheet' ),
 	'rtl.css'               => __( 'RTL Stylesheet' ),
-	// Other
+	// Other.
 	'my-hacks.php'          => __( 'my-hacks.php (legacy hacks support)' ),
 	'.htaccess'             => __( '.htaccess (for rewrite rules )' ),
-	// Deprecated files
+	// Deprecated files.
 	'wp-layout.css'         => __( 'Stylesheet' ),
 	'wp-comments.php'       => __( 'Comments Template' ),
 	'wp-comments-popup.php' => __( 'Popup Comments Template' ),
@@ -65,28 +65,30 @@
 );
 
 /**
- * Get the description for standard WordPress theme files and other various standard
- * WordPress files
+ * Gets the description for standard WordPress theme files.
  *
  * @since 1.5.0
  *
  * @global array $wp_file_descriptions Theme file descriptions.
  * @global array $allowed_files        List of allowed files.
- * @param string $file Filesystem path or filename
+ *
+ * @param string $file Filesystem path or filename.
  * @return string Description of file from $wp_file_descriptions or basename of $file if description doesn't exist.
- *                Appends 'Page Template' to basename of $file if the file is a page template
+ *                Appends 'Page Template' to basename of $file if the file is a page template.
  */
 function get_file_description( $file ) {
 	global $wp_file_descriptions, $allowed_files;
 
-	$dirname = pathinfo( $file, PATHINFO_DIRNAME );
+	$dirname   = pathinfo( $file, PATHINFO_DIRNAME );
+	$file_path = $allowed_files[ $file ];
 
-	$file_path = $allowed_files[ $file ];
 	if ( isset( $wp_file_descriptions[ basename( $file ) ] ) && '.' === $dirname ) {
 		return $wp_file_descriptions[ basename( $file ) ];
 	} elseif ( file_exists( $file_path ) && is_file( $file_path ) ) {
 		$template_data = implode( '', file( $file_path ) );
+
 		if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ) ) {
+			/* translators: %s: Template name. */
 			return sprintf( __( '%s Page Template' ), _cleanup_header_comment( $name[1] ) );
 		}
 	}
@@ -95,15 +97,16 @@
 }
 
 /**
- * Get the absolute filesystem path to the root of the WordPress installation
+ * Gets the absolute filesystem path to the root of the WordPress installation.
  *
  * @since 1.5.0
  *
- * @return string Full filesystem path to the root of the WordPress installation
+ * @return string Full filesystem path to the root of the WordPress installation.
  */
 function get_home_path() {
 	$home    = set_url_scheme( get_option( 'home' ), 'http' );
 	$siteurl = set_url_scheme( get_option( 'siteurl' ), 'http' );
+
 	if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) {
 		$wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /* $siteurl - $home */
 		$pos                 = strripos( str_replace( '\\', '/', $_SERVER['SCRIPT_FILENAME'] ), trailingslashit( $wp_path_rel_to_home ) );
@@ -118,6 +121,7 @@
 
 /**
  * Returns a listing of all files in the specified folder and all subdirectories up to 100 levels deep.
+ *
  * The depth of the recursiveness can be controlled by the $levels param.
  *
  * @since 2.6.0
@@ -165,14 +169,15 @@
 				$files[] = $folder . $file;
 			}
 		}
+
+		closedir( $dir );
 	}
-	@closedir( $dir );
 
 	return $files;
 }
 
 /**
- * Get list of file extensions that are editable in plugins.
+ * Gets the list of file extensions that are editable in plugins.
  *
  * @since 4.9.0
  *
@@ -181,7 +186,7 @@
  */
 function wp_get_plugin_file_editable_extensions( $plugin ) {
 
-	$editable_extensions = array(
+	$default_types = array(
 		'bash',
 		'conf',
 		'css',
@@ -217,21 +222,23 @@
 	);
 
 	/**
-	 * Filters file type extensions editable in the plugin editor.
+	 * Filters the list of file types allowed for editing in the plugin editor.
 	 *
 	 * @since 2.8.0
 	 * @since 4.9.0 Added the `$plugin` parameter.
 	 *
-	 * @param string[] $editable_extensions An array of editable plugin file extensions.
-	 * @param string   $plugin              Path to the plugin file relative to the plugins directory.
+	 * @param string[] $default_types An array of editable plugin file extensions.
+	 * @param string   $plugin        Path to the plugin file relative to the plugins directory.
 	 */
-	$editable_extensions = (array) apply_filters( 'editable_extensions', $editable_extensions, $plugin );
+	$file_types = (array) apply_filters( 'editable_extensions', $default_types, $plugin );
 
-	return $editable_extensions;
+	return $file_types;
 }
 
 /**
- * Get list of file extensions that are editable for a given theme.
+ * Gets the list of file extensions that are editable for a given theme.
+ *
+ * @since 4.9.0
  *
  * @param WP_Theme $theme Theme object.
  * @return string[] Array of editable file extensions.
@@ -274,12 +281,12 @@
 	);
 
 	/**
-	 * Filters the list of file types allowed for editing in the Theme editor.
+	 * Filters the list of file types allowed for editing in the theme editor.
 	 *
 	 * @since 4.4.0
 	 *
-	 * @param string[] $default_types List of allowed file types.
-	 * @param WP_Theme $theme         The current Theme object.
+	 * @param string[] $default_types An array of editable theme file extensions.
+	 * @param WP_Theme $theme         The current theme object.
 	 */
 	$file_types = apply_filters( 'wp_theme_editor_filetypes', $default_types, $theme );
 
@@ -288,7 +295,7 @@
 }
 
 /**
- * Print file editor templates (for plugins and themes).
+ * Prints file editor templates (for plugins and themes).
  *
  * @since 4.9.0
  */
@@ -300,7 +307,7 @@
 				<p>
 					<?php
 					printf(
-						/* translators: 1: line number, 2: file path */
+						/* translators: 1: Line number, 2: File path. */
 						__( 'Your PHP code changes were rolled back due to an error on line %1$s of file %2$s. Please fix and try saving again.' ),
 						'{{ data.line }}',
 						'{{ data.file }}'
@@ -309,7 +316,15 @@
 				</p>
 				<pre>{{ data.message }}</pre>
 			<# } else if ( 'file_not_writable' === data.code ) { #>
-				<p><?php _e( 'You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.' ); ?></p>
+				<p>
+					<?php
+					printf(
+						/* translators: %s: Documentation URL. */
+						__( 'You need to make this file writable before you can save your changes. See <a href="%s">Changing File Permissions</a> for more information.' ),
+						__( 'https://wordpress.org/support/article/changing-file-permissions/' )
+					);
+					?>
+				</p>
 			<# } else { #>
 				<p>{{ data.message || data.code }}</p>
 
@@ -330,7 +345,7 @@
 }
 
 /**
- * Attempt to edit a file for a theme or plugin.
+ * Attempts to edit a file for a theme or plugin.
  *
  * When editing a PHP file, loopback requests will be made to the admin and the homepage
  * to attempt to see if there is a fatal error introduced. If so, the PHP change will be
@@ -445,7 +460,7 @@
 			}
 		}
 
-		// Compare based on relative paths
+		// Compare based on relative paths.
 		if ( 0 !== validate_file( $file, array_keys( $allowed_files ) ) ) {
 			return new WP_Error( 'disallowed_theme_file', __( 'Sorry, that file cannot be edited.' ) );
 		}
@@ -460,7 +475,7 @@
 
 	// Ensure file is real.
 	if ( ! is_file( $real_file ) ) {
-		return new WP_Error( 'file_does_not_exist', __( 'No such file exists! Double check the name and try again.' ) );
+		return new WP_Error( 'file_does_not_exist', __( 'File does not exist! Please double check the name and try again.' ) );
 	}
 
 	// Ensure file extension is allowed.
@@ -488,16 +503,16 @@
 	if ( false === $written ) {
 		return new WP_Error( 'unable_to_write', __( 'Unable to write to file.' ) );
 	}
-	if ( 'php' === $extension && function_exists( 'opcache_invalidate' ) ) {
-		opcache_invalidate( $real_file, true );
-	}
+
+	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 ); // It shouldn't take more than 60 seconds to make the two loopback requests.
+		// It shouldn't take more than 60 seconds to make the two loopback requests.
+		set_transient( $transient, $scrape_nonce, 60 );
 
 		$cookies       = wp_unslash( $_COOKIE );
 		$scrape_params = array(
@@ -508,13 +523,16 @@
 			'Cache-Control' => 'no-cache',
 		);
 
+		/** This filter is documented in wp-includes/class-wp-http-streams.php */
+		$sslverify = apply_filters( 'https_local_ssl_verify', false );
+
 		// 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'] ) );
 		}
 
 		// Make sure PHP process doesn't die before loopback requests complete.
-		@set_time_limit( 300 );
+		set_time_limit( 300 );
 
 		// Time to wait for loopback requests to finish.
 		$timeout = 100;
@@ -536,8 +554,15 @@
 		} else {
 			$url = admin_url();
 		}
+
+		if ( function_exists( 'session_status' ) && PHP_SESSION_ACTIVE === session_status() ) {
+			// Close any active session to prevent HTTP requests from timing out
+			// when attempting to connect back to the site.
+			session_write_close();
+		}
+
 		$url                    = add_query_arg( $scrape_params, $url );
-		$r                      = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
+		$r                      = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
 		$body                   = wp_remote_retrieve_body( $r );
 		$scrape_result_position = strpos( $body, $needle_start );
 
@@ -565,7 +590,7 @@
 		if ( true === $result ) {
 			$url                    = home_url( '/' );
 			$url                    = add_query_arg( $scrape_params, $url );
-			$r                      = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
+			$r                      = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
 			$body                   = wp_remote_retrieve_body( $r );
 			$scrape_result_position = strpos( $body, $needle_start );
 
@@ -587,9 +612,7 @@
 
 			// Roll-back file change.
 			file_put_contents( $real_file, $previous_content );
-			if ( function_exists( 'opcache_invalidate' ) ) {
-				opcache_invalidate( $real_file, true );
-			}
+			wp_opcache_invalidate( $real_file, true );
 
 			if ( ! isset( $result['message'] ) ) {
 				$message = __( 'Something went wrong.' );
@@ -610,28 +633,30 @@
 
 
 /**
- * Returns a filename of a Temporary unique file.
+ * Returns a filename of a temporary unique file.
+ *
  * Please note that the calling function must unlink() this itself.
  *
  * The filename is based off the passed parameter or defaults to the current unix timestamp,
- * while the directory can either be passed as well, or by leaving it blank, default to a writable temporary directory.
+ * while the directory can either be passed as well, or by leaving it blank, default to a writable
+ * temporary directory.
  *
  * @since 2.6.0
  *
  * @param string $filename Optional. Filename to base the Unique file off. Default empty.
  * @param string $dir      Optional. Directory to store the file in. Default empty.
- * @return string a writable filename
+ * @return string A writable filename.
  */
 function wp_tempnam( $filename = '', $dir = '' ) {
 	if ( empty( $dir ) ) {
 		$dir = get_temp_dir();
 	}
 
-	if ( empty( $filename ) || '.' == $filename || '/' == $filename || '\\' == $filename ) {
+	if ( empty( $filename ) || in_array( $filename, array( '.', '/', '\\' ), true ) ) {
 		$filename = uniqid();
 	}
 
-	// Use the basename of the given file without the extension as the name for the temporary directory
+	// Use the basename of the given file without the extension as the name for the temporary directory.
 	$temp_filename = basename( $filename );
 	$temp_filename = preg_replace( '|\.[^.]*$|', '', $temp_filename );
 
@@ -640,7 +665,7 @@
 		return wp_tempnam( dirname( $filename ), $dir );
 	}
 
-	// Suffix some random data to avoid filename conflicts
+	// Suffix some random data to avoid filename conflicts.
 	$temp_filename .= '-' . wp_generate_password( 6, false );
 	$temp_filename .= '.tmp';
 	$temp_filename  = $dir . wp_unique_filename( $dir, $temp_filename );
@@ -664,7 +689,8 @@
  * @since 1.5.0
  *
  * @param string   $file          File the user is attempting to edit.
- * @param string[] $allowed_files Optional. Array of allowed files to edit. `$file` must match an entry exactly.
+ * @param string[] $allowed_files Optional. Array of allowed files to edit.
+ *                                `$file` must match an entry exactly.
  * @return string|void Returns the file name on success, dies on failure.
  */
 function validate_file_to_edit( $file, $allowed_files = array() ) {
@@ -687,20 +713,25 @@
 }
 
 /**
- * Handle PHP uploads in WordPress, sanitizing file names, checking extensions for mime type,
- * and moving the file to the appropriate directory within the uploads directory.
+ * Handles PHP uploads in WordPress.
+ *
+ * Sanitizes file names, checks extensions for mime type, and moves the file
+ * to the appropriate directory within the uploads directory.
  *
  * @access private
  * @since 4.0.0
  *
  * @see wp_handle_upload_error
  *
- * @param string[]       $file      Reference to a single element of `$_FILES`. Call the function once for each uploaded file.
- * @param string[]|false $overrides An associative array of names => values to override default variables. Default false.
+ * @param string[]       $file      Reference to a single element of `$_FILES`.
+ *                                  Call the function once for each uploaded file.
+ * @param string[]|false $overrides An associative array of names => values
+ *                                  to override default variables. Default false.
  * @param string         $time      Time formatted in 'yyyy/mm'.
  * @param string         $action    Expected value for `$_POST['action']`.
- * @return string[] On success, returns an associative array of file attributes. On failure, returns
- *               `$overrides['upload_error_handler'](&$file, $message )` or `array( 'error'=>$message )`.
+ * @return string[] On success, returns an associative array of file attributes.
+ *                  On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
+ *                  or `array( 'error' => $message )`.
  */
 function _wp_handle_upload( &$file, $overrides, $time, $action ) {
 	// The default error handler.
@@ -722,7 +753,7 @@
 	 */
 	$file = apply_filters( "{$action}_prefilter", $file );
 
-	// You may define your own function and pass the name in $overrides['upload_error_handler']
+	// You may define your own function and pass the name in $overrides['upload_error_handler'].
 	$upload_error_handler = 'wp_handle_upload_error';
 	if ( isset( $overrides['upload_error_handler'] ) ) {
 		$upload_error_handler = $overrides['upload_error_handler'];
@@ -735,14 +766,14 @@
 
 	// Install user overrides. Did we mention that this voids your warranty?
 
-	// You may define your own function and pass the name in $overrides['unique_filename_callback']
+	// You may define your own function and pass the name in $overrides['unique_filename_callback'].
 	$unique_filename_callback = null;
 	if ( isset( $overrides['unique_filename_callback'] ) ) {
 		$unique_filename_callback = $overrides['unique_filename_callback'];
 	}
 
 	/*
-	 * This may not have orignially been intended to be overrideable,
+	 * This may not have originally been intended to be overridable,
 	 * but historically has been.
 	 */
 	if ( isset( $overrides['upload_error_strings'] ) ) {
@@ -751,8 +782,17 @@
 		// Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
 		$upload_error_strings = array(
 			false,
-			__( 'The uploaded file exceeds the upload_max_filesize directive in php.ini.' ),
-			__( 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.' ),
+			sprintf(
+				/* translators: 1: upload_max_filesize, 2: php.ini */
+				__( 'The uploaded file exceeds the %1$s directive in %2$s.' ),
+				'upload_max_filesize',
+				'php.ini'
+			),
+			sprintf(
+				/* translators: %s: MAX_FILE_SIZE */
+				__( 'The uploaded file exceeds the %s directive that was specified in the HTML form.' ),
+				'MAX_FILE_SIZE'
+			),
 			__( 'The uploaded file was only partially uploaded.' ),
 			__( 'No file was uploaded.' ),
 			'',
@@ -780,7 +820,7 @@
 	}
 
 	// A properly uploaded file will pass this test. There should be no reason to override this one.
-	$test_uploaded_file = 'wp_handle_upload' === $action ? @ is_uploaded_file( $file['tmp_name'] ) : @ is_readable( $file['tmp_name'] );
+	$test_uploaded_file = 'wp_handle_upload' === $action ? is_uploaded_file( $file['tmp_name'] ) : @is_readable( $file['tmp_name'] );
 	if ( ! $test_uploaded_file ) {
 		return call_user_func_array( $upload_error_handler, array( &$file, __( 'Specified file failed upload test.' ) ) );
 	}
@@ -791,7 +831,13 @@
 		if ( is_multisite() ) {
 			$error_msg = __( 'File is empty. Please upload something more substantial.' );
 		} else {
-			$error_msg = __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' );
+			$error_msg = sprintf(
+				/* translators: 1: php.ini, 2: post_max_size, 3: upload_max_filesize */
+				__( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your %1$s file or by %2$s being defined as smaller than %3$s in %1$s.' ),
+				'php.ini',
+				'post_max_size',
+				'upload_max_filesize'
+			);
 		}
 		return call_user_func_array( $upload_error_handler, array( &$file, $error_msg ) );
 	}
@@ -803,7 +849,7 @@
 		$type            = empty( $wp_filetype['type'] ) ? '' : $wp_filetype['type'];
 		$proper_filename = empty( $wp_filetype['proper_filename'] ) ? '' : $wp_filetype['proper_filename'];
 
-		// Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
+		// Check to see if wp_check_filetype_and_ext() determined the filename was incorrect.
 		if ( $proper_filename ) {
 			$file['name'] = $proper_filename;
 		}
@@ -821,7 +867,8 @@
 	 * A writable uploads dir will pass this test. Again, there's no point
 	 * overriding this one.
 	 */
-	if ( ! ( ( $uploads = wp_upload_dir( $time ) ) && false === $uploads['error'] ) ) {
+	$uploads = wp_upload_dir( $time );
+	if ( ! ( $uploads && false === $uploads['error'] ) ) {
 		return call_user_func_array( $upload_error_handler, array( &$file, $uploads['error'] ) );
 	}
 
@@ -833,24 +880,25 @@
 	/**
 	 * Filters whether to short-circuit moving the uploaded file after passing all checks.
 	 *
-	 * If a non-null value is passed to the filter, moving the file and any related error
-	 * reporting will be completely skipped.
+	 * If a non-null value is returned from the filter, moving the file and any related
+	 * error reporting will be completely skipped.
 	 *
 	 * @since 4.9.0
 	 *
-	 * @param string $move_new_file If null (default) move the file after the upload.
-	 * @param string $file          An array of data for a single file.
-	 * @param string $new_file      Filename of the newly-uploaded file.
-	 * @param string $type          File type.
+	 * @param mixed    $move_new_file If null (default) move the file after the upload.
+	 * @param string[] $file          An array of data for a single file.
+	 * @param string   $new_file      Filename of the newly-uploaded file.
+	 * @param string   $type          Mime type of the newly-uploaded file.
 	 */
 	$move_new_file = apply_filters( 'pre_move_uploaded_file', null, $file, $new_file, $type );
 
 	if ( null === $move_new_file ) {
 		if ( 'wp_handle_upload' === $action ) {
-			$move_new_file = @ move_uploaded_file( $file['tmp_name'], $new_file );
+			$move_new_file = @move_uploaded_file( $file['tmp_name'], $new_file );
 		} else {
-			// use copy and unlink because rename breaks streams.
-			$move_new_file = @ copy( $file['tmp_name'], $new_file );
+			// Use copy and unlink because rename breaks streams.
+			// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+			$move_new_file = @copy( $file['tmp_name'], $new_file );
 			unlink( $file['tmp_name'] );
 		}
 
@@ -860,14 +908,21 @@
 			} else {
 				$error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
 			}
-			return $upload_error_handler( $file, sprintf( __( 'The uploaded file could not be moved to %s.' ), $error_path ) );
+			return $upload_error_handler(
+				$file,
+				sprintf(
+					/* translators: %s: Destination file path. */
+					__( 'The uploaded file could not be moved to %s.' ),
+					$error_path
+				)
+			);
 		}
 	}
 
 	// Set correct file permissions.
 	$stat  = stat( dirname( $new_file ) );
 	$perms = $stat['mode'] & 0000666;
-	@ chmod( $new_file, $perms );
+	chmod( $new_file, $perms );
 
 	// Compute the URL.
 	$url = $uploads['url'] . "/$filename";
@@ -885,8 +940,8 @@
 	 *     Array of upload data.
 	 *
 	 *     @type string $file Filename of the newly-uploaded file.
-	 *     @type string $url  URL of the uploaded file.
-	 *     @type string $type File type.
+	 *     @type string $url  URL of the newly-uploaded file.
+	 *     @type string $type Mime type of the newly-uploaded file.
 	 * }
 	 * @param string $context The type of upload action. Values include 'upload' or 'sideload'.
 	 */
@@ -910,13 +965,14 @@
  *
  * @see _wp_handle_upload()
  *
- * @param array      $file      Reference to a single element of `$_FILES`. Call the function once for
- *                              each uploaded file.
- * @param array|bool $overrides Optional. An associative array of names=>values to override default
- *                              variables. Default false.
+ * @param array      $file      Reference to a single element of `$_FILES`.
+ *                              Call the function once for each uploaded file.
+ * @param array|bool $overrides Optional. An associative array of names => values
+ *                              to override default variables. Default false.
  * @param string     $time      Optional. Time formatted in 'yyyy/mm'. Default null.
- * @return array On success, returns an associative array of file attributes. On failure, returns
- *               $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
+ * @return array On success, returns an associative array of file attributes.
+ *               On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
+ *               or `array( 'error' => $message )`.
  */
 function wp_handle_upload( &$file, $overrides = false, $time = null ) {
 	/*
@@ -940,12 +996,14 @@
  *
  * @see _wp_handle_upload()
  *
- * @param array      $file      An array similar to that of a PHP `$_FILES` POST array
- * @param array|bool $overrides Optional. An associative array of names=>values to override default
- *                              variables. Default false.
+ * @param array      $file      Reference to a single element of `$_FILES`.
+ *                              Call the function once for each uploaded file.
+ * @param array|bool $overrides Optional. An associative array of names => values
+ *                              to override default variables. Default false.
  * @param string     $time      Optional. Time formatted in 'yyyy/mm'. Default null.
- * @return array On success, returns an associative array of file attributes. On failure, returns
- *               $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
+ * @return array On success, returns an associative array of file attributes.
+ *               On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
+ *               or `array( 'error' => $message )`.
  */
 function wp_handle_sideload( &$file, $overrides = false, $time = null ) {
 	/*
@@ -956,10 +1014,10 @@
 	if ( isset( $overrides['action'] ) ) {
 		$action = $overrides['action'];
 	}
+
 	return _wp_handle_upload( $file, $overrides, $time, $action );
 }
 
-
 /**
  * Downloads a URL to a local temporary file using the WordPress HTTP API.
  *
@@ -969,12 +1027,14 @@
  * @since 5.2.0 Signature Verification with SoftFail was added.
  *
  * @param string $url                    The URL of the file to download.
- * @param int    $timeout                The timeout for the request to download the file. Default 300 seconds.
- * @param bool   $signature_verification Whether to perform Signature Verification. Default false.
+ * @param int    $timeout                The timeout for the request to download the file.
+ *                                       Default 300 seconds.
+ * @param bool   $signature_verification Whether to perform Signature Verification.
+ *                                       Default false.
  * @return string|WP_Error Filename on success, WP_Error on failure.
  */
 function download_url( $url, $timeout = 300, $signature_verification = false ) {
-	//WARNING: The file is not automatically deleted, The script must unlink() the file.
+	// WARNING: The file is not automatically deleted, the script must unlink() the file.
 	if ( ! $url ) {
 		return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) );
 	}
@@ -1040,11 +1100,11 @@
 	// If the caller expects signature verification to occur, check to see if this URL supports it.
 	if ( $signature_verification ) {
 		/**
-		 * Filters the list of hosts which should have Signature Verification attempteds on.
+		 * Filters the list of hosts which should have Signature Verification attempted on.
 		 *
 		 * @since 5.2.0
 		 *
-		 * @param array List of hostnames.
+		 * @param string[] $hostnames List of hostnames.
 		 */
 		$signed_hostnames       = apply_filters( 'wp_signature_hosts', array( 'wordpress.org', 'downloads.wordpress.org', 's.w.org' ) );
 		$signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true );
@@ -1055,11 +1115,12 @@
 		$signature = wp_remote_retrieve_header( $response, 'x-content-signature' );
 		if ( ! $signature ) {
 			// Retrieve signatures from a file if the header wasn't included.
-			// WordPress.org stores signatures at $package_url.sig
+			// WordPress.org stores signatures at $package_url.sig.
 
 			$signature_url = false;
 			$url_path      = parse_url( $url, PHP_URL_PATH );
-			if ( substr( $url_path, -4 ) == '.zip' || substr( $url_path, -7 ) == '.tar.gz' ) {
+
+			if ( '.zip' === substr( $url_path, -4 ) || '.tar.gz' === substr( $url_path, -7 ) ) {
 				$signature_url = str_replace( $url_path, $url_path . '.sig', $url );
 			}
 
@@ -1077,7 +1138,7 @@
 				$signature_request = wp_safe_remote_get(
 					$signature_url,
 					array(
-						'limit_response_size' => 10 * 1024, // 10KB should be large enough for quite a few signatures.
+						'limit_response_size' => 10 * KB_IN_BYTES, // 10KB should be large enough for quite a few signatures.
 					)
 				);
 
@@ -1134,7 +1195,7 @@
 	} elseif ( 24 == strlen( $expected_md5 ) ) {
 		$expected_raw_md5 = base64_decode( $expected_md5 );
 	} else {
-		return false; // unknown format
+		return false; // Unknown format.
 	}
 
 	$file_md5 = md5_file( $filename, true );
@@ -1143,7 +1204,15 @@
 		return true;
 	}
 
-	return new WP_Error( 'md5_mismatch', sprintf( __( 'The checksum of the file (%1$s) does not match the expected checksum value (%2$s).' ), bin2hex( $file_md5 ), bin2hex( $expected_raw_md5 ) ) );
+	return new WP_Error(
+		'md5_mismatch',
+		sprintf(
+			/* translators: 1: File checksum, 2: Expected checksum value. */
+			__( 'The checksum of the file (%1$s) does not match the expected checksum value (%2$s).' ),
+			bin2hex( $file_md5 ),
+			bin2hex( $expected_raw_md5 )
+		)
+	);
 }
 
 /**
@@ -1154,8 +1223,8 @@
  * @param string       $filename            The file to validate.
  * @param string|array $signatures          A Signature provided for the file.
  * @param string       $filename_for_errors A friendly filename for errors. Optional.
- *
- * @return bool|WP_Error true on success, false if verificaiton not attempted, or WP_Error describing an error condition.
+ * @return bool|WP_Error True on success, false if verification not attempted,
+ *                       or WP_Error describing an error condition.
  */
 function verify_file_signature( $filename, $signatures, $filename_for_errors = false ) {
 	if ( ! $filename_for_errors ) {
@@ -1163,7 +1232,7 @@
 	}
 
 	// Check we can process signatures.
-	if ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) || ! in_array( 'sha384', array_map( 'strtolower', hash_algos() ) ) ) {
+	if ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) || ! in_array( 'sha384', array_map( 'strtolower', hash_algos() ), true ) ) {
 		return new WP_Error(
 			'signature_verification_unsupported',
 			sprintf(
@@ -1175,10 +1244,10 @@
 		);
 	}
 
-	// Check for a edge-case affecting PHP Maths abilities
+	// Check for a edge-case affecting PHP Maths abilities.
 	if (
 		! extension_loaded( 'sodium' ) &&
-		in_array( PHP_VERSION_ID, [ 70200, 70201, 70202 ], true ) &&
+		in_array( PHP_VERSION_ID, array( 70200, 70201, 70202 ), true ) &&
 		extension_loaded( 'opcache' )
 	) {
 		// Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
@@ -1193,6 +1262,7 @@
 			),
 			array(
 				'php'    => phpversion(),
+				// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 				'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 			)
 		);
@@ -1206,13 +1276,15 @@
 		// Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
 		if ( method_exists( 'ParagonIE_Sodium_Compat', 'runtime_speed_test' ) ) {
 			// Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
+			// phpcs:disable WordPress.NamingConventions.ValidVariableName
 			$old_fastMult                      = ParagonIE_Sodium_Compat::$fastMult;
 			ParagonIE_Sodium_Compat::$fastMult = true;
 			$sodium_compat_is_fast             = ParagonIE_Sodium_Compat::runtime_speed_test( 100, 10 );
 			ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
+			// phpcs:enable
 		}
 
-		// This cannot be performed in a reasonable amount of time
+		// This cannot be performed in a reasonable amount of time.
 		// https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
 		if ( ! $sodium_compat_is_fast ) {
 			return new WP_Error(
@@ -1224,6 +1296,7 @@
 				),
 				array(
 					'php'                => phpversion(),
+					// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 					'sodium'             => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 					'polyfill_is_fast'   => false,
 					'max_execution_time' => ini_get( 'max_execution_time' ),
@@ -1251,7 +1324,8 @@
 
 	mbstring_binary_safe_encoding();
 
-	$skipped_key = $skipped_signature = 0;
+	$skipped_key       = 0;
+	$skipped_signature = 0;
 
 	foreach ( (array) $signatures as $signature ) {
 		$signature_raw = base64_decode( $signature );
@@ -1296,17 +1370,18 @@
 			'skipped_key' => $skipped_key,
 			'skipped_sig' => $skipped_signature,
 			'php'         => phpversion(),
+			// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 			'sodium'      => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 		)
 	);
 }
 
 /**
- * Retrieve the list of signing keys trusted by WordPress.
+ * Retrieves the list of signing keys trusted by WordPress.
  *
  * @since 5.2.0
  *
- * @return array List of base64-encoded Signing keys.
+ * @return string[] Array of base64-encoded signing keys.
  */
 function wp_trusted_keys() {
 	$trusted_keys = array();
@@ -1319,11 +1394,11 @@
 	// TODO: Add key #2 with longer expiration.
 
 	/**
-	 * Filter the valid Signing keys used to verify the contents of files.
+	 * Filter the valid signing keys used to verify the contents of files.
 	 *
 	 * @since 5.2.0
 	 *
-	 * @param array $trusted_keys The trusted keys that may sign packages.
+	 * @param string[] $trusted_keys The trusted keys that may sign packages.
 	 */
 	return apply_filters( 'wp_trusted_keys', $trusted_keys );
 }
@@ -1392,7 +1467,7 @@
 		if ( true === $result ) {
 			return $result;
 		} elseif ( is_wp_error( $result ) ) {
-			if ( 'incompatible_archive' != $result->get_error_code() ) {
+			if ( 'incompatible_archive' !== $result->get_error_code() ) {
 				return $result;
 			}
 		}
@@ -1409,14 +1484,15 @@
  * Assumes that WP_Filesystem() has already been called and set up.
  *
  * @since 3.0.0
+ * @access private
+ *
  * @see unzip_file()
- * @access private
  *
  * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
  *
- * @param string $file       Full path and filename of ZIP archive.
- * @param string $to         Full path on the filesystem to extract archive to.
- * @param array $needed_dirs A partial list of required folders needed to be created.
+ * @param string   $file        Full path and filename of ZIP archive.
+ * @param string   $to          Full path on the filesystem to extract archive to.
+ * @param string[] $needed_dirs A partial list of required folders needed to be created.
  * @return true|WP_Error True on success, WP_Error on failure.
  */
 function _unzip_file_ziparchive( $file, $to, $needed_dirs = array() ) {
@@ -1432,11 +1508,12 @@
 	$uncompressed_size = 0;
 
 	for ( $i = 0; $i < $z->numFiles; $i++ ) {
-		if ( ! $info = $z->statIndex( $i ) ) {
+		$info = $z->statIndex( $i );
+		if ( ! $info ) {
 			return new WP_Error( 'stat_failed_ziparchive', __( 'Could not retrieve file from archive.' ) );
 		}
 
-		if ( '__MACOSX/' === substr( $info['name'], 0, 9 ) ) { // Skip the OS X-created __MACOSX directory
+		if ( '__MACOSX/' === substr( $info['name'], 0, 9 ) ) { // Skip the OS X-created __MACOSX directory.
 			continue;
 		}
 
@@ -1447,10 +1524,12 @@
 
 		$uncompressed_size += $info['size'];
 
+		$dirname = dirname( $info['name'] );
+
 		if ( '/' === substr( $info['name'], -1 ) ) {
 			// Directory.
 			$needed_dirs[] = $to . untrailingslashit( $info['name'] );
-		} elseif ( '.' !== $dirname = dirname( $info['name'] ) ) {
+		} elseif ( '.' !== $dirname ) {
 			// Path to a file.
 			$needed_dirs[] = $to . untrailingslashit( $dirname );
 		}
@@ -1471,15 +1550,15 @@
 	$needed_dirs = array_unique( $needed_dirs );
 	foreach ( $needed_dirs as $dir ) {
 		// Check the parent folders of the folders all exist within the creation array.
-		if ( untrailingslashit( $to ) == $dir ) { // Skip over the working directory, We know this exists (or will exist)
+		if ( untrailingslashit( $to ) == $dir ) { // Skip over the working directory, we know this exists (or will exist).
 			continue;
 		}
-		if ( strpos( $dir, $to ) === false ) { // If the directory is not within the working directory, Skip it
+		if ( strpos( $dir, $to ) === false ) { // If the directory is not within the working directory, skip it.
 			continue;
 		}
 
 		$parent_folder = dirname( $dir );
-		while ( ! empty( $parent_folder ) && untrailingslashit( $to ) != $parent_folder && ! in_array( $parent_folder, $needed_dirs ) ) {
+		while ( ! empty( $parent_folder ) && untrailingslashit( $to ) != $parent_folder && ! in_array( $parent_folder, $needed_dirs, true ) ) {
 			$needed_dirs[] = $parent_folder;
 			$parent_folder = dirname( $parent_folder );
 		}
@@ -1496,15 +1575,16 @@
 	unset( $needed_dirs );
 
 	for ( $i = 0; $i < $z->numFiles; $i++ ) {
-		if ( ! $info = $z->statIndex( $i ) ) {
+		$info = $z->statIndex( $i );
+		if ( ! $info ) {
 			return new WP_Error( 'stat_failed_ziparchive', __( 'Could not retrieve file from archive.' ) );
 		}
 
-		if ( '/' == substr( $info['name'], -1 ) ) { // directory
+		if ( '/' === substr( $info['name'], -1 ) ) { // Directory.
 			continue;
 		}
 
-		if ( '__MACOSX/' === substr( $info['name'], 0, 9 ) ) { // Don't extract the OS X-created __MACOSX directory files
+		if ( '__MACOSX/' === substr( $info['name'], 0, 9 ) ) { // Don't extract the OS X-created __MACOSX directory files.
 			continue;
 		}
 
@@ -1536,14 +1616,15 @@
  * Assumes that WP_Filesystem() has already been called and set up.
  *
  * @since 3.0.0
+ * @access private
+ *
  * @see unzip_file()
- * @access private
  *
  * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
  *
- * @param string $file       Full path and filename of ZIP archive.
- * @param string $to         Full path on the filesystem to extract archive to.
- * @param array $needed_dirs A partial list of required folders needed to be created.
+ * @param string   $file        Full path and filename of ZIP archive.
+ * @param string   $to          Full path on the filesystem to extract archive to.
+ * @param string[] $needed_dirs A partial list of required folders needed to be created.
  * @return true|WP_Error True on success, WP_Error on failure.
  */
 function _unzip_file_pclzip( $file, $to, $needed_dirs = array() ) {
@@ -1551,7 +1632,7 @@
 
 	mbstring_binary_safe_encoding();
 
-	require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
+	require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
 
 	$archive = new PclZip( $file );
 
@@ -1564,15 +1645,15 @@
 		return new WP_Error( 'incompatible_archive', __( 'Incompatible Archive.' ), $archive->errorInfo( true ) );
 	}
 
-	if ( 0 == count( $archive_files ) ) {
+	if ( 0 === count( $archive_files ) ) {
 		return new WP_Error( 'empty_archive_pclzip', __( 'Empty archive.' ) );
 	}
 
 	$uncompressed_size = 0;
 
-	// Determine any children directories needed (From within the archive)
+	// Determine any children directories needed (From within the archive).
 	foreach ( $archive_files as $file ) {
-		if ( '__MACOSX/' === substr( $file['filename'], 0, 9 ) ) { // Skip the OS X-created __MACOSX directory
+		if ( '__MACOSX/' === substr( $file['filename'], 0, 9 ) ) { // Skip the OS X-created __MACOSX directory.
 			continue;
 		}
 
@@ -1596,15 +1677,15 @@
 	$needed_dirs = array_unique( $needed_dirs );
 	foreach ( $needed_dirs as $dir ) {
 		// Check the parent folders of the folders all exist within the creation array.
-		if ( untrailingslashit( $to ) == $dir ) { // Skip over the working directory, We know this exists (or will exist)
+		if ( untrailingslashit( $to ) == $dir ) { // Skip over the working directory, we know this exists (or will exist).
 			continue;
 		}
-		if ( strpos( $dir, $to ) === false ) { // If the directory is not within the working directory, Skip it
+		if ( strpos( $dir, $to ) === false ) { // If the directory is not within the working directory, skip it.
 			continue;
 		}
 
 		$parent_folder = dirname( $dir );
-		while ( ! empty( $parent_folder ) && untrailingslashit( $to ) != $parent_folder && ! in_array( $parent_folder, $needed_dirs ) ) {
+		while ( ! empty( $parent_folder ) && untrailingslashit( $to ) != $parent_folder && ! in_array( $parent_folder, $needed_dirs, true ) ) {
 			$needed_dirs[] = $parent_folder;
 			$parent_folder = dirname( $parent_folder );
 		}
@@ -1620,13 +1701,13 @@
 	}
 	unset( $needed_dirs );
 
-	// Extract the files from the zip
+	// Extract the files from the zip.
 	foreach ( $archive_files as $file ) {
 		if ( $file['folder'] ) {
 			continue;
 		}
 
-		if ( '__MACOSX/' === substr( $file['filename'], 0, 9 ) ) { // Don't extract the OS X-created __MACOSX directory files
+		if ( '__MACOSX/' === substr( $file['filename'], 0, 9 ) ) { // Don't extract the OS X-created __MACOSX directory files.
 			continue;
 		}
 
@@ -1652,9 +1733,9 @@
  *
  * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
  *
- * @param string $from     Source directory.
- * @param string $to       Destination directory.
- * @param array $skip_list A list of files/folders to skip copying.
+ * @param string   $from      Source directory.
+ * @param string   $to        Destination directory.
+ * @param string[] $skip_list An array of files/folders to skip copying.
  * @return true|WP_Error True on success, WP_Error on failure.
  */
 function copy_dir( $from, $to, $skip_list = array() ) {
@@ -1666,11 +1747,11 @@
 	$to   = trailingslashit( $to );
 
 	foreach ( (array) $dirlist as $filename => $fileinfo ) {
-		if ( in_array( $filename, $skip_list ) ) {
+		if ( in_array( $filename, $skip_list, true ) ) {
 			continue;
 		}
 
-		if ( 'f' == $fileinfo['type'] ) {
+		if ( 'f' === $fileinfo['type'] ) {
 			if ( ! $wp_filesystem->copy( $from . $filename, $to . $filename, true, FS_CHMOD_FILE ) ) {
 				// If copy failed, chmod file to 0644 and try again.
 				$wp_filesystem->chmod( $to . $filename, FS_CHMOD_FILE );
@@ -1678,14 +1759,16 @@
 					return new WP_Error( 'copy_failed_copy_dir', __( 'Could not copy file.' ), $to . $filename );
 				}
 			}
-		} elseif ( 'd' == $fileinfo['type'] ) {
+
+			wp_opcache_invalidate( $to . $filename );
+		} elseif ( 'd' === $fileinfo['type'] ) {
 			if ( ! $wp_filesystem->is_dir( $to . $filename ) ) {
 				if ( ! $wp_filesystem->mkdir( $to . $filename, FS_CHMOD_DIR ) ) {
 					return new WP_Error( 'mkdir_failed_copy_dir', __( 'Could not create directory.' ), $to . $filename );
 				}
 			}
 
-			// generate the $sub_skip_list for the subdirectory as a sub-set of the existing $skip_list
+			// Generate the $sub_skip_list for the subdirectory as a sub-set of the existing $skip_list.
 			$sub_skip_list = array();
 			foreach ( $skip_list as $skip_item ) {
 				if ( 0 === strpos( $skip_item, $filename . '/' ) ) {
@@ -1699,11 +1782,12 @@
 			}
 		}
 	}
+
 	return true;
 }
 
 /**
- * Initialises and connects the WordPress Filesystem Abstraction classes.
+ * Initializes and connects the WordPress Filesystem Abstraction classes.
  *
  * This function will include the chosen transport and attempt connecting.
  *
@@ -1714,16 +1798,20 @@
  *
  * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
  *
- * @param array|false  $args                         Optional. Connection args, These are passed directly to
- *                                                   the `WP_Filesystem_*()` classes. Default false.
- * @param string|false $context                      Optional. Context for get_filesystem_method(). Default false.
- * @param bool         $allow_relaxed_file_ownership Optional. Whether to allow Group/World writable. Default false.
- * @return bool|null True on success, false on failure, null if the filesystem method class file does not exist.
+ * @param array|false  $args                         Optional. Connection args, These are passed
+ *                                                   directly to the `WP_Filesystem_*()` classes.
+ *                                                   Default false.
+ * @param string|false $context                      Optional. Context for get_filesystem_method().
+ *                                                   Default false.
+ * @param bool         $allow_relaxed_file_ownership Optional. Whether to allow Group/World writable.
+ *                                                   Default false.
+ * @return bool|null True on success, false on failure,
+ *                   null if the filesystem method class file does not exist.
  */
-function WP_Filesystem( $args = false, $context = false, $allow_relaxed_file_ownership = false ) {
+function WP_Filesystem( $args = false, $context = false, $allow_relaxed_file_ownership = false ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
 	global $wp_filesystem;
 
-	require_once( ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php' );
+	require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
 
 	$method = get_filesystem_method( $args, $context, $allow_relaxed_file_ownership );
 
@@ -1749,13 +1837,16 @@
 			return;
 		}
 
-		require_once( $abstraction_file );
+		require_once $abstraction_file;
 	}
 	$method = "WP_Filesystem_$method";
 
 	$wp_filesystem = new $method( $args );
 
-	//Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default.
+	/*
+	 * Define the timeouts for the connections. Only available after the constructor is called
+	 * to allow for per-transport overriding of the default.
+	 */
 	if ( ! defined( 'FS_CONNECT_TIMEOUT' ) ) {
 		define( 'FS_CONNECT_TIMEOUT', 30 );
 	}
@@ -1768,7 +1859,7 @@
 	}
 
 	if ( ! $wp_filesystem->connect() ) {
-		return false; //There was an error connecting to the server.
+		return false; // There was an error connecting to the server.
 	}
 
 	// Set the permission constants if not already set.
@@ -1793,7 +1884,7 @@
  * The return value can be overridden by defining the `FS_METHOD` constant in `wp-config.php`,
  * or filtering via {@see 'filesystem_method'}.
  *
- * @link https://codex.wordpress.org/Editing_wp-config.php#WordPress_Upgrade_Constants
+ * @link https://wordpress.org/support/article/editing-wp-config-php/#wordpress-upgrade-constants
  *
  * Plugins may define a custom transport handler, See WP_Filesystem().
  *
@@ -1809,7 +1900,8 @@
  * @return string The transport to use, see description for valid return values.
  */
 function get_filesystem_method( $args = array(), $context = '', $allow_relaxed_file_ownership = false ) {
-	$method = defined( 'FS_METHOD' ) ? FS_METHOD : false; // Please ensure that this is either 'direct', 'ssh2', 'ftpext' or 'ftpsockets'
+	// Please ensure that this is either 'direct', 'ssh2', 'ftpext', or 'ftpsockets'.
+	$method = defined( 'FS_METHOD' ) ? FS_METHOD : false;
 
 	if ( ! $context ) {
 		$context = WP_CONTENT_DIR;
@@ -1828,38 +1920,44 @@
 		$temp_handle    = @fopen( $temp_file_name, 'w' );
 		if ( $temp_handle ) {
 
-			// Attempt to determine the file owner of the WordPress files, and that of newly created files
-			$wp_file_owner = $temp_file_owner = false;
+			// Attempt to determine the file owner of the WordPress files, and that of newly created files.
+			$wp_file_owner   = false;
+			$temp_file_owner = false;
 			if ( function_exists( 'fileowner' ) ) {
 				$wp_file_owner   = @fileowner( __FILE__ );
 				$temp_file_owner = @fileowner( $temp_file_name );
 			}
 
-			if ( $wp_file_owner !== false && $wp_file_owner === $temp_file_owner ) {
-				// WordPress is creating files as the same owner as the WordPress files,
-				// this means it's safe to modify & create new files via PHP.
+			if ( false !== $wp_file_owner && $wp_file_owner === $temp_file_owner ) {
+				/*
+				 * WordPress is creating files as the same owner as the WordPress files,
+				 * this means it's safe to modify & create new files via PHP.
+				 */
 				$method                                  = 'direct';
 				$GLOBALS['_wp_filesystem_direct_method'] = 'file_owner';
 			} elseif ( $allow_relaxed_file_ownership ) {
-				// The $context directory is writable, and $allow_relaxed_file_ownership is set, this means we can modify files
-				// safely in this directory. This mode doesn't create new files, only alter existing ones.
+				/*
+				 * The $context directory is writable, and $allow_relaxed_file_ownership is set,
+				 * this means we can modify files safely in this directory.
+				 * This mode doesn't create new files, only alter existing ones.
+				 */
 				$method                                  = 'direct';
 				$GLOBALS['_wp_filesystem_direct_method'] = 'relaxed_ownership';
 			}
 
-			@fclose( $temp_handle );
+			fclose( $temp_handle );
 			@unlink( $temp_file_name );
 		}
 	}
 
-	if ( ! $method && isset( $args['connection_type'] ) && 'ssh' == $args['connection_type'] && extension_loaded( 'ssh2' ) && function_exists( 'stream_get_contents' ) ) {
+	if ( ! $method && isset( $args['connection_type'] ) && 'ssh' === $args['connection_type'] && extension_loaded( 'ssh2' ) ) {
 		$method = 'ssh2';
 	}
 	if ( ! $method && extension_loaded( 'ftp' ) ) {
 		$method = 'ftpext';
 	}
 	if ( ! $method && ( extension_loaded( 'sockets' ) || function_exists( 'fsockopen' ) ) ) {
-		$method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
+		$method = 'ftpsockets'; // Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread.
 	}
 
 	/**
@@ -1867,9 +1965,9 @@
 	 *
 	 * @since 2.6.0
 	 *
-	 * @param string $method  Filesystem method to return.
-	 * @param array  $args    An array of connection details for the method.
-	 * @param string $context Full path to the directory that is tested for being writable.
+	 * @param string $method                       Filesystem method to return.
+	 * @param array  $args                         An array of connection details for the method.
+	 * @param string $context                      Full path to the directory that is tested for being writable.
 	 * @param bool   $allow_relaxed_file_ownership Whether to allow Group/World writable.
 	 */
 	return apply_filters( 'filesystem_method', $method, $args, $context, $allow_relaxed_file_ownership );
@@ -1891,40 +1989,44 @@
  *
  * @global string $pagenow
  *
- * @param string $form_post                    The URL to post the form to.
- * @param string $type                         Optional. Chosen type of filesystem. Default empty.
- * @param bool   $error                        Optional. Whether the current request has failed to connect.
- *                                             Default false.
- * @param string $context                      Optional. Full path to the directory that is tested for being
- *                                             writable. Default empty.
- * @param array  $extra_fields                 Optional. Extra `POST` fields to be checked for inclusion in
- *                                             the post. Default null.
- * @param bool   $allow_relaxed_file_ownership Optional. Whether to allow Group/World writable. Default false.
- *
- * @return bool True on success, false on failure.
+ * @param string        $form_post                    The URL to post the form to.
+ * @param string        $type                         Optional. Chosen type of filesystem. Default empty.
+ * @param bool|WP_Error $error                        Optional. Whether the current request has failed
+ *                                                    to connect, or an error object. Default false.
+ * @param string        $context                      Optional. Full path to the directory that is tested
+ *                                                    for being writable. Default empty.
+ * @param array         $extra_fields                 Optional. Extra `POST` fields to be checked
+ *                                                    for inclusion in the post. Default null.
+ * @param bool          $allow_relaxed_file_ownership Optional. Whether to allow Group/World writable.
+ *                                                    Default false.
+ * @return bool|array True if no filesystem credentials are required,
+ *                    false if they are required but have not been provided,
+ *                    array of credentials if they are required and have been provided.
  */
 function request_filesystem_credentials( $form_post, $type = '', $error = false, $context = '', $extra_fields = null, $allow_relaxed_file_ownership = false ) {
 	global $pagenow;
 
 	/**
-	 * Filters the filesystem credentials form output.
+	 * Filters the filesystem credentials.
 	 *
 	 * Returning anything other than an empty string will effectively short-circuit
 	 * output of the filesystem credentials form, returning that value instead.
 	 *
+	 * A filter should return true if no filesystem credentials are required, false if they are required but have not been
+	 * provided, or an array of credentials if they are required and have been provided.
+	 *
 	 * @since 2.5.0
 	 * @since 4.6.0 The `$context` parameter default changed from `false` to an empty string.
 	 *
-	 * @param mixed  $output                       Form output to return instead. Default empty.
-	 * @param string $form_post                    The URL to post the form to.
-	 * @param string $type                         Chosen type of filesystem.
-	 * @param bool   $error                        Whether the current request has failed to connect.
-	 *                                             Default false.
-	 * @param string $context                      Full path to the directory that is tested for
-	 *                                             being writable.
-	 * @param bool   $allow_relaxed_file_ownership Whether to allow Group/World writable.
-	 *                                             Default false.
-	 * @param array  $extra_fields                 Extra POST fields.
+	 * @param mixed         $credentials                  Credentials to return instead. Default empty string.
+	 * @param string        $form_post                    The URL to post the form to.
+	 * @param string        $type                         Chosen type of filesystem.
+	 * @param bool|WP_Error $error                        Whether the current request has failed to connect,
+	 *                                                    or an error object.
+	 * @param string        $context                      Full path to the directory that is tested for
+	 *                                                    being writable.
+	 * @param array         $extra_fields                 Extra POST fields.
+	 * @param bool          $allow_relaxed_file_ownership Whether to allow Group/World writable.
 	 */
 	$req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
 	if ( '' !== $req_cred ) {
@@ -1935,7 +2037,7 @@
 		$type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
 	}
 
-	if ( 'direct' == $type ) {
+	if ( 'direct' === $type ) {
 		return true;
 	}
 
@@ -1953,7 +2055,7 @@
 
 	$submitted_form = wp_unslash( $_POST );
 
-	// Verify nonce, or unset submitted form field values on failure
+	// Verify nonce, or unset submitted form field values on failure.
 	if ( ! isset( $_POST['_fs_nonce'] ) || ! wp_verify_nonce( $_POST['_fs_nonce'], 'filesystem-credentials' ) ) {
 		unset(
 			$submitted_form['hostname'],
@@ -1965,17 +2067,17 @@
 		);
 	}
 
-	// If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
+	// If defined, set it to that. Else, if POST'd, set it to that. If not, set it to whatever it previously was (saved details in option).
 	$credentials['hostname'] = defined( 'FTP_HOST' ) ? FTP_HOST : ( ! empty( $submitted_form['hostname'] ) ? $submitted_form['hostname'] : $credentials['hostname'] );
 	$credentials['username'] = defined( 'FTP_USER' ) ? FTP_USER : ( ! empty( $submitted_form['username'] ) ? $submitted_form['username'] : $credentials['username'] );
 	$credentials['password'] = defined( 'FTP_PASS' ) ? FTP_PASS : ( ! empty( $submitted_form['password'] ) ? $submitted_form['password'] : '' );
 
-	// Check to see if we are setting the public/private keys for ssh
+	// Check to see if we are setting the public/private keys for ssh.
 	$credentials['public_key']  = defined( 'FTP_PUBKEY' ) ? FTP_PUBKEY : ( ! empty( $submitted_form['public_key'] ) ? $submitted_form['public_key'] : '' );
 	$credentials['private_key'] = defined( 'FTP_PRIKEY' ) ? FTP_PRIKEY : ( ! empty( $submitted_form['private_key'] ) ? $submitted_form['private_key'] : '' );
 
-	// Sanitize the hostname, Some people might pass in odd-data:
-	$credentials['hostname'] = preg_replace( '|\w+://|', '', $credentials['hostname'] ); //Strip any schemes off
+	// Sanitize the hostname, some people might pass in odd data.
+	$credentials['hostname'] = preg_replace( '|\w+://|', '', $credentials['hostname'] ); // Strip any schemes off.
 
 	if ( strpos( $credentials['hostname'], ':' ) ) {
 		list( $credentials['hostname'], $credentials['port'] ) = explode( ':', $credentials['hostname'], 2 );
@@ -1986,29 +2088,32 @@
 		unset( $credentials['port'] );
 	}
 
-	if ( ( defined( 'FTP_SSH' ) && FTP_SSH ) || ( defined( 'FS_METHOD' ) && 'ssh2' == FS_METHOD ) ) {
+	if ( ( defined( 'FTP_SSH' ) && FTP_SSH ) || ( defined( 'FS_METHOD' ) && 'ssh2' === FS_METHOD ) ) {
 		$credentials['connection_type'] = 'ssh';
-	} elseif ( ( defined( 'FTP_SSL' ) && FTP_SSL ) && 'ftpext' == $type ) { //Only the FTP Extension understands SSL
+	} elseif ( ( defined( 'FTP_SSL' ) && FTP_SSL ) && 'ftpext' === $type ) { // Only the FTP Extension understands SSL.
 		$credentials['connection_type'] = 'ftps';
 	} elseif ( ! empty( $submitted_form['connection_type'] ) ) {
 		$credentials['connection_type'] = $submitted_form['connection_type'];
-	} elseif ( ! isset( $credentials['connection_type'] ) ) { //All else fails (And it's not defaulted to something else saved), Default to FTP
+	} elseif ( ! isset( $credentials['connection_type'] ) ) { // All else fails (and it's not defaulted to something else saved), default to FTP.
 		$credentials['connection_type'] = 'ftp';
 	}
-	if ( ! $error &&
-			(
-				( ! empty( $credentials['password'] ) && ! empty( $credentials['username'] ) && ! empty( $credentials['hostname'] ) ) ||
-				( 'ssh' == $credentials['connection_type'] && ! empty( $credentials['public_key'] ) && ! empty( $credentials['private_key'] ) )
-			) ) {
+	if ( ! $error
+		&& ( ( ! empty( $credentials['password'] ) && ! empty( $credentials['username'] ) && ! empty( $credentials['hostname'] ) )
+			|| ( 'ssh' === $credentials['connection_type'] && ! empty( $credentials['public_key'] ) && ! empty( $credentials['private_key'] ) )
+		)
+	) {
 		$stored_credentials = $credentials;
-		if ( ! empty( $stored_credentials['port'] ) ) { //save port as part of hostname to simplify above code.
+
+		if ( ! empty( $stored_credentials['port'] ) ) { // Save port as part of hostname to simplify above code.
 			$stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
 		}
 
 		unset( $stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key'] );
+
 		if ( ! wp_installing() ) {
 			update_option( 'ftp_credentials', $stored_credentials );
 		}
+
 		return $credentials;
 	}
 	$hostname        = isset( $credentials['hostname'] ) ? $credentials['hostname'] : '';
@@ -2019,7 +2124,7 @@
 	$connection_type = isset( $credentials['connection_type'] ) ? $credentials['connection_type'] : '';
 
 	if ( $error ) {
-		$error_string = __( '<strong>ERROR:</strong> There was an error connecting to the server, Please verify the settings are correct.' );
+		$error_string = __( '<strong>Error</strong>: Could not connect to the server. Please verify the settings are correct.' );
 		if ( is_wp_error( $error ) ) {
 			$error_string = esc_html( $error->get_error_message() );
 		}
@@ -2030,10 +2135,10 @@
 	if ( extension_loaded( 'ftp' ) || extension_loaded( 'sockets' ) || function_exists( 'fsockopen' ) ) {
 		$types['ftp'] = __( 'FTP' );
 	}
-	if ( extension_loaded( 'ftp' ) ) { //Only this supports FTPS
+	if ( extension_loaded( 'ftp' ) ) { // Only this supports FTPS.
 		$types['ftps'] = __( 'FTPS (SSL)' );
 	}
-	if ( extension_loaded( 'ssh2' ) && function_exists( 'stream_get_contents' ) ) {
+	if ( extension_loaded( 'ssh2' ) ) {
 		$types['ssh'] = __( 'SSH2' );
 	}
 
@@ -2043,12 +2148,12 @@
 	 * @since 2.9.0
 	 * @since 4.6.0 The `$context` parameter default changed from `false` to an empty string.
 	 *
-	 * @param array  $types       Types of connections.
-	 * @param array  $credentials Credentials to connect with.
-	 * @param string $type        Chosen filesystem method.
-	 * @param object $error       Error object.
-	 * @param string $context     Full path to the directory that is tested
-	 *                            for being writable.
+	 * @param string[]      $types       Types of connections.
+	 * @param array         $credentials Credentials to connect with.
+	 * @param string        $type        Chosen filesystem method.
+	 * @param bool|WP_Error $error       Whether the current request has failed to connect,
+	 *                                   or an error object.
+	 * @param string        $context     Full path to the directory that is tested for being writable.
 	 */
 	$types = apply_filters( 'fs_ftp_connection_types', $types, $credentials, $type, $error, $context );
 
@@ -2133,7 +2238,7 @@
 	<?php
 	if ( isset( $types['ssh'] ) ) {
 		$hidden_class = '';
-		if ( 'ssh' != $connection_type || empty( $connection_type ) ) {
+		if ( 'ssh' !== $connection_type || empty( $connection_type ) ) {
 			$hidden_class = ' class="hidden"';
 		}
 		?>
@@ -2170,16 +2275,18 @@
 }
 
 /**
- * Print the filesystem credentials modal when needed.
+ * Prints the filesystem credentials modal when needed.
  *
  * @since 4.2.0
  */
 function wp_print_request_filesystem_credentials_modal() {
 	$filesystem_method = get_filesystem_method();
+
 	ob_start();
 	$filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() );
 	ob_end_clean();
-	$request_filesystem_credentials = ( $filesystem_method != 'direct' && ! $filesystem_credentials_are_stored );
+
+	$request_filesystem_credentials = ( 'direct' !== $filesystem_method && ! $filesystem_credentials_are_stored );
 	if ( ! $request_filesystem_credentials ) {
 		return;
 	}
@@ -2196,456 +2303,74 @@
 }
 
 /**
- * Generate a single group for the personal data export report.
- *
- * @since 4.9.6
- *
- * @param array $group_data {
- *     The group data to render.
+ * Attempts to clear the opcode cache for an individual PHP file.
  *
- *     @type string $group_label  The user-facing heading for the group, e.g. 'Comments'.
- *     @type array  $items        {
- *         An array of group items.
+ * This function can be called safely without having to check the file extension
+ * or availability of the OPcache extension.
  *
- *         @type array  $group_item_data  {
- *             An array of name-value pairs for the item.
+ * Whether or not invalidation is possible is cached to improve performance.
  *
- *             @type string $name   The user-facing name of an item name-value pair, e.g. 'IP Address'.
- *             @type string $value  The user-facing value of an item data pair, e.g. '50.60.70.0'.
- *         }
- *     }
- * }
- * @return string The HTML for this group and its items.
- */
-function wp_privacy_generate_personal_data_export_group_html( $group_data ) {
-	$group_html  = '<h2>' . esc_html( $group_data['group_label'] ) . '</h2>';
-	$group_html .= '<div>';
-
-	foreach ( (array) $group_data['items'] as $group_item_id => $group_item_data ) {
-		$group_html .= '<table>';
-		$group_html .= '<tbody>';
-
-		foreach ( (array) $group_item_data as $group_item_datum ) {
-			$value = $group_item_datum['value'];
-			// If it looks like a link, make it a link.
-			if ( false === strpos( $value, ' ' ) && ( 0 === strpos( $value, 'http://' ) || 0 === strpos( $value, 'https://' ) ) ) {
-				$value = '<a href="' . esc_url( $value ) . '">' . esc_html( $value ) . '</a>';
-			}
-
-			$group_html .= '<tr>';
-			$group_html .= '<th>' . esc_html( $group_item_datum['name'] ) . '</th>';
-			$group_html .= '<td>' . wp_kses( $value, 'personal_data_export' ) . '</td>';
-			$group_html .= '</tr>';
-		}
-
-		$group_html .= '</tbody>';
-		$group_html .= '</table>';
-	}
-
-	$group_html .= '</div>';
-
-	return $group_html;
-}
-
-/**
- * Generate the personal data export file.
+ * @since 5.5.0
+ *
+ * @link https://www.php.net/manual/en/function.opcache-invalidate.php
  *
- * @since 4.9.6
- *
- * @param int $request_id The export request ID.
+ * @param string $filepath Path to the file, including extension, for which the opcode cache is to be cleared.
+ * @param bool   $force    Invalidate even if the modification time is not newer than the file in cache.
+ *                         Default false.
+ * @return bool True if opcache was invalidated for `$filepath`, or there was nothing to invalidate.
+ *              False if opcache invalidation is not available, or is disabled via filter.
  */
-function wp_privacy_generate_personal_data_export_file( $request_id ) {
-	if ( ! class_exists( 'ZipArchive' ) ) {
-		wp_send_json_error( __( 'Unable to generate export file. ZipArchive not available.' ) );
-	}
-
-	// Get the request data.
-	$request = wp_get_user_request_data( $request_id );
-
-	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
-		wp_send_json_error( __( 'Invalid request ID when generating export file.' ) );
-	}
-
-	$email_address = $request->email;
-
-	if ( ! is_email( $email_address ) ) {
-		wp_send_json_error( __( 'Invalid email address when generating export file.' ) );
-	}
-
-	// Create the exports folder if needed.
-	$exports_dir = wp_privacy_exports_dir();
-	$exports_url = wp_privacy_exports_url();
-
-	if ( ! wp_mkdir_p( $exports_dir ) ) {
-		wp_send_json_error( __( 'Unable to create export folder.' ) );
-	}
-
-	// Protect export folder from browsing.
-	$index_pathname = $exports_dir . 'index.html';
-	if ( ! file_exists( $index_pathname ) ) {
-		$file = fopen( $index_pathname, 'w' );
-		if ( false === $file ) {
-			wp_send_json_error( __( 'Unable to protect export folder from browsing.' ) );
-		}
-		fwrite( $file, '<!-- Silence is golden. -->' );
-		fclose( $file );
-	}
-
-	$stripped_email       = str_replace( '@', '-at-', $email_address );
-	$stripped_email       = sanitize_title( $stripped_email ); // slugify the email address
-	$obscura              = wp_generate_password( 32, false, false );
-	$file_basename        = 'wp-personal-data-file-' . $stripped_email . '-' . $obscura;
-	$html_report_filename = $file_basename . '.html';
-	$html_report_pathname = wp_normalize_path( $exports_dir . $html_report_filename );
-	$file                 = fopen( $html_report_pathname, 'w' );
-	if ( false === $file ) {
-		wp_send_json_error( __( 'Unable to open export file (HTML report) for writing.' ) );
-	}
-
-	$title = sprintf(
-		/* translators: %s: user's email address */
-		__( 'Personal Data Export for %s' ),
-		$email_address
-	);
-
-	// Open HTML.
-	fwrite( $file, "<!DOCTYPE html>\n" );
-	fwrite( $file, "<html>\n" );
-
-	// Head.
-	fwrite( $file, "<head>\n" );
-	fwrite( $file, "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n" );
-	fwrite( $file, "<style type='text/css'>" );
-	fwrite( $file, 'body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }' );
-	fwrite( $file, 'table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }' );
-	fwrite( $file, 'th { padding: 5px; text-align: left; width: 20%; }' );
-	fwrite( $file, 'td { padding: 5px; }' );
-	fwrite( $file, 'tr:nth-child(odd) { background-color: #fafafa; }' );
-	fwrite( $file, '</style>' );
-	fwrite( $file, '<title>' );
-	fwrite( $file, esc_html( $title ) );
-	fwrite( $file, '</title>' );
-	fwrite( $file, "</head>\n" );
-
-	// Body.
-	fwrite( $file, "<body>\n" );
-
-	// Heading.
-	fwrite( $file, '<h1>' . esc_html__( 'Personal Data Export' ) . '</h1>' );
-
-	// And now, all the Groups.
-	$groups = get_post_meta( $request_id, '_export_data_grouped', true );
-
-	// First, build an "About" group on the fly for this report.
-	$about_group = array(
-		/* translators: Header for the About section in a personal data export. */
-		'group_label' => _x( 'About', 'personal data group label' ),
-		'items'       => array(
-			'about-1' => array(
-				array(
-					'name'  => _x( 'Report generated for', 'email address' ),
-					'value' => $email_address,
-				),
-				array(
-					'name'  => _x( 'For site', 'website name' ),
-					'value' => get_bloginfo( 'name' ),
-				),
-				array(
-					'name'  => _x( 'At URL', 'website URL' ),
-					'value' => get_bloginfo( 'url' ),
-				),
-				array(
-					'name'  => _x( 'On', 'date/time' ),
-					'value' => current_time( 'mysql' ),
-				),
-			),
-		),
-	);
-
-	// Merge in the special about group.
-	$groups = array_merge( array( 'about' => $about_group ), $groups );
-
-	// Now, iterate over every group in $groups and have the formatter render it in HTML.
-	foreach ( (array) $groups as $group_id => $group_data ) {
-		fwrite( $file, wp_privacy_generate_personal_data_export_group_html( $group_data ) );
-	}
-
-	fwrite( $file, "</body>\n" );
-
-	// Close HTML.
-	fwrite( $file, "</html>\n" );
-	fclose( $file );
+function wp_opcache_invalidate( $filepath, $force = false ) {
+	static $can_invalidate = null;
 
 	/*
-	 * Now, generate the ZIP.
+	 * Check to see if WordPress is able to run `opcache_invalidate()` or not, and cache the value.
+	 *
+	 * First, check to see if the function is available to call, then if the host has restricted
+	 * the ability to run the function to avoid a PHP warning.
+	 *
+	 * `opcache.restrict_api` can specify the path for files allowed to call `opcache_invalidate()`.
 	 *
-	 * If an archive has already been generated, then remove it and reuse the
-	 * filename, to avoid breaking any URLs that may have been previously sent
-	 * via email.
+	 * If the host has this set, check whether the path in `opcache.restrict_api` matches
+	 * the beginning of the path of the origin file.
+	 *
+	 * `$_SERVER['SCRIPT_FILENAME']` approximates the origin file's path, but `realpath()`
+	 * is necessary because `SCRIPT_FILENAME` can be a relative path when run from CLI.
+	 *
+	 * For more details, see:
+	 * - https://www.php.net/manual/en/opcache.configuration.php
+	 * - https://www.php.net/manual/en/reserved.variables.server.php
+	 * - https://core.trac.wordpress.org/ticket/36455
 	 */
-	$error            = false;
-	$archive_url      = get_post_meta( $request_id, '_export_file_url', true );
-	$archive_pathname = get_post_meta( $request_id, '_export_file_path', true );
-
-	if ( empty( $archive_pathname ) || empty( $archive_url ) ) {
-		$archive_filename = $file_basename . '.zip';
-		$archive_pathname = $exports_dir . $archive_filename;
-		$archive_url      = $exports_url . $archive_filename;
-
-		update_post_meta( $request_id, '_export_file_url', $archive_url );
-		update_post_meta( $request_id, '_export_file_path', wp_normalize_path( $archive_pathname ) );
-	}
-
-	if ( ! empty( $archive_pathname ) && file_exists( $archive_pathname ) ) {
-		wp_delete_file( $archive_pathname );
+	if ( null === $can_invalidate
+		&& function_exists( 'opcache_invalidate' )
+		&& ( ! ini_get( 'opcache.restrict_api' )
+			|| stripos( realpath( $_SERVER['SCRIPT_FILENAME'] ), ini_get( 'opcache.restrict_api' ) ) === 0 )
+	) {
+		$can_invalidate = true;
 	}
 
-	$zip = new ZipArchive;
-	if ( true === $zip->open( $archive_pathname, ZipArchive::CREATE ) ) {
-		if ( ! $zip->addFile( $html_report_pathname, 'index.html' ) ) {
-			$error = __( 'Unable to add data to export file.' );
-		}
-
-		$zip->close();
-
-		if ( ! $error ) {
-			/**
-			 * Fires right after all personal data has been written to the export file.
-			 *
-			 * @since 4.9.6
-			 *
-			 * @param string $archive_pathname     The full path to the export file on the filesystem.
-			 * @param string $archive_url          The URL of the archive file.
-			 * @param string $html_report_pathname The full path to the personal data report on the filesystem.
-			 * @param int    $request_id           The export request ID.
-			 */
-			do_action( 'wp_privacy_personal_data_export_file_created', $archive_pathname, $archive_url, $html_report_pathname, $request_id );
-		}
-	} else {
-		$error = __( 'Unable to open export file (archive) for writing.' );
-	}
-
-	// And remove the HTML file.
-	unlink( $html_report_pathname );
-
-	if ( $error ) {
-		wp_send_json_error( $error );
-	}
-}
-
-/**
- * Send an email to the user with a link to the personal data export file
- *
- * @since 4.9.6
- *
- * @param int $request_id The request ID for this personal data export.
- * @return true|WP_Error True on success or `WP_Error` on failure.
- */
-function wp_privacy_send_personal_data_export_email( $request_id ) {
-	// Get the request data.
-	$request = wp_get_user_request_data( $request_id );
-
-	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
-		return new WP_Error( 'invalid_request', __( 'Invalid request ID when sending personal data export email.' ) );
-	}
-
-	// Localize message content for user; fallback to site default for visitors.
-	if ( ! empty( $request->user_id ) ) {
-		$locale = get_user_locale( $request->user_id );
-	} else {
-		$locale = get_locale();
+	// If invalidation is not available, return early.
+	if ( ! $can_invalidate ) {
+		return false;
 	}
 
-	$switched_locale = switch_to_locale( $locale );
-
-	/** This filter is documented in wp-includes/functions.php */
-	$expiration      = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
-	$expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration );
-
-	/* translators: Do not translate EXPIRATION, LINK, SITENAME, SITEURL: those are placeholders. */
-	$email_text = __(
-		'Howdy,
-
-Your request for an export of personal data has been completed. You may
-download your personal data by clicking on the link below. For privacy
-and security, we will automatically delete the file on ###EXPIRATION###,
-so please download it before then.
-
-###LINK###
-
-Regards,
-All at ###SITENAME###
-###SITEURL###'
-	);
-
-	/**
-	 * Filters the text of the email sent with a personal data export file.
-	 *
-	 * The following strings have a special meaning and will get replaced dynamically:
-	 * ###EXPIRATION###         The date when the URL will be automatically deleted.
-	 * ###LINK###               URL of the personal data export file for the user.
-	 * ###SITENAME###           The name of the site.
-	 * ###SITEURL###            The URL to the site.
-	 *
-	 * @since 4.9.6
-	 *
-	 * @param string $email_text     Text in the email.
-	 * @param int    $request_id     The request ID for this personal data export.
-	 */
-	$content = apply_filters( 'wp_privacy_personal_data_email_content', $email_text, $request_id );
-
-	$email_address   = $request->email;
-	$export_file_url = get_post_meta( $request_id, '_export_file_url', true );
-	$site_name       = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
-	$site_url        = home_url();
-
-	$content = str_replace( '###EXPIRATION###', $expiration_date, $content );
-	$content = str_replace( '###LINK###', esc_url_raw( $export_file_url ), $content );
-	$content = str_replace( '###EMAIL###', $email_address, $content );
-	$content = str_replace( '###SITENAME###', $site_name, $content );
-	$content = str_replace( '###SITEURL###', esc_url_raw( $site_url ), $content );
-
-	$mail_success = wp_mail(
-		$email_address,
-		sprintf(
-			/* translators: Personal data export notification email subject. %s: Site title */
-			__( '[%s] Personal Data Export' ),
-			$site_name
-		),
-		$content
-	);
-
-	if ( $switched_locale ) {
-		restore_previous_locale();
-	}
-
-	if ( ! $mail_success ) {
-		return new WP_Error( 'privacy_email_error', __( 'Unable to send personal data export email.' ) );
+	// Verify that file to be invalidated has a PHP extension.
+	if ( '.php' !== strtolower( substr( $filepath, -4 ) ) ) {
+		return false;
 	}
 
-	return true;
-}
-
-/**
- * Intercept personal data exporter page ajax responses in order to assemble the personal data export file.
- * @see wp_privacy_personal_data_export_page
- * @since 4.9.6
- *
- * @param array  $response        The response from the personal data exporter for the given page.
- * @param int    $exporter_index  The index of the personal data exporter. Begins at 1.
- * @param string $email_address   The email address of the user whose personal data this is.
- * @param int    $page            The page of personal data for this exporter. Begins at 1.
- * @param int    $request_id      The request ID for this personal data export.
- * @param bool   $send_as_email   Whether the final results of the export should be emailed to the user.
- * @param string $exporter_key    The slug (key) of the exporter.
- * @return array The filtered response.
- */
-function wp_privacy_process_personal_data_export_page( $response, $exporter_index, $email_address, $page, $request_id, $send_as_email, $exporter_key ) {
-	/* Do some simple checks on the shape of the response from the exporter.
-	 * If the exporter response is malformed, don't attempt to consume it - let it
-	 * pass through to generate a warning to the user by default ajax processing.
+	/**
+	 * Filters whether to invalidate a file from the opcode cache.
+	 *
+	 * @since 5.5.0
+	 *
+	 * @param bool   $will_invalidate Whether WordPress will invalidate `$filepath`. Default true.
+	 * @param string $filepath        The path to the PHP file to invalidate.
 	 */
-	if ( ! is_array( $response ) ) {
-		return $response;
-	}
-
-	if ( ! array_key_exists( 'done', $response ) ) {
-		return $response;
-	}
-
-	if ( ! array_key_exists( 'data', $response ) ) {
-		return $response;
-	}
-
-	if ( ! is_array( $response['data'] ) ) {
-		return $response;
-	}
-
-	// Get the request data.
-	$request = wp_get_user_request_data( $request_id );
-
-	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
-		wp_send_json_error( __( 'Invalid request ID when merging exporter data.' ) );
-	}
-
-	$export_data = array();
-
-	// First exporter, first page? Reset the report data accumulation array.
-	if ( 1 === $exporter_index && 1 === $page ) {
-		update_post_meta( $request_id, '_export_data_raw', $export_data );
-	} else {
-		$export_data = get_post_meta( $request_id, '_export_data_raw', true );
+	if ( apply_filters( 'wp_opcache_invalidate_file', true, $filepath ) ) {
+		return opcache_invalidate( $filepath, $force );
 	}
 
-	// Now, merge the data from the exporter response into the data we have accumulated already.
-	$export_data = array_merge( $export_data, $response['data'] );
-	update_post_meta( $request_id, '_export_data_raw', $export_data );
-
-	// If we are not yet on the last page of the last exporter, return now.
-	/** This filter is documented in wp-admin/includes/ajax-actions.php */
-	$exporters        = apply_filters( 'wp_privacy_personal_data_exporters', array() );
-	$is_last_exporter = $exporter_index === count( $exporters );
-	$exporter_done    = $response['done'];
-	if ( ! $is_last_exporter || ! $exporter_done ) {
-		return $response;
-	}
-
-	// Last exporter, last page - let's prepare the export file.
-
-	// First we need to re-organize the raw data hierarchically in groups and items.
-	$groups = array();
-	foreach ( (array) $export_data as $export_datum ) {
-		$group_id    = $export_datum['group_id'];
-		$group_label = $export_datum['group_label'];
-		if ( ! array_key_exists( $group_id, $groups ) ) {
-			$groups[ $group_id ] = array(
-				'group_label' => $group_label,
-				'items'       => array(),
-			);
-		}
-
-		$item_id = $export_datum['item_id'];
-		if ( ! array_key_exists( $item_id, $groups[ $group_id ]['items'] ) ) {
-			$groups[ $group_id ]['items'][ $item_id ] = array();
-		}
-
-		$old_item_data                            = $groups[ $group_id ]['items'][ $item_id ];
-		$merged_item_data                         = array_merge( $export_datum['data'], $old_item_data );
-		$groups[ $group_id ]['items'][ $item_id ] = $merged_item_data;
-	}
-
-	// Then save the grouped data into the request.
-	delete_post_meta( $request_id, '_export_data_raw' );
-	update_post_meta( $request_id, '_export_data_grouped', $groups );
-
-	/**
-	 * Generate the export file from the collected, grouped personal data.
-	 *
-	 * @since 4.9.6
-	 *
-	 * @param int $request_id The export request ID.
-	 */
-	do_action( 'wp_privacy_personal_data_export_file', $request_id );
-
-	// Clear the grouped data now that it is no longer needed.
-	delete_post_meta( $request_id, '_export_data_grouped' );
-
-	// If the destination is email, send it now.
-	if ( $send_as_email ) {
-		$mail_success = wp_privacy_send_personal_data_export_email( $request_id );
-		if ( is_wp_error( $mail_success ) ) {
-			wp_send_json_error( $mail_success->get_error_message() );
-		}
-
-		// Update the request to completed state when the export email is sent.
-		_wp_privacy_completed_request( $request_id );
-	} else {
-		// Modify the response to include the URL of the export file so the browser can fetch it.
-		$export_file_url = get_post_meta( $request_id, '_export_file_url', true );
-		if ( ! empty( $export_file_url ) ) {
-			$response['url'] = $export_file_url;
-		}
-	}
-
-	return $response;
+	return false;
 }