From 3223d4a4b3cee69e28366a654cc7e5bf89e4c524 Mon Sep 17 00:00:00 2001 From: Jeremy Felt Date: Thu, 20 Nov 2014 06:52:07 +0000 Subject: [PATCH] Prevent wpmu_delete_blog from removing the wrong uploads directory `wp_upload_dir()` includes some logic to fall back to the default site's upload directory if a specific directory for the requested site cannot be found. Because of this, if `wpmu_delete_blog()` is fired twice in a row for the same site, the main site's upload directory could be deleted as well. This adds some checks in `wpmu_delete_blog()` so that we are confident in the site and it's upload directory's existence before dropping the site. Tests are added for when `ms_files_rewriting` is enabled or disabled. Fixes #30121 git-svn-id: https://develop.svn.wordpress.org/trunk@30404 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/ms.php | 20 ++++++++++-- .../tests/multisite/ms-files-rewriting.php | 31 +++++++++++++++++++ tests/phpunit/tests/multisite/site.php | 31 +++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/includes/ms.php b/src/wp-admin/includes/ms.php index d2201d34ba..4735cf97fc 100644 --- a/src/wp-admin/includes/ms.php +++ b/src/wp-admin/includes/ms.php @@ -85,11 +85,26 @@ function wpmu_delete_blog( $blog_id, $drop = false ) { $current_site = get_current_site(); - // Don't destroy the initial, main, or root blog. - if ( $drop && ( 1 == $blog_id || is_main_site( $blog_id ) || ( $blog->path == $current_site->path && $blog->domain == $current_site->domain ) ) ) + // If a full blog object is not available, do not destroy anything. + if ( $drop && ! $blog ) { $drop = false; + } + + // Don't destroy the initial, main, or root blog. + if ( $drop && ( 1 == $blog_id || is_main_site( $blog_id ) || ( $blog->path == $current_site->path && $blog->domain == $current_site->domain ) ) ) { + $drop = false; + } + + $upload_path = trim( get_option( 'upload_path' ) ); + + // If ms_files_rewriting is enabled and upload_path is empty, wp_upload_dir is not reliable. + if ( $drop && get_site_option( 'ms_files_rewriting' ) && empty( $upload_path ) ) { + $drop = false; + } if ( $drop ) { + $uploads = wp_upload_dir(); + $tables = $wpdb->tables( 'blog' ); /** * Filter the tables to drop when the blog is deleted. @@ -107,7 +122,6 @@ function wpmu_delete_blog( $blog_id, $drop = false ) { $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $blog_id ) ); - $uploads = wp_upload_dir(); /** * Filter the upload base directory to delete when the blog is deleted. * diff --git a/tests/phpunit/tests/multisite/ms-files-rewriting.php b/tests/phpunit/tests/multisite/ms-files-rewriting.php index 3a7950b41c..d36b4d89a7 100644 --- a/tests/phpunit/tests/multisite/ms-files-rewriting.php +++ b/tests/phpunit/tests/multisite/ms-files-rewriting.php @@ -55,6 +55,37 @@ class Tests_Multisite_MS_Files_Rewriting extends WP_UnitTestCase { $this->assertEquals( '', $info2['error'] ); restore_current_blog(); } + + /** + * When a site is deleted with wpmu_delete_blog(), only the files associated with + * that site should be removed. When wpmu_delete_blog() is run a second time, nothing + * should change with upload directories. + */ + function test_upload_directories_after_multiple_wpmu_delete_blog_with_ms_files() { + $filename = rand_str().'.jpg'; + $contents = rand_str(); + + // Upload a file to the main site on the network. + $file1 = wp_upload_bits( $filename, null, $contents ); + + $blog_id = $this->factory->blog->create(); + + switch_to_blog( $blog_id ); + $file2 = wp_upload_bits( $filename, null, $contents ); + restore_current_blog(); + + wpmu_delete_blog( $blog_id, true ); + + // The file on the main site should still exist. The file on the deleted site should not. + $this->assertTrue( file_exists( $file1['file'] ) ); + $this->assertFalse( file_exists( $file2['file'] ) ); + + wpmu_delete_blog( $blog_id, true ); + + // The file on the main site should still exist. The file on the deleted site should not. + $this->assertTrue( file_exists( $file1['file'] ) ); + $this->assertFalse( file_exists( $file2['file'] ) ); + } } endif; \ No newline at end of file diff --git a/tests/phpunit/tests/multisite/site.php b/tests/phpunit/tests/multisite/site.php index 5d23fed5e2..3dafbeea68 100644 --- a/tests/phpunit/tests/multisite/site.php +++ b/tests/phpunit/tests/multisite/site.php @@ -274,6 +274,37 @@ class Tests_Multisite_Site extends WP_UnitTestCase { $this->assertEquals( 1, get_blog_count() ); } + /** + * When a site is deleted with wpmu_delete_blog(), only the files associated with + * that site should be removed. When wpmu_delete_blog() is run a second time, nothing + * should change with upload directories. + */ + function test_upload_directories_after_multiple_wpmu_delete_blog() { + $filename = rand_str().'.jpg'; + $contents = rand_str(); + + // Upload a file to the main site on the network. + $file1 = wp_upload_bits( $filename, null, $contents ); + + $blog_id = $this->factory->blog->create(); + + switch_to_blog( $blog_id ); + $file2 = wp_upload_bits( $filename, null, $contents ); + restore_current_blog(); + + wpmu_delete_blog( $blog_id, true ); + + // The file on the main site should still exist. The file on the deleted site should not. + $this->assertTrue( file_exists( $file1['file'] ) ); + $this->assertFalse( file_exists( $file2['file'] ) ); + + wpmu_delete_blog( $blog_id, true ); + + // The file on the main site should still exist. The file on the deleted site should not. + $this->assertTrue( file_exists( $file1['file'] ) ); + $this->assertFalse( file_exists( $file2['file'] ) ); + } + function test_wpmu_update_blogs_date() { global $wpdb;