From b351a2f05805cf2d8b9ee431020abbe692b8fb36 Mon Sep 17 00:00:00 2001 From: Anthony Burchell Date: Tue, 23 Aug 2022 19:57:17 +0000 Subject: [PATCH] Media: Account for Windows when normalizing file paths. Previously, Windows paths in the `path_is_absolute` function resulted in incorrect URIs. This patch adjusts for forward slashes and adds tests for the `get_attached_file` function. Props Whissi, SergeyBiryukov, desrosj, stevenlinx, birgire, davidbaumwald, costdev, peterwilsoncc, audrasjb, hellofromTonya, johnbillion. Fixes #36308. git-svn-id: https://develop.svn.wordpress.org/trunk@53934 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/functions.php | 6 ++ src/wp-includes/post.php | 5 +- tests/phpunit/tests/functions.php | 11 ++++ tests/phpunit/tests/post/getAttachedFile.php | 67 ++++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tests/phpunit/tests/post/getAttachedFile.php diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index eb8130d5b4..16462b07dc 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -2083,6 +2083,7 @@ function wp_mkdir_p( $target ) { * For example, '/foo/bar', or 'c:\windows'. * * @since 2.5.0 + * @since 6.1.0 Allows normalized Windows paths (forward slashes). * * @param string $path File path. * @return bool True if path is absolute, false is not absolute. @@ -2113,6 +2114,11 @@ function path_is_absolute( $path ) { return true; } + // Normalized Windows paths for local filesystem and network shares (forward slashes). + if ( preg_match( '#(^[a-zA-Z]+:/|^//[\w!@\#\$%\^\(\)\-\'{}\.~]{1,15})#', $path ) ) { + return true; + } + // A path starting with / or \ is absolute; anything else is relative. return ( '/' === $path[0] || '\\' === $path[0] ); } diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index b434ae52e4..214ab582cd 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -724,10 +724,11 @@ function get_attached_file( $attachment_id, $unfiltered = false ) { $file = get_post_meta( $attachment_id, '_wp_attached_file', true ); // If the file is relative, prepend upload dir. - if ( $file && 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ) { + if ( $file ) { $uploads = wp_get_upload_dir(); + if ( false === $uploads['error'] ) { - $file = $uploads['basedir'] . "/$file"; + $file = path_join( $uploads['basedir'], $file ); } } diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index 5f5a49c975..a7679be7f0 100644 --- a/tests/phpunit/tests/functions.php +++ b/tests/phpunit/tests/functions.php @@ -105,6 +105,13 @@ class Tests_Functions extends WP_UnitTestCase { 'C:\\', 'C:\\WINDOWS', '\\\\sambashare\\foo', + 'c:/', + 'c://', + '//', + 'c:/FOO', + '//FOO', + 'C:/WWW/Sites/demo/htdocs/wordpress/wp-content/uploads/2016/03/example.jpg', + '//ComputerName/ShareName/SubfolderName/example.txt', ); foreach ( $absolute_paths as $path ) { $this->assertTrue( path_is_absolute( $path ), "path_is_absolute('$path') should return true" ); @@ -119,10 +126,14 @@ class Tests_Functions extends WP_UnitTestCase { '../foo', '../', '../foo.bar', + 'foo.bar', 'foo/bar', 'foo', 'FOO', '..\\WINDOWS', + '..//WINDOWS', + 'c:', + 'C:', ); foreach ( $relative_paths as $path ) { $this->assertFalse( path_is_absolute( $path ), "path_is_absolute('$path') should return false" ); diff --git a/tests/phpunit/tests/post/getAttachedFile.php b/tests/phpunit/tests/post/getAttachedFile.php new file mode 100644 index 0000000000..09501b6c18 --- /dev/null +++ b/tests/phpunit/tests/post/getAttachedFile.php @@ -0,0 +1,67 @@ +post->create_and_get( + array( + 'post_title' => 'example-page', + 'post_type' => 'post', + ) + ); + } + + /** + * @ticket 36308 + * + * @dataProvider data_get_attached_file_with_windows_paths + * + * @param string $file The file path to attach to the post. + * @param string $expected The expected attached file path. + * @param string $message The message when an assertion fails. + */ + public function test_get_attached_file_with_windows_paths( $file, $expected, $message ) { + $attachment = self::factory()->attachment->create_and_get( + array( + 'post_parent' => self::$post->ID, + 'file' => $file, + ) + ); + + $this->assertSame( $expected, get_attached_file( $attachment->ID ), $message ); + } + + /** + * Data provider with Windows paths. + * + * @return array + */ + public function data_get_attached_file_with_windows_paths() { + return array( + 'a local path' => array( + 'file' => 'C:/WWW/Sites/demo/htdocs/wordpress/wp-content/uploads/2016/03/example.jpg', + 'expected' => 'C:/WWW/Sites/demo/htdocs/wordpress/wp-content/uploads/2016/03/example.jpg', + 'message' => 'Windows local filesystem paths should be equal', + ), + 'a network share path' => array( + 'file' => '//ComputerName/ShareName/SubfolderName/example.txt', + 'expected' => '//ComputerName/ShareName/SubfolderName/example.txt', + 'message' => 'Network share paths should be equal', + ), + ); + } + +}