--- 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;
}