diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d27f2a3..91b75e49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All Notable changes to `League\Uri` will be documented in this file +## 6.3.1 - 2020-11-23 + +### Added + +- None + +### Fixed + +- Bugfix `Uri::formatPath` to improve URL encoding in the path component [#180](https://github.com/thephpleague/uri/pull/180) thanks [mdawaffe](https://github.com/mdawaffe). + +### Deprecated + +- Nothing + +### Remove + +- None + ## 6.3.0 - 2020-08-13 ### Added diff --git a/src/Uri.php b/src/Uri.php index 5740bdfb..50e954c3 100644 --- a/src/Uri.php +++ b/src/Uri.php @@ -145,8 +145,11 @@ final class Uri implements UriInterface /** * Regular expression pattern to for file URI. + * contains the volume but not the volume separator. + * The volume separator may be URL-encoded (`|` as `%7C`) by ::formatPath(), + * so we account for that here. */ - private const REGEXP_FILE_PATH = ',^(?/)?(?[a-zA-Z][:|\|])(?.*)?,'; + private const REGEXP_FILE_PATH = ',^(?/)?(?[a-zA-Z])(?:[:|\|]|%7C)(?.*)?,'; /** * Mimetype regular expression pattern. @@ -164,6 +167,7 @@ final class Uri implements UriInterface /** * Windows file path string regular expression pattern. + * contains both the volume and volume separator. */ private const REGEXP_WINDOW_PATH = ',^(?[a-zA-Z][:|\|]),'; @@ -972,7 +976,7 @@ private function formatPath(string $path): string { $path = $this->formatDataPath($path); - static $pattern = '/(?:[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.'%:@\/}{]++\|%(?![A-Fa-f0-9]{2}))/'; + static $pattern = '/(?:[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.'%:@\/}{]++|%(?![A-Fa-f0-9]{2}))/'; $path = (string) preg_replace_callback($pattern, [Uri::class, 'urlEncodeMatch'], $path); @@ -1071,7 +1075,7 @@ private function formatFilePath(string $path): string } $replace = static function (array $matches): string { - return $matches['delim'].str_replace('|', ':', $matches['root']).$matches['rest']; + return $matches['delim'].$matches['volume'].':'.$matches['rest']; }; return (string) preg_replace_callback(self::REGEXP_FILE_PATH, $replace, $path); diff --git a/tests/UriTest.php b/tests/UriTest.php index 19a6ef6b..f1df5346 100644 --- a/tests/UriTest.php +++ b/tests/UriTest.php @@ -549,6 +549,20 @@ public function testReservedCharsInPathUnencoded(): void ); } + /** + * @covers ::formatPath + */ + public function testUnreservedCharsInPathUnencoded(): void + { + $uri = Uri::createFromString('http://www.example.com/') + ->withPath('/h"ell\'o/./wor ld/%25abc%xyz'); + + self::assertSame( + "/h%22ell'o/./wor%20ld%3Ci%3E/%25abc%25xyz", + $uri->getPath() + ); + } + /** * @dataProvider userInfoProvider * @param ?string $credential