diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index f5002a45de1e8..e386a23ccf12d 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -7494,6 +7494,7 @@ function _device_can_upload() { * Tests if a given path is a stream URL * * @since 3.5.0 + * @since 7.2.0 A lowercased scheme is accepted as a fallback, matching PHP. * * @param string $path The resource path or URL. * @return bool True if the path is a stream URL. @@ -7506,9 +7507,15 @@ function wp_is_stream( $path ) { return false; } - $stream = substr( $path, 0, $scheme_separator ); + $stream = substr( $path, 0, $scheme_separator ); + $wrappers = stream_get_wrappers(); - return in_array( $stream, stream_get_wrappers(), true ); + /* + * PHP looks the scheme up as given, then retries once with it lowercased. + * This is not a case-insensitive match: a wrapper registered as `MyStream` + * is not reachable as `mystream`. + */ + return in_array( $stream, $wrappers, true ) || in_array( strtolower( $stream ), $wrappers, true ); } /** diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index 19c721aeaa46a..9db34df8f4a87 100644 --- a/tests/phpunit/tests/functions.php +++ b/tests/phpunit/tests/functions.php @@ -2007,6 +2007,8 @@ public function data_validate_file() { /** * Test stream URL validation. * + * @ticket 65870 + * * @dataProvider data_wp_is_stream * * @param string $path The resource path or URL. @@ -2037,6 +2039,7 @@ public function data_wp_is_stream() { array( 'https://example.com', true ), array( 'ftp://example.com', true ), array( 'file:///path/to/some/file', true ), + array( 'FILE:///path/to/some/file', true ), array( 'php://some/php/file.php', true ), // Non-stream examples. @@ -2047,6 +2050,25 @@ public function data_wp_is_stream() { ); } + /** + * Tests that a wrapper registered under a mixed case scheme is not + * reachable under a lowercased scheme. + * + * @ticket 65870 + */ + public function test_wp_is_stream_does_not_lowercase_registered_wrappers() { + require_once DIR_TESTROOT . '/includes/class-wp-test-stream.php'; + stream_wrapper_register( 'wpTestMixedCase', 'WP_Test_Stream' ); + + $exact = wp_is_stream( 'wpTestMixedCase://foo' ); + $lowercased = wp_is_stream( 'wptestmixedcase://foo' ); + + stream_wrapper_unregister( 'wpTestMixedCase' ); + + $this->assertTrue( $exact, 'The scheme was not matched as registered.' ); + $this->assertFalse( $lowercased, 'A lowercased scheme matched a mixed case wrapper.' ); + } + /** * Test human_readable_duration(). *