WordPress 4.3
[autoinstalls/wordpress.git] / wp-admin / includes / class-wp-upgrader.php
index acab417d3b55dc4ff604a9aa64c9dde4b86dba39..235df514c1716888f480c0c59f8f5702ab33c007 100644 (file)
@@ -132,6 +132,7 @@ class WP_Upgrader {
                $this->strings['folder_exists'] = __('Destination folder already exists.');
                $this->strings['mkdir_failed'] = __('Could not create directory.');
                $this->strings['incompatible_archive'] = __('The package could not be installed.');
+               $this->strings['files_not_writable'] = __( 'The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.' );
 
                $this->strings['maintenance_start'] = __('Enabling Maintenance mode…');
                $this->strings['maintenance_end'] = __('Disabling Maintenance mode…');
@@ -142,6 +143,8 @@ class WP_Upgrader {
         *
         * @since 2.8.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param array $directories                  Optional. A list of directories. If any of these do
         *                                            not exist, a {@see WP_Error} object will be returned.
         *                                            Default empty array.
@@ -244,6 +247,8 @@ class WP_Upgrader {
         *
         * @since 2.8.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param string $package        Full path to the package file.
         * @param bool   $delete_package Optional. Whether to delete the package file after attempting
         *                               to unpack it. Default true.
@@ -288,6 +293,65 @@ class WP_Upgrader {
                return $working_dir;
        }
 
+       /**
+        * Clears the directory where this item is going to be installed into.
+        *
+        * @since 4.3.0
+        *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
+        * @param string $remote_destination The location on the remote filesystem to be cleared
+        * @return bool|WP_Error True upon success, WP_Error on failure.
+        */
+       public function clear_destination( $remote_destination ) {
+               global $wp_filesystem;
+
+               if ( ! $wp_filesystem->exists( $remote_destination ) ) {
+                       return true;
+               }
+
+               // Check all files are writable before attempting to clear the destination.
+               $unwritable_files = array();
+
+               $_files = $wp_filesystem->dirlist( $remote_destination, true, true );
+
+               // Flatten the resulting array, iterate using each as we append to the array during iteration.
+               while ( $f = each( $_files ) ) {
+                       $file = $f['value'];
+                       $name = $f['key'];
+
+                       if ( ! isset( $file['files'] ) ) {
+                               continue;
+                       }
+
+                       foreach ( $file['files'] as $filename => $details ) {
+                               $_files[ $name . '/' . $filename ] = $details;
+                       }
+               }
+
+               // Check writability.
+               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 ) );
+                               if ( ! $wp_filesystem->is_writable( $remote_destination . $filename ) ) {
+                                       $unwritable_files[] = $filename;
+                               }
+                       }
+               }
+
+               if ( ! empty( $unwritable_files ) ) {
+                       return new WP_Error( 'files_not_writable', $this->strings['files_not_writable'], implode( ', ', $unwritable_files ) );
+               }
+
+               if ( ! $wp_filesystem->delete( $remote_destination, true ) ) {
+                       return new WP_Error( 'remove_old_failed', $this->strings['remove_old_failed'] );
+               }
+
+               return true;
+       }
+
        /**
         * Install a package.
         *
@@ -297,6 +361,9 @@ class WP_Upgrader {
         *
         * @since 2.8.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        * @global array              $wp_theme_directories
+        *
         * @param array|string $args {
         *     Optional. Array or string of arguments for installing a package. Default empty array.
         *
@@ -410,29 +477,25 @@ class WP_Upgrader {
                }
 
                if ( $clear_destination ) {
-                       //We're going to clear the destination if there's something there
+                       // We're going to clear the destination if there's something there
                        $this->skin->feedback('remove_old');
-                       $removed = true;
-                       if ( $wp_filesystem->exists( $remote_destination ) ) {
-                               $removed = $wp_filesystem->delete( $remote_destination, true );
-                       }
+
+                       $removed = $this->clear_destination( $remote_destination );
 
                        /**
                         * Filter whether the upgrader cleared the destination.
                         *
                         * @since 2.8.0
                         *
-                        * @param bool   $removed            Whether the destination was cleared.
+                        * @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.
                         */
                        $removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
 
-                       if ( is_wp_error($removed) ) {
+                       if ( is_wp_error( $removed ) ) {
                                return $removed;
-                       } elseif ( ! $removed ) {
-                               return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
                        }
                } 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.
@@ -539,6 +602,25 @@ class WP_Upgrader {
 
                $options = wp_parse_args( $options, $defaults );
 
+               /**
+                * Filter the package options before running an update.
+                *
+                * @since 4.3.0
+                *
+                * @param array $options {
+                *     Options used by the upgrader.
+                *
+                *     @type string $package                     Package for update.
+                *     @type string $destination                 Update location.
+                *     @type bool   $clear_destination           Clear the destination resource.
+                *     @type bool   $clear_working               Clear the working resource.
+                *     @type bool   $abort_if_destination_exists Abort if the Destination directory exists.
+                *     @type bool   $is_multi                    Whether the upgrader is running multiple times.
+                *     @type array  $hook_extra                  Extra hook arguments.
+                * }
+                */
+               $options = apply_filters( 'upgrader_package_options', $options );
+
                if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
                        $this->skin->header();
                }
@@ -626,6 +708,8 @@ class WP_Upgrader {
         *
         * @since 2.8.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param bool $enable True to enable maintenance mode, false to disable.
         */
        public function maintenance_mode( $enable = false ) {
@@ -957,6 +1041,8 @@ class Plugin_Upgrader extends WP_Upgrader {
         *
         * @since 3.3.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param string $source The path to the downloaded package source.
         * @return string|WP_Error The source as passed, or a {@see WP_Error} object if no plugins were found.
         */
@@ -972,11 +1058,14 @@ class Plugin_Upgrader extends WP_Upgrader {
 
                // Check the folder contains at least 1 valid plugin.
                $plugins_found = false;
-               foreach ( glob( $working_directory . '*.php' ) as $file ) {
-                       $info = get_plugin_data($file, false, false);
-                       if ( !empty( $info['Name'] ) ) {
-                               $plugins_found = true;
-                               break;
+               $files = glob( $working_directory . '*.php' );
+               if ( $files ) {
+                       foreach ( $files as $file ) {
+                               $info = get_plugin_data( $file, false, false );
+                               if ( ! empty( $info['Name'] ) ) {
+                                       $plugins_found = true;
+                                       break;
+                               }
                        }
                }
 
@@ -1050,6 +1139,14 @@ class Plugin_Upgrader extends WP_Upgrader {
         * {@see Plugin_Upgrader::upgrade()} and {@see Plugin_Upgrader::bulk_upgrade()}.
         *
         * @since 2.8.0
+        *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+     *
+        * @param bool|WP_Error $removed
+        * @param string        $local_destination
+        * @param string        $remote_destination
+        * @param array         $plugin
+        * @return WP_Error|bool
         */
        public function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) {
                global $wp_filesystem;
@@ -1153,6 +1250,11 @@ class Theme_Upgrader extends WP_Upgrader {
         * Hooked to the {@see 'upgrader_post_install'} filter by {@see Theme_Upgrader::install()}.
         *
         * @since 3.4.0
+        *
+        * @param bool  $install_result
+        * @param array $hook_extra
+        * @param array $child_result
+        * @return type
         */
        public function check_parent_theme_filter( $install_result, $hook_extra, $child_result ) {
                // Check to see if we need to install a parent theme
@@ -1223,6 +1325,7 @@ class Theme_Upgrader extends WP_Upgrader {
         * @since 3.4.0
         *
         * @param array $actions Preview actions.
+        * @return array
         */
        public function hide_activate_preview_actions( $actions ) {
                unset($actions['activate'], $actions['preview']);
@@ -1472,6 +1575,8 @@ class Theme_Upgrader extends WP_Upgrader {
         *
         * @since 3.3.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param string $source The full path to the package source.
         * @return string|WP_Error The source or a WP_Error.
         */
@@ -1509,9 +1614,12 @@ class Theme_Upgrader extends WP_Upgrader {
         * {@see Theme_Upgrader::bulk_upgrade()}.
         *
         * @since 2.8.0
+        *
+        * @param bool|WP_Error  $return
+        * @param array          $theme
+        * @return bool|WP_Error
         */
        public function current_before($return, $theme) {
-
                if ( is_wp_error($return) )
                        return $return;
 
@@ -1533,6 +1641,10 @@ class Theme_Upgrader extends WP_Upgrader {
         * and {@see Theme_Upgrader::bulk_upgrade()}.
         *
         * @since 2.8.0
+        *
+        * @param bool|WP_Error  $return
+        * @param array          $theme
+        * @return bool|WP_Error
         */
        public function current_after($return, $theme) {
                if ( is_wp_error($return) )
@@ -1563,6 +1675,14 @@ class Theme_Upgrader extends WP_Upgrader {
         * and {@see Theme_Upgrader::bulk_upgrade()}.
         *
         * @since 2.8.0
+        *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
+        * @param bool   $removed
+        * @param string $local_destination
+        * @param string $remote_destination
+        * @param array  $theme
+        * @return bool
         */
        public function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) {
                global $wp_filesystem;
@@ -1607,8 +1727,6 @@ class Theme_Upgrader extends WP_Upgrader {
 
 }
 
-add_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
-
 /**
  * Language pack upgrader, for updating translations of plugins, themes, and core.
  *
@@ -1641,6 +1759,10 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         * Hooked to the {@see 'upgrader_process_complete'} action by default.
         *
         * @since 3.7.0
+        *
+        * @static
+        *
+        * @param false|WP_Upgrader $upgrader
         */
        public static function async_upgrade( $upgrader = false ) {
                // Avoid recursion.
@@ -1714,7 +1836,7 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         * @param string|false $update Optional. Whether an update offer is available. Default false.
         * @param array        $args   Optional. Other optional arguments, see
         *                             {@see Language_Pack_Upgrader::bulk_upgrade()}. Default empty array.
-        * @return array|WP_Error The result of the upgrade, or a {@see wP_Error} object instead.
+        * @return array|bool|WP_Error The result of the upgrade, or a {@see wP_Error} object instead.
         */
        public function upgrade( $update = false, $args = array() ) {
                if ( $update ) {
@@ -1735,6 +1857,8 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         *
         * @since 3.7.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
         * @param array $language_updates Optional. Language pack updates. Default empty array.
         * @param array $args {
         *     Optional. Other arguments for upgrading multiple language packs. Default empty array
@@ -1742,7 +1866,7 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         *     @type bool $clear_update_cache Whether to clear the update cache when done.
         *                                    Default true.
         * }
-        * @return array|true|false|WP_Error Will return an array of results, or true if there are no updates,
+        * @return array|bool|WP_Error Will return an array of results, or true if there are no updates,
         *                                   false or WP_Error for initial errors.
         */
        public function bulk_upgrade( $language_updates = array(), $args = array() ) {
@@ -1776,7 +1900,7 @@ class Language_Pack_Upgrader extends WP_Upgrader {
                // Remove any existing upgrade filters from the plugin/theme upgraders #WP29425 & #WP29230
                remove_all_filters( 'upgrader_pre_install' );
                remove_all_filters( 'upgrader_clear_destination' );
-               remove_all_filterS( 'upgrader_post_install' );
+               remove_all_filters( 'upgrader_post_install' );
                remove_all_filters( 'upgrader_source_selection' );
 
                add_filter( 'upgrader_source_selection', array( $this, 'check_package' ), 10, 2 );
@@ -1859,6 +1983,11 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         * {@see Language_Pack_Upgrader::bulk_upgrade()}.
         *
         * @since 3.7.0
+        *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        *
+        * @param string|WP_Error $source
+        * @param string          $remote_source
         */
        public function check_package( $source, $remote_source ) {
                global $wp_filesystem;
@@ -1890,7 +2019,7 @@ class Language_Pack_Upgrader extends WP_Upgrader {
         *
         * @since 3.7.0
         *
-        * @param object The data for an update.
+        * @param object $update The data for an update.
         * @return string The name of the item being updated.
         */
        public function get_name_for_update( $update ) {
@@ -1945,6 +2074,9 @@ class Core_Upgrader extends WP_Upgrader {
         *
         * @since 2.8.0
         *
+        * @global WP_Filesystem_Base $wp_filesystem Subclass
+        * @global callback           $_wp_filesystem_direct_method
+        *
         * @param object $current Response object for whether WordPress is current.
         * @param array  $args {
         *        Optional. Arguments for upgrading WordPress core. Default empty array.
@@ -2112,6 +2244,8 @@ class Core_Upgrader extends WP_Upgrader {
         *
         * @since 3.7.0
         *
+        * @static
+        *
         * @param string $offered_ver The offered version, of the format x.y.z.
         * @return bool True if we should update to the offered version, otherwise false.
         */
@@ -2218,6 +2352,9 @@ class Core_Upgrader extends WP_Upgrader {
         *
         * @since 3.7.0
         *
+        * @global string $wp_version
+        * @global string $wp_local_package
+        *
         * @return bool True if the checksums match, otherwise false.
         */
        public function check_files() {
@@ -2463,6 +2600,8 @@ class WP_Automatic_Updater {
         *
         * @since 3.7.0
         *
+        * @global wpdb $wpdb
+        *
         * @param string $type    The type of update being checked: 'core', 'theme',
         *                        'plugin', 'translation'.
         * @param object $item    The update offer.
@@ -2589,6 +2728,8 @@ class WP_Automatic_Updater {
         *
         * @param string $type The type of update being checked: 'core', 'theme', 'plugin', 'translation'.
         * @param object $item The update offer.
+        *
+        * @return null|WP_Error
         */
        public function update( $type, $item ) {
                $skin = new Automatic_Upgrader_Skin;
@@ -2687,6 +2828,9 @@ class WP_Automatic_Updater {
         * Kicks off the background update process, looping through all pending updates.
         *
         * @since 3.7.0
+        *
+        * @global wpdb   $wpdb
+        * @global string $wp_version
         */
        public function run() {
                global $wpdb, $wp_version;
@@ -2822,7 +2966,9 @@ class WP_Automatic_Updater {
         * If we tried to perform a core update, check if we should send an email,
         * and if we need to avoid processing future updates.
         *
-        * @param object $update_result The result of the core update. Includes the update offer and result.
+        * @global string $wp_version
+        *
+        * @param object|WP_Error $update_result The result of the core update. Includes the update offer and result.
         */
        protected function after_core_update( $update_result ) {
                global $wp_version;
@@ -2909,6 +3055,8 @@ class WP_Automatic_Updater {
         *
         * @since 3.7.0
         *
+        * @global string $wp_version
+        *
         * @param string $type        The type of email to send. Can be one of 'success', 'fail', 'manual', 'critical'.
         * @param object $core_update The update offer that was attempted.
         * @param mixed  $result      Optional. The result for the core update. Can be WP_Error.