wp/wp-admin/includes/class-wp-upgrader.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
--- a/wp/wp-admin/includes/class-wp-upgrader.php	Tue Oct 22 16:11:46 2019 +0200
+++ b/wp/wp-admin/includes/class-wp-upgrader.php	Tue Dec 15 13:49:49 2020 +0100
@@ -76,17 +76,17 @@
 	 *
 	 * @since 2.8.0
 	 *
-	 * @var WP_Error|array $result {
-	 *      @type string $source             The full path to the source the files were installed from.
-	 *      @type string $source_files       List of all the files in the source directory.
-	 *      @type string $destination        The full path to the installation destination folder.
-	 *      @type string $destination_name   The name of the destination folder, or empty if `$destination`
-	 *                                       and `$local_destination` are the same.
-	 *      @type string $local_destination  The full local path to the destination folder. This is usually
-	 *                                       the same as `$destination`.
-	 *      @type string $remote_destination The full remote path to the destination folder
-	 *                                       (i.e., from `$wp_filesystem`).
-	 *      @type bool   $clear_destination  Whether the destination folder was cleared.
+	 * @var array|WP_Error $result {
+	 *     @type string $source             The full path to the source the files were installed from.
+	 *     @type string $source_files       List of all the files in the source directory.
+	 *     @type string $destination        The full path to the installation destination folder.
+	 *     @type string $destination_name   The name of the destination folder, or empty if `$destination`
+	 *                                      and `$local_destination` are the same.
+	 *     @type string $local_destination  The full local path to the destination folder. This is usually
+	 *                                      the same as `$destination`.
+	 *     @type string $remote_destination The full remote path to the destination folder
+	 *                                      (i.e., from `$wp_filesystem`).
+	 *     @type bool   $clear_destination  Whether the destination folder was cleared.
 	 * }
 	 */
 	public $result = array();
@@ -116,7 +116,7 @@
 	 *
 	 * @since 2.8.0
 	 *
-	 * @param WP_Upgrader_Skin $skin The upgrader skin to use. Default is a WP_Upgrader_Skin.
+	 * @param WP_Upgrader_Skin $skin The upgrader skin to use. Default is a WP_Upgrader_Skin
 	 *                               instance.
 	 */
 	public function __construct( $skin = null ) {
@@ -153,7 +153,7 @@
 		$this->strings['fs_no_content_dir'] = __( 'Unable to locate WordPress content directory (wp-content).' );
 		$this->strings['fs_no_plugins_dir'] = __( 'Unable to locate WordPress plugin directory.' );
 		$this->strings['fs_no_themes_dir']  = __( 'Unable to locate WordPress theme directory.' );
-		/* translators: %s: directory name */
+		/* translators: %s: Directory name. */
 		$this->strings['fs_no_folder'] = __( 'Unable to locate needed folder (%s).' );
 
 		$this->strings['download_failed']      = __( 'Download failed.' );
@@ -175,17 +175,18 @@
 	 *
 	 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 	 *
-	 * @param array $directories                  Optional. A list of directories. If any of these do
-	 *                                            not exist, a WP_Error object will be returned.
-	 *                                            Default empty array.
-	 * @param bool  $allow_relaxed_file_ownership Whether to allow relaxed file ownership.
-	 *                                            Default false.
+	 * @param string[] $directories                  Optional. Array of directories. If any of these do
+	 *                                               not exist, a WP_Error object will be returned.
+	 *                                               Default empty array.
+	 * @param bool     $allow_relaxed_file_ownership Whether to allow relaxed file ownership.
+	 *                                               Default false.
 	 * @return bool|WP_Error True if able to connect, false or a WP_Error otherwise.
 	 */
 	public function fs_connect( $directories = array(), $allow_relaxed_file_ownership = false ) {
 		global $wp_filesystem;
 
-		if ( false === ( $credentials = $this->skin->request_filesystem_credentials( false, $directories[0], $allow_relaxed_file_ownership ) ) ) {
+		$credentials = $this->skin->request_filesystem_credentials( false, $directories[0], $allow_relaxed_file_ownership );
+		if ( false === $credentials ) {
 			return false;
 		}
 
@@ -194,7 +195,7 @@
 			if ( is_object( $wp_filesystem ) && $wp_filesystem->errors->has_errors() ) {
 				$error = $wp_filesystem->errors;
 			}
-			// Failed to connect, Error and request again
+			// Failed to connect. Error and request again.
 			$this->skin->request_filesystem_credentials( $error, $directories[0], $allow_relaxed_file_ownership );
 			return false;
 		}
@@ -237,37 +238,40 @@
 			}
 		}
 		return true;
-	} //end fs_connect();
+	}
 
 	/**
 	 * Download a package.
 	 *
 	 * @since 2.8.0
+	 * @since 5.5.0 Added the `$hook_extra` parameter.
 	 *
 	 * @param string $package          The URI of the package. If this is the full path to an
 	 *                                 existing local file, it will be returned untouched.
 	 * @param bool   $check_signatures Whether to validate file signatures. Default false.
+	 * @param array  $hook_extra       Extra arguments to pass to the filter hooks. Default empty array.
 	 * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object.
 	 */
-	public function download_package( $package, $check_signatures = false ) {
-
+	public function download_package( $package, $check_signatures = false, $hook_extra = array() ) {
 		/**
 		 * Filters whether to return the package.
 		 *
 		 * @since 3.7.0
+		 * @since 5.5.0 Added the `$hook_extra` parameter.
 		 *
-		 * @param bool        $reply   Whether to bail without returning the package.
-		 *                             Default false.
-		 * @param string      $package The package file name.
-		 * @param WP_Upgrader $this    The WP_Upgrader instance.
+		 * @param bool        $reply      Whether to bail without returning the package.
+		 *                                Default false.
+		 * @param string      $package    The package file name.
+		 * @param WP_Upgrader $this       The WP_Upgrader instance.
+		 * @param array       $hook_extra Extra arguments passed to hooked filters.
 		 */
-		$reply = apply_filters( 'upgrader_pre_download', false, $package, $this );
+		$reply = apply_filters( 'upgrader_pre_download', false, $package, $this, $hook_extra );
 		if ( false !== $reply ) {
 			return $reply;
 		}
 
-		if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { //Local file or remote?
-			return $package; //must be a local file..
+		if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { // Local file or remote?
+			return $package; // Must be a local file.
 		}
 
 		if ( empty( $package ) ) {
@@ -304,7 +308,7 @@
 
 		$upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
 
-		//Clean up contents of upgrade directory beforehand.
+		// Clean up contents of upgrade directory beforehand.
 		$upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
 		if ( ! empty( $upgrade_files ) ) {
 			foreach ( $upgrade_files as $file ) {
@@ -312,15 +316,15 @@
 			}
 		}
 
-		// We need a working directory - Strip off any .tmp or .zip suffixes
+		// We need a working directory - strip off any .tmp or .zip suffixes.
 		$working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
 
-		// Clean up working directory
+		// Clean up working directory.
 		if ( $wp_filesystem->is_dir( $working_dir ) ) {
 			$wp_filesystem->delete( $working_dir, true );
 		}
 
-		// Unzip package to working directory
+		// Unzip package to working directory.
 		$result = unzip_file( $package, $working_dir );
 
 		// Once extracted, delete the package if required.
@@ -330,7 +334,7 @@
 
 		if ( is_wp_error( $result ) ) {
 			$wp_filesystem->delete( $working_dir, true );
-			if ( 'incompatible_archive' == $result->get_error_code() ) {
+			if ( 'incompatible_archive' === $result->get_error_code() ) {
 				return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() );
 			}
 			return $result;
@@ -345,9 +349,9 @@
 	 * @since 4.9.0
 	 * @access protected
 	 *
-	 * @param  array  $nested_files  Array of files as returned by WP_Filesystem::dirlist()
-	 * @param  string $path          Relative path to prepend to child nodes. Optional.
-	 * @return array $files A flattened array of the $nested_files specified.
+	 * @param array  $nested_files Array of files as returned by WP_Filesystem::dirlist().
+	 * @param string $path         Relative path to prepend to child nodes. Optional.
+	 * @return array A flattened array of the $nested_files specified.
 	 */
 	protected function flatten_dirlist( $nested_files, $path = '' ) {
 		$files = array();
@@ -355,11 +359,11 @@
 		foreach ( $nested_files as $name => $details ) {
 			$files[ $path . $name ] = $details;
 
-			// Append children recursively
+			// Append children recursively.
 			if ( ! empty( $details['files'] ) ) {
 				$children = $this->flatten_dirlist( $details['files'], $path . $name . '/' );
 
-				// Merge keeping possible numeric keys, which array_merge() will reindex from 0..n
+				// Merge keeping possible numeric keys, which array_merge() will reindex from 0..n.
 				$files = $files + $children;
 			}
 		}
@@ -387,7 +391,7 @@
 			return true;
 		}
 
-		// Flatten the file list to iterate over
+		// Flatten the file list to iterate over.
 		$files = $this->flatten_dirlist( $files );
 
 		// Check all files are writable before attempting to clear the destination.
@@ -397,7 +401,7 @@
 		foreach ( $files as $filename => $file_details ) {
 			if ( ! $wp_filesystem->is_writable( $remote_destination . $filename ) ) {
 				// Attempt to alter permissions to allow writes and try again.
-				$wp_filesystem->chmod( $remote_destination . $filename, ( 'd' == $file_details['type'] ? FS_CHMOD_DIR : FS_CHMOD_FILE ) );
+				$wp_filesystem->chmod( $remote_destination . $filename, ( 'd' === $file_details['type'] ? FS_CHMOD_DIR : FS_CHMOD_FILE ) );
 				if ( ! $wp_filesystem->is_writable( $remote_destination . $filename ) ) {
 					$unwritable_files[] = $filename;
 				}
@@ -449,8 +453,8 @@
 		global $wp_filesystem, $wp_theme_directories;
 
 		$defaults = array(
-			'source'                      => '', // Please always pass this
-			'destination'                 => '', // and this
+			'source'                      => '', // Please always pass this.
+			'destination'                 => '', // ...and this.
 			'clear_destination'           => false,
 			'clear_working'               => false,
 			'abort_if_destination_exists' => true,
@@ -464,7 +468,7 @@
 		$destination       = $args['destination'];
 		$clear_destination = $args['clear_destination'];
 
-		@set_time_limit( 300 );
+		set_time_limit( 300 );
 
 		if ( empty( $source ) || empty( $destination ) ) {
 			return new WP_Error( 'bad_request', $this->strings['bad_request'] );
@@ -489,19 +493,23 @@
 			return $res;
 		}
 
-		//Retain the Original source and destinations
+		// Retain the original source and destinations.
 		$remote_source     = $args['source'];
 		$local_destination = $destination;
 
 		$source_files       = array_keys( $wp_filesystem->dirlist( $remote_source ) );
 		$remote_destination = $wp_filesystem->find_folder( $local_destination );
 
-		//Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
-		if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { //Only one folder? Then we want its contents.
+		// Locate which directory to copy to the new folder. This is based on the actual folder holding the files.
+		if ( 1 === count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) {
+			// Only one folder? Then we want its contents.
 			$source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] );
 		} elseif ( count( $source_files ) == 0 ) {
-			return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
-		} else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename.
+			// There are no files?
+			return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] );
+		} else {
+			// It's only a single file, the upgrader will use the folder name of this file as the destination folder.
+			// Folder name is based on zip filename.
 			$source = trailingslashit( $args['source'] );
 		}
 
@@ -540,7 +548,7 @@
 			$protected_directories = array_merge( $protected_directories, $wp_theme_directories );
 		}
 
-		if ( in_array( $destination, $protected_directories ) ) {
+		if ( in_array( $destination, $protected_directories, true ) ) {
 			$remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) );
 			$destination        = trailingslashit( $destination ) . trailingslashit( basename( $source ) );
 		}
@@ -556,10 +564,10 @@
 			 *
 			 * @since 2.8.0
 			 *
-			 * @param mixed  $removed            Whether the destination was cleared. true on success, WP_Error on failure
-			 * @param string $local_destination  The local package destination.
-			 * @param string $remote_destination The remote package destination.
-			 * @param array  $hook_extra         Extra arguments passed to hooked filters.
+			 * @param true|WP_Error $removed            Whether the destination was cleared. true upon success, WP_Error on failure.
+			 * @param string        $local_destination  The local package destination.
+			 * @param string        $remote_destination The remote package destination.
+			 * @param array         $hook_extra         Extra arguments passed to hooked filters.
 			 */
 			$removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
 
@@ -567,21 +575,22 @@
 				return $removed;
 			}
 		} elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists( $remote_destination ) ) {
-			//If we're not clearing the destination folder and something exists there already, Bail.
-			//But first check to see if there are actually any files in the folder.
+			// If we're not clearing the destination folder and something exists there already, bail.
+			// But first check to see if there are actually any files in the folder.
 			$_files = $wp_filesystem->dirlist( $remote_destination );
 			if ( ! empty( $_files ) ) {
-				$wp_filesystem->delete( $remote_source, true ); //Clear out the source files.
+				$wp_filesystem->delete( $remote_source, true ); // Clear out the source files.
 				return new WP_Error( 'folder_exists', $this->strings['folder_exists'], $remote_destination );
 			}
 		}
 
-		//Create destination if needed
+		// Create destination if needed.
 		if ( ! $wp_filesystem->exists( $remote_destination ) ) {
 			if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) {
 				return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
 			}
 		}
+
 		// Copy new version of item into place.
 		$result = copy_dir( $source, $remote_destination );
 		if ( is_wp_error( $result ) ) {
@@ -591,13 +600,13 @@
 			return $result;
 		}
 
-		//Clear the Working folder?
+		// Clear the working folder?
 		if ( $args['clear_working'] ) {
 			$wp_filesystem->delete( $remote_source, true );
 		}
 
 		$destination_name = basename( str_replace( $local_destination, '', $destination ) );
-		if ( '.' == $destination_name ) {
+		if ( '.' === $destination_name ) {
 			$destination_name = '';
 		}
 
@@ -619,7 +628,7 @@
 			return $res;
 		}
 
-		//Bombard the calling function will all the info which we've just used.
+		// Bombard the calling function will all the info which we've just used.
 		return $this->result;
 	}
 
@@ -653,16 +662,16 @@
 	 *     @type array  $hook_extra                  Extra arguments to pass to the filter hooks called by
 	 *                                               WP_Upgrader::run().
 	 * }
-	 * @return array|false|WP_error The result from self::install_package() on success, otherwise a WP_Error,
+	 * @return array|false|WP_Error The result from self::install_package() on success, otherwise a WP_Error,
 	 *                              or false if unable to connect to the filesystem.
 	 */
 	public function run( $options ) {
 
 		$defaults = array(
 			'package'                     => '', // Please always pass this.
-			'destination'                 => '', // And this
+			'destination'                 => '', // ...and this.
 			'clear_destination'           => false,
-			'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please
+			'abort_if_destination_exists' => true, // Abort if the destination directory exists. Pass clear_destination as false please.
 			'clear_working'               => true,
 			'is_multi'                    => false,
 			'hook_extra'                  => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
@@ -702,11 +711,11 @@
 		 */
 		$options = apply_filters( 'upgrader_package_options', $options );
 
-		if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
+		if ( ! $options['is_multi'] ) { // Call $this->header separately if running multiple times.
 			$this->skin->header();
 		}
 
-		// Connect to the Filesystem first.
+		// Connect to the filesystem first.
 		$res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
 		// Mainly for non-connected filesystem.
 		if ( ! $res ) {
@@ -731,15 +740,15 @@
 		 * Download the package (Note, This just returns the filename
 		 * of the file if the package is a local file)
 		 */
-		$download = $this->download_package( $options['package'], true );
+		$download = $this->download_package( $options['package'], true, $options['hook_extra'] );
 
 		// Allow for signature soft-fail.
 		// WARNING: This may be removed in the future.
 		if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) {
 
 			// Don't output the 'no signature could be found' failure message for now.
-			if ( 'signature_verification_no_signature' != $download->get_error_code() || WP_DEBUG ) {
-				// Outout the failure error as a normal feedback, and not as an error:
+			if ( 'signature_verification_no_signature' !== $download->get_error_code() || WP_DEBUG ) {
+				// Output the failure error as a normal feedback, and not as an error.
 				$this->skin->feedback( $download->get_error_message() );
 
 				// Report this failure back to WordPress.org for debugging purposes.
@@ -764,7 +773,7 @@
 			return $download;
 		}
 
-		$delete_package = ( $download != $options['package'] ); // Do not delete a "local" file
+		$delete_package = ( $download != $options['package'] ); // Do not delete a "local" file.
 
 		// Unzips the file into a temporary directory.
 		$working_dir = $this->unpack_package( $download, $delete_package );
@@ -792,7 +801,10 @@
 		$this->skin->set_result( $result );
 		if ( is_wp_error( $result ) ) {
 			$this->skin->error( $result );
-			$this->skin->feedback( 'process_failed' );
+
+			if ( ! method_exists( $this->skin, 'hide_process_failed' ) || ! $this->skin->hide_process_failed( $result ) ) {
+				$this->skin->feedback( 'process_failed' );
+			}
 		} else {
 			// Installation succeeded.
 			$this->skin->feedback( 'process_success' );
@@ -856,7 +868,7 @@
 		$file = $wp_filesystem->abspath() . '.maintenance';
 		if ( $enable ) {
 			$this->skin->feedback( 'maintenance_start' );
-			// Create maintenance file to signal that we are upgrading
+			// Create maintenance file to signal that we are upgrading.
 			$maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
 			$wp_filesystem->delete( $file );
 			$wp_filesystem->put_contents( $file, $maintenance_string, FS_CHMOD_FILE );