• File: plugin-upgrader.php
  • Full Path: /home/matthif/www/wp-content/plugins/google-analytics-for-wordpress/includes/admin/licensing/plugin-upgrader.php
  • Date Modified: 01/24/2025 1:57 PM
  • File size: 21.59 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php

/** WP_Upgrader class */
require_once ABSPATH 'wp-admin/includes/class-wp-upgrader.php';

/** Plugin_Upgrader class */
require_once ABSPATH 'wp-admin/includes/class-plugin-upgrader.php';


/**
 * In WP 5.3 a PHP 5.6 splat operator (...$args) was added to WP_Upgrader_Skin::feedback().
 * We need to remove all calls to *Skin::feedback() method, as we can't override it in own Skins
 * without breaking support for PHP 5.3-5.5.
 *
 * @internal Please do not use this class outside of core MonsterInsights development. May be removed at any time.
 *
 * @since 7.10.6
 */
class MonsterInsights_Plugin_Upgrader extends Plugin_Upgrader {

    
/**
     * Run an upgrade/installation.
     *
     * Attempt to download the package (if it is not a local file), unpack it, and
     * install it in the destination folder.
     *
     * @param array $options {
     *     Array or string of arguments for upgrading/installing a package.
     *
     * @type string $package The full path or URI of the package to install.
     *                                               Default empty.
     * @type string $destination The full path to the destination folder.
     *                                               Default empty.
     * @type bool $clear_destination Whether to delete any files already in the
     *                                               destination folder. Default false.
     * @type bool $clear_working Whether to delete the files form the working
     *                                               directory after copying to the destination.
     *                                               Default false.
     * @type bool $abort_if_destination_exists Whether to abort the installation if the destination
     *                                               folder already exists. When true, `$clear_destination`
     *                                               should be false. Default true.
     * @type bool $is_multi Whether this run is one of multiple upgrade/installation
     *                                               actions being performed in bulk. When true, the skin
     *                                               WP_Upgrader::header() and WP_Upgrader::footer()
     *                                               aren't called. Default false.
     * @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,
     *                              or false if unable to connect to the filesystem.
     * @since 1.5.6.1
     *
     */
    
public function run$options ) {

        
$defaults = array(
            
'package'                     => '',
            
// Please always pass this.
            
'destination'                 => '',
            
// And this
            
'clear_destination'           => false,
            
'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.
        
);

        
$options wp_parse_args$options$defaults );

        
/**
         * Filter the package options before running an update.
         *
         * See also {@see 'upgrader_process_complete'}.
         *
         * @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.
         *
         * @type string $action Type of action. Default 'update'.
         * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'.
         * @type bool $bulk Whether the update process is a bulk update. Default true.
         * @type string $plugin Path to the plugin file relative to the plugins directory.
         * @type string $theme The stylesheet or template name of the theme.
         * @type string $language_update_type The language pack update type. Accepts 'plugin', 'theme',
         *                                            or 'core'.
         * @type object $language_update The language pack update offer.
         *     }
         * }
         * @since 4.3.0
         *
         */
        
$options apply_filters'upgrader_package_options'$options );

        if ( ! 
$options['is_multi'] ) { // call $this->header separately if running multiple times
            
$this->skin->header();
        }

        
// Connect to the Filesystem first.
        
$res $this->fs_connect( array( WP_CONTENT_DIR$options['destination'] ) );
        
// Mainly for non-connected filesystem.
        
if ( ! $res ) {
            if ( ! 
$options['is_multi'] ) {
                
$this->skin->footer();
            }

            return 
false;
        }

        
$this->skin->before();

        if ( 
is_wp_error$res ) ) {
            
$this->skin->error$res );
            
$this->skin->after();
            if ( ! 
$options['is_multi'] ) {
                
$this->skin->footer();
            }

            return 
$res;
        }

        
/*
         * 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 );

        
// 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:
                //$this->skin->feedback( $download->get_error_message() );

                // Report this failure back to WordPress.org for debugging purposes.
                
wp_version_check(
                    array(
                        
'signature_failure_code' => $download->get_error_code(),
                        
'signature_failure_data' => $download->get_error_data(),
                    )
                );
            }

            
// Pretend this error didn't happen.
            
$download $download->get_error_data'softfail-filename' );
        }

        if ( 
is_wp_error$download ) ) {
            
$this->skin->error$download );
            
$this->skin->after();
            if ( ! 
$options['is_multi'] ) {
                
$this->skin->footer();
            }

            return 
$download;
        }

        
$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 );
        if ( 
is_wp_error$working_dir ) ) {
            
$this->skin->error$working_dir );
            
$this->skin->after();
            if ( ! 
$options['is_multi'] ) {
                
$this->skin->footer();
            }

            return 
$working_dir;
        }

        
// With the given options, this installs it to the destination directory.
        
$result $this->install_package(
            array(
                
'source'                      => $working_dir,
                
'destination'                 => $options['destination'],
                
'clear_destination'           => $options['clear_destination'],
                
'abort_if_destination_exists' => $options['abort_if_destination_exists'],
                
'clear_working'               => $options['clear_working'],
                
'hook_extra'                  => $options['hook_extra'],
            )
        );

        
$this->skin->set_result$result );
        if ( 
is_wp_error$result ) ) {
            
$this->skin->error$result );
            
//$this->skin->feedback( 'process_failed' );
        
} else {
            
// Installation succeeded.
            //$this->skin->feedback( 'process_success' );
        
}

        
$this->skin->after();

        if ( ! 
$options['is_multi'] ) {

            
/**
             * Fire when the upgrader process is complete.
             *
             * See also {@see 'upgrader_package_options'}.
             *
             * @param WP_Upgrader $this WP_Upgrader instance. In other contexts, $this, might be a
             *                          Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
             * @param array $hook_extra {
             *     Array of bulk item update data.
             *
             * @type string $action Type of action. Default 'update'.
             * @type string $type Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
             * @type bool $bulk Whether the update process is a bulk update. Default true.
             * @type array $plugins Array of the basename paths of the plugins' main files.
             * @type array $themes The theme slugs.
             * @type array $translations {
             *         Array of translations update data.
             *
             * @type string $language The locale the translation is for.
             * @type string $type Type of translation. Accepts 'plugin', 'theme', or 'core'.
             * @type string $slug Text domain the translation is for. The slug of a theme/plugin or
             *                                'default' for core translations.
             * @type string $version The version of a theme, plugin, or core.
             *     }
             * }
             * @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`.
             *
             * @since 3.6.0
             * @since 3.7.0 Added to WP_Upgrader::run().
             */
            
do_action'upgrader_process_complete'$this$options['hook_extra'] );

            
$this->skin->footer();
        }

        return 
$result;
    }

    
/**
     * Toggle maintenance mode for the site.
     *
     * Create/delete the maintenance file to enable/disable maintenance mode.
     *
     * @param bool $enable True to enable maintenance mode, false to disable.
     *
     * @global WP_Filesystem_Base $wp_filesystem Subclass
     *
     * @since 2.8.0
     *
     */
    
public function maintenance_mode$enable false ) {
        global 
$wp_filesystem;
        
$file $wp_filesystem->abspath() . '.maintenance';
        if ( 
$enable ) {
            
//$this->skin->feedback( 'maintenance_start' );
            // Create maintenance file to signal that we are upgrading
            
$maintenance_string '<?php $upgrading = ' time() . '; ?>';
            
$wp_filesystem->delete$file );
            
$wp_filesystem->put_contents$file$maintenance_stringFS_CHMOD_FILE );
        } elseif ( ! 
$enable && $wp_filesystem->exists$file ) ) {
            
//$this->skin->feedback( 'maintenance_end' );
            
$wp_filesystem->delete$file );
        }
    }

    
/**
     * Download a package.
     *
     * @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 Added in WP 5.5.
     *
     * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object.
     * @since 2.8.0
     *
     */
    
public function download_package$package$check_signatures false$hook_extra = array() ) {

        
/**
         * Filter whether to return the package.
         *
         * @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.
         *
         * @since 3.7.0
         *
         */
        
$reply apply_filters'upgrader_pre_download'false$package$this );
        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 ( empty( 
$package ) ) {
            return new 
WP_Error'no_package'$this->strings['no_package'] );
        }

        
//$this->skin->feedback( 'downloading_package', $package );

        
$download_file download_url$package300$check_signatures );

        if ( 
is_wp_error$download_file ) && ! $download_file->get_error_data'softfail-filename' ) ) {
            return new 
WP_Error'download_failed'$this->strings['download_failed'], $download_file->get_error_message() );
        }

        return 
$download_file;
    }

    
/**
     * Unpack a compressed package file.
     *
     * @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.
     *
     * @return string|WP_Error The path to the unpacked contents, or a WP_Error on failure.
     * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
     *
     * @since 2.8.0
     *
     */
    
public function unpack_package$package$delete_package true ) {
        global 
$wp_filesystem;

        
//$this->skin->feedback( 'unpack_package' );

        
$upgrade_folder $wp_filesystem->wp_content_dir() . 'upgrade/';

        
//Clean up contents of upgrade directory beforehand.
        
$upgrade_files $wp_filesystem->dirlist$upgrade_folder );
        if ( ! empty( 
$upgrade_files ) ) {
            foreach ( 
$upgrade_files as $file ) {
                
$wp_filesystem->delete$upgrade_folder $file['name'], true );
            }
        }

        
// We need a working directory - Strip off any .tmp or .zip suffixes
        
$working_dir $upgrade_folder basenamebasename$package'.tmp' ), '.zip' );

        
// Clean up working directory
        
if ( $wp_filesystem->is_dir$working_dir ) ) {
            
$wp_filesystem->delete$working_dirtrue );
        }

        
// Unzip package to working directory
        
$result unzip_file$package$working_dir );

        
// Once extracted, delete the package if required.
        
if ( $delete_package ) {
            
unlink$package );
        }

        if ( 
is_wp_error$result ) ) {
            
$wp_filesystem->delete$working_dirtrue );
            if ( 
'incompatible_archive' == $result->get_error_code() ) {
                return new 
WP_Error'incompatible_archive'$this->strings['incompatible_archive'], $result->get_error_data() );
            }

            return 
$result;
        }

        return 
$working_dir;
    }

    
/**
     * Install a package.
     *
     * Copies the contents of a package form a source directory, and installs them in
     * a destination directory. Optionally removes the source. It can also optionally
     * clear out the destination folder if it already exists.
     *
     * @param array|string $args {
     *     Optional. Array or string of arguments for installing a package. Default empty array.
     *
     * @type string $source Required path to the package source. Default empty.
     * @type string $destination Required path to a folder to install the package in.
     *                                               Default empty.
     * @type bool $clear_destination Whether to delete any files already in the destination
     *                                               folder. Default false.
     * @type bool $clear_working Whether to delete the files form the working directory
     *                                               after copying to the destination. Default false.
     * @type bool $abort_if_destination_exists Whether to abort the installation if
     *                                               the destination folder already exists. Default true.
     * @type array $hook_extra Extra arguments to pass to the filter hooks called by
     *                                               WP_Upgrader::install_package(). Default empty array.
     * }
     *
     * @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure.
     * @global array $wp_theme_directories
     *
     * @since 2.8.0
     *
     * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
     */
    
public function install_package$args = array() ) {
        global 
$wp_filesystem$wp_theme_directories;

        
$defaults = array(
            
'source'                      => ''// Please always pass this
            
'destination'                 => ''// and this
            
'clear_destination'           => false,
            
'clear_working'               => false,
            
'abort_if_destination_exists' => true,
            
'hook_extra'                  => array(),
        );

        
$args wp_parse_args$args$defaults );

        
// These were previously extract()'d.
        
$source            $args['source'];
        
$destination       $args['destination'];
        
$clear_destination $args['clear_destination'];

        
set_time_limit300 );

        if ( empty( 
$source ) || empty( $destination ) ) {
            return new 
WP_Error'bad_request'$this->strings['bad_request'] );
        }
        
//$this->skin->feedback( 'installing_package' );

        /**
         * Filter the install response before the installation has started.
         *
         * Returning a truthy value, or one that could be evaluated as a WP_Error
         * will effectively short-circuit the installation, returning that value
         * instead.
         *
         * @param bool|WP_Error $response Response.
         * @param array $hook_extra Extra arguments passed to hooked filters.
         *
         * @since 2.8.0
         *
         */
        
$res apply_filters'upgrader_pre_install'true$args['hook_extra'] );

        if ( 
is_wp_error$res ) ) {
            return 
$res;
        }

        
//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 ( == count$source_files ) && $wp_filesystem->is_dirtrailingslashit$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 ) == ) {
            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.
            
$source trailingslashit$args['source'] );
        }

        
/**
         * Filter the source file location for the upgrade package.
         *
         * @param string $source File source location.
         * @param string $remote_source Remote file source location.
         * @param WP_Upgrader $this WP_Upgrader instance.
         * @param array $hook_extra Extra arguments passed to hooked filters.
         *
         * @since 2.8.0
         * @since 4.4.0 The $hook_extra parameter became available.
         *
         */
        
$source apply_filters'upgrader_source_selection'$source$remote_source$this$args['hook_extra'] );

        if ( 
is_wp_error$source ) ) {
            return 
$source;
        }

        
// Has the source location changed? If so, we need a new source_files list.
        
if ( $source !== $remote_source ) {
            
$source_files array_keys$wp_filesystem->dirlist$source ) );
        }

        
/*
         * Protection against deleting files in any important base directories.
         * Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the
         * destination directory (WP_PLUGIN_DIR / wp-content/themes) intending
         * to copy the directory into the directory, whilst they pass the source
         * as the actual files to copy.
         */
        
$protected_directories = array( ABSPATHWP_CONTENT_DIRWP_PLUGIN_DIRWP_CONTENT_DIR '/themes' );

        if ( 
is_array$wp_theme_directories ) ) {
            
$protected_directories array_merge$protected_directories$wp_theme_directories );
        }

        if ( 
in_array$destination$protected_directories ) ) {
            
$remote_destination trailingslashit$remote_destination ) . trailingslashitbasename$source ) );
            
$destination        trailingslashit$destination ) . trailingslashitbasename$source ) );
        }

        if ( 
$clear_destination ) {
            
// We're going to clear the destination if there's something there.
            //$this->skin->feedback( 'remove_old' );

            
$removed $this->clear_destination$remote_destination );

            
/**
             * Filter whether the upgrader cleared the destination.
             *
             * @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.
             *
             * @since 2.8.0
             *
             */
            
$removed apply_filters'upgrader_clear_destination'$removed$local_destination$remote_destination$args['hook_extra'] );

            if ( 
is_wp_error$removed ) ) {
                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.
            
$_files $wp_filesystem->dirlist$remote_destination );
            if ( ! empty( 
$_files ) ) {
                
$wp_filesystem->delete$remote_sourcetrue ); //Clear out the source files.

                
return new WP_Error'folder_exists'$this->strings['folder_exists'], $remote_destination );
            }
        }

        
//Create destination if needed
        
if ( ! $wp_filesystem->exists$remote_destination ) ) {
            if ( ! 
$wp_filesystem->mkdir$remote_destinationFS_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 ) ) {
            if ( 
$args['clear_working'] ) {
                
$wp_filesystem->delete$remote_sourcetrue );
            }

            return 
$result;
        }

        
//Clear the Working folder?
        
if ( $args['clear_working'] ) {
            
$wp_filesystem->delete$remote_sourcetrue );
        }

        
$destination_name basenamestr_replace$local_destination''$destination ) );
        if ( 
'.' == $destination_name ) {
            
$destination_name '';
        }

        
$this->result compact'source''source_files''destination''destination_name''local_destination''remote_destination''clear_destination' );

        
/**
         * Filter the installation response after the installation has finished.
         *
         * @param bool $response Installation response.
         * @param array $hook_extra Extra arguments passed to hooked filters.
         * @param array $result Installation result data.
         *
         * @since 2.8.0
         *
         */
        
$res apply_filters'upgrader_post_install'true$args['hook_extra'], $this->result );

        if ( 
is_wp_error$res ) ) {
            
$this->result $res;

            return 
$res;
        }

        
//Bombard the calling function will all the info which we've just used.
        
return $this->result;
    }
}