diff --git a/wp-admin/includes/file.php b/wp-admin/includes/file.php index f9ac5fb434..5599a729e2 100644 --- a/wp-admin/includes/file.php +++ b/wp-admin/includes/file.php @@ -482,6 +482,14 @@ function unzip_file($file, $to) { if ( 0 == count($archive_files) ) return new WP_Error('empty_archive', __('Empty archive')); + //Prepend another directory level if there are files in the root directory of the zip + foreach ( $archive_files as $archive_file ) { + if ( false === strpos($archive_file['filename'], '/') ) { + $to = trailingslashit($to) . basename($file, '.zip'); + break; + } + } + $path = explode('/', untrailingslashit($to)); for ( $i = count($path); $i > 0; $i-- ) { //>0 = first element is empty allways for paths starting with '/' $tmppath = implode('/', array_slice($path, 0, $i) ); @@ -561,6 +569,54 @@ function copy_dir($from, $to) { } } +/** + * Locates the lowest safe directory in a Plugin folder to copy to the plugins directory. + * + * Note: Desination directory will allways be unique. + * + * @since 2.7.0 + * + * @param string $from the Working directory of the plugin files + * @param string $to the proposed destination for the for the plugin files + * @return array an array of the keys 'from' and 'to' for the actual copy. + */ +function update_pluginfiles_base_dir($from, $to) { + $files = list_files($from); + + //Remove non-php files + foreach ( (array)$files as $key => $file ) + if ( ! preg_match('!.php$!i', $file) ) + unset($files[$key]); + + //remove non-plugin files + foreach ( (array)$files as $key => $file ) { + $details = get_plugin_data($file, false, false); + if ( empty($details['Name']) ) + unset($files[$key]); + } + + if ( empty($files) ) + return false; + + //Left with paths to files which ARE plugins. + $min_num = 100; //assume no zips with deeper paths will come along + $min_file = ''; + foreach ( (array)$files as $key => $file ) { + $this_num = substr_count($file, '/'); + if ( $this_num < $min_num ) { + $min_file = $file; + $min_num = $this_num; + } + } + unset($min_num); + + $from = dirname($min_file); + //Ensure its a unique install folder, Upgrades delete the folder prior to this. + $to = dirname($to) . '/' . wp_unique_filename(dirname($to), basename($to)); + + return compact('from', 'to'); +} + /** * {@internal Missing Short Description}} * diff --git a/wp-admin/includes/plugin-install.php b/wp-admin/includes/plugin-install.php index e2f4e7e932..1402ab2b71 100644 --- a/wp-admin/includes/plugin-install.php +++ b/wp-admin/includes/plugin-install.php @@ -744,37 +744,34 @@ function wp_install_plugin($package, $feedback = '') { return $result; } - //Get a list of the directories in the working directory before we delete it, We need to know the new folder for the plugin + apply_filters('install_feedback', __('Installing the plugin')); + $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); - if( $wp_filesystem->exists( $plugins_dir . $filelist[0] ) ) { - $wp_filesystem->delete($working_dir, true); - return new WP_Error('install_folder_exists', __('Folder allready exists.'), $filelist[0] ); - } + //find base plugin directory + $res = update_pluginfiles_base_dir($working_dir . '/' . $filelist[0], $plugins_dir . $filelist[0]); + + //Create folder if not exists. + if( ! $wp_filesystem->exists( $res['to'] ) ) + if ( ! $wp_filesystem->mkdir( $res['to'] ) ) + return new WP_Error('mkdir_failed', __('Could not create directory'), $res['to']); - apply_filters('install_feedback', __('Installing the plugin')); // Copy new version of plugin into place. - $result = copy_dir($working_dir, $plugins_dir); + $result = copy_dir($res['from'], $res['to']); if ( is_wp_error($result) ) { $wp_filesystem->delete($working_dir, true); return $result; } - //Get a list of the directories in the working directory before we delete it, We need to know the new folder for the plugin - $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); - // Remove working directory $wp_filesystem->delete($working_dir, true); - if( empty($filelist) ) - return false; //We couldnt find any files in the working dir, therefor no plugin installed? Failsafe backup. - - $folder = $filelist[0]; + $folder = trailingslashit(str_replace($plugins_dir, '', $res['to'])); $plugin = get_plugins('/' . $folder); //Ensure to pass with leading slash $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list //Return the plugin files name. - return $folder . '/' . $pluginfiles[0]; + return $folder . $pluginfiles[0]; } /** @@ -839,37 +836,34 @@ function wp_install_plugin_local_package($package, $feedback = '') { return $result; } - //Get a list of the directories in the working directory before we delete it, We need to know the new folder for the plugin + apply_filters('install_feedback', __('Installing the plugin')); + $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); - if( $wp_filesystem->exists( $plugins_dir . $filelist[0] ) ) { - $wp_filesystem->delete($working_dir, true); - return new WP_Error('install_folder_exists', __('Folder allready exists.'), $filelist[0] ); - } + //find base plugin directory + $res = update_pluginfiles_base_dir($working_dir . '/' . $filelist[0], $plugins_dir . $filelist[0]); + + //Create folder if not exists. + if( ! $wp_filesystem->exists( $res['to'] ) ) + if ( ! $wp_filesystem->mkdir( $res['to'] ) ) + return new WP_Error('mkdir_failed', __('Could not create directory'), $res['to']); - apply_filters('install_feedback', __('Installing the plugin')); // Copy new version of plugin into place. - $result = copy_dir($working_dir, $plugins_dir); + $result = copy_dir($res['from'], $res['to']); if ( is_wp_error($result) ) { $wp_filesystem->delete($working_dir, true); return $result; } - //Get a list of the directories in the working directory before we delete it, We need to know the new folder for the plugin - $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); - // Remove working directory $wp_filesystem->delete($working_dir, true); - if( empty($filelist) ) - return false; //We couldnt find any files in the working dir, therefor no plugin installed? Failsafe backup. - - $folder = $filelist[0]; + $folder = trailingslashit(str_replace($plugins_dir, '', $res['to'])); $plugin = get_plugins('/' . $folder); //Ensure to pass with leading slash $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list //Return the plugin files name. - return $folder . '/' . $pluginfiles[0]; + return $folder . $pluginfiles[0]; } -?> +?> \ No newline at end of file diff --git a/wp-admin/includes/update.php b/wp-admin/includes/update.php index 83af44729a..8392e006f3 100644 --- a/wp-admin/includes/update.php +++ b/wp-admin/includes/update.php @@ -246,30 +246,36 @@ function wp_update_plugin($plugin, $feedback = '') { } apply_filters('update_feedback', __('Installing the latest version')); + + $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); + + //find base plugin directory + $res = update_pluginfiles_base_dir($working_dir . '/' . $filelist[0], $plugins_dir . $filelist[0]); + + //Create folder if not exists. + if( ! $wp_filesystem->exists( $res['to'] ) ) + if ( ! $wp_filesystem->mkdir( $res['to'] ) ) + return new WP_Error('mkdir_failed', __('Could not create directory'), $res['to']); + // Copy new version of plugin into place. - $result = copy_dir($working_dir, $plugins_dir); + $result = copy_dir($res['from'], $res['to']); if ( is_wp_error($result) ) { $wp_filesystem->delete($working_dir, true); return $result; } - //Get a list of the directories in the working directory before we delete it, We need to know the new folder for the plugin - $filelist = array_keys( $wp_filesystem->dirlist($working_dir) ); - // Remove working directory $wp_filesystem->delete($working_dir, true); // Force refresh of plugin update information delete_option('update_plugins'); - if( empty($filelist) ) - return false; //We couldnt find any files in the working dir, therefor no plugin installed? Failsafe backup. - - $folder = $filelist[0]; + $folder = trailingslashit(str_replace($plugins_dir, '', $res['to'])); $plugin = get_plugins('/' . $folder); //Ensure to pass with leading slash $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list - return $folder . '/' . $pluginfiles[0]; + //Return the plugin files name. + return $folder . $pluginfiles[0]; } function wp_update_theme($theme, $feedback = '') {