diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 64dce4a159755..51dc18d52e5e5 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -2093,7 +2093,7 @@ function wp_mkdir_p( $target ) { $dir_perms = 0777; } - if ( @mkdir( $target, $dir_perms, true ) ) { + if ( mkdir( $target, $dir_perms, true ) || is_dir( $target ) ) { /* * If a umask is set that modifies $dir_perms, we'll have to re-set diff --git a/tests/phpunit/tests/functions/wpMkdirP.php b/tests/phpunit/tests/functions/wpMkdirP.php new file mode 100644 index 0000000000000..29bb56b1df906 --- /dev/null +++ b/tests/phpunit/tests/functions/wpMkdirP.php @@ -0,0 +1,51 @@ +assertTrue( wp_mkdir_p( $target ) ); + $this->assertDirectoryExists( $target ); + } + + public function test_if_file_with_name_extists() { + + $this->assertFalse( wp_mkdir_p( ABSPATH . 'wp-admin/index.php' ) ); + } + + public function test_if_folder_with_name_exists() { + + $this->assertTrue( wp_mkdir_p( ABSPATH . 'wp-admin' ) ); + } + + // should return false ../ in path + // Do not allow path traversals. + public function test_if_up_tree_in_target() { + + $this->assertFalse( wp_mkdir_p( '../wp-admin' ) ); + $this->assertFalse( wp_mkdir_p( '../../test' ) ); + $this->assertFalse( wp_mkdir_p( '..' . DIRECTORY_SEPARATOR . 'test' ) ); + $this->assertFalse( wp_mkdir_p( ABSPATH . 'test/../../' ) ); + + // this resolves to current dir so is found + $this->assertTrue( wp_mkdir_p( '../../../../' ) ); + } + + public function test_permissions_are_set() { + + $upload_dir = wp_upload_dir(); + $target = $upload_dir['basedir'] . 'permission_test'; + $parent_stat = stat( $upload_dir['basedir'] ); + $this->assertTrue( wp_mkdir_p( $target ) ); + $target_stat = stat( $target ); + $this->assertSame( $parent_stat['mode'], $target_stat['mode'] ); + } +}