diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
index aa507bb004..81409e9382 100644
--- a/src/wp-includes/functions.php
+++ b/src/wp-includes/functions.php
@@ -8221,21 +8221,50 @@ function recurse_dirsize( $directory, $exclude = null, $max_execution_time = nul
* Removes the current directory and all parent directories from the `dirsize_cache` transient.
*
* @since 5.6.0
+ * @since 5.9.0 Added input validation with a notice for invalid input.
*
* @param string $path Full path of a directory or file.
*/
function clean_dirsize_cache( $path ) {
+ if ( ! is_string( $path ) || empty( $path ) ) {
+ trigger_error(
+ sprintf(
+ /* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */
+ __( '%1$s only accepts a non-empty path string, received %2$s.' ),
+ 'clean_dirsize_cache()',
+ '' . gettype( $path ) . ''
+ )
+ );
+ return;
+ }
+
$directory_cache = get_transient( 'dirsize_cache' );
if ( empty( $directory_cache ) ) {
return;
}
- $path = untrailingslashit( $path );
+ if (
+ strpos( $path, '/' ) === false &&
+ strpos( $path, '\\' ) === false
+ ) {
+ unset( $directory_cache[ $path ] );
+ set_transient( 'dirsize_cache', $directory_cache );
+ return;
+ }
+
+ $last_path = null;
+ $path = untrailingslashit( $path );
unset( $directory_cache[ $path ] );
- while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) {
- $path = dirname( $path );
+ while (
+ $last_path !== $path &&
+ DIRECTORY_SEPARATOR !== $path &&
+ '.' !== $path &&
+ '..' !== $path
+ ) {
+ $last_path = $path;
+ $path = dirname( $path );
unset( $directory_cache[ $path ] );
}
diff --git a/tests/phpunit/tests/functions/cleanDirsizeCache.php b/tests/phpunit/tests/functions/cleanDirsizeCache.php
new file mode 100644
index 0000000000..6ae7d6d2dc
--- /dev/null
+++ b/tests/phpunit/tests/functions/cleanDirsizeCache.php
@@ -0,0 +1 @@
+expectNotice();
$this->expectNoticeMessage( $expected_message );
clean_dirsize_cache( $path );
}
/**
* Data provider.
*
* @return array
*/
public function data_clean_dirsize_cache_with_invalid_inputs() {
return array(
'null' => array(
'path' => null,
'expected_message' => 'clean_dirsize_cache() only accepts a non-empty path string, received NULL.',
),
'bool false' => array(
'path' => false,
'expected_message' => 'clean_dirsize_cache() only accepts a non-empty path string, received boolean.',
),
'empty string' => array(
'path' => '',
'expected_message' => 'clean_dirsize_cache() only accepts a non-empty path string, received string.',
),
'array' => array(
'path' => array( '.', './second/path/' ),
'expected_message' => 'clean_dirsize_cache() only accepts a non-empty path string, received array.',
),
);
}
/**
* Test the handling of a non-path text string passed as the $path parameter.
*
* @ticket 52241
*
* @dataProvider data_clean_dirsize_cache_with_non_path_string
*
* @param string $path Path input to use in the test.
* @param int $expected_count Expected number of paths in the cache after cleaning.
*/
public function test_clean_dirsize_cache_with_non_path_string( $path, $expected_count ) {
// Set the dirsize cache to our mock.
set_transient( 'dirsize_cache', $this->mock_dirsize_cache_with_non_path_string() );
clean_dirsize_cache( $path );
$cache = get_transient( 'dirsize_cache' );
$this->assertIsArray( $cache );
$this->assertCount( $expected_count, $cache );
}
/**
* Data provider.
*
* @return array
*/
public function data_clean_dirsize_cache_with_non_path_string() {
return array(
'single dot' => array(
'path' => '.',
'expected_count' => 1,
),
'non-path' => array(
'path' => 'string',
'expected_count' => 1,
),
'non-existant string, but non-path' => array(
'path' => 'doesnotexist',
'expected_count' => 2,
),
);
}
private function mock_dirsize_cache_with_non_path_string() {
return array(
'.' => array( 'size' => 50 ),
'string' => array( 'size' => 42 ),
);
}
}
\ No newline at end of file