diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-admin/includes/file.php --- 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 @@
{{ data.message }}<# } else if ( 'file_not_writable' === data.code ) { #> -
the Codex for more information.' ); ?>
++ Changing File Permissions for more information.' ), + __( 'https://wordpress.org/support/article/changing-file-permissions/' ) + ); + ?> +
<# } else { #>{{ data.message || data.code }}
@@ -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 = __( 'ERROR: There was an error connecting to the server, Please verify the settings are correct.' ); + $error_string = __( 'Error: 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 @@ @@ -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 = '' . esc_html( $group_item_datum['name'] ) . ' | '; - $group_html .= '' . wp_kses( $value, 'personal_data_export' ) . ' | '; - $group_html .= '
---|