Skip to content

Commit eac0893

Browse files
Fix wrong combined paths when traversing upwards. Fixes #557 (#652)
* Fix wrong combined paths when traversing upwards. Fixes #557 * docs: add changelog entry --------- Co-authored-by: Danny van der Sluijs <[email protected]>
1 parent 60488b2 commit eac0893

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Add missing property in UriResolverTest ([#743](https://github.com/jsonrainbow/json-schema/pull/743))
1616
- Correct casing of paths used in tests ([#745](https://github.com/jsonrainbow/json-schema/pull/745))
1717
- Resolve deprecations of optional parameter ([#752](https://github.com/jsonrainbow/json-schema/pull/752))
18+
- Fix wrong combined paths when traversing upward, fixes #557 ([#652](https://github.com/jsonrainbow/json-schema/pull/652))
1819

1920
### Changed
2021
- Bump to minimum PHP 7.2 ([#746](https://github.com/jsonrainbow/json-schema/pull/746))

phpstan-baseline.neon

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,21 +1030,11 @@ parameters:
10301030
count: 1
10311031
path: src/JsonSchema/Uri/UriResolver.php
10321032

1033-
-
1034-
message: "#^Offset 0 does not exist on array\\{0\\?\\: string, 1\\?\\: non\\-falsy\\-string\\}\\.$#"
1035-
count: 1
1036-
path: src/JsonSchema/Uri/UriResolver.php
1037-
10381033
-
10391034
message: "#^Parameter \\#1 \\$uri of method JsonSchema\\\\Uri\\\\UriResolver\\:\\:parse\\(\\) expects string, string\\|null given\\.$#"
10401035
count: 1
10411036
path: src/JsonSchema/Uri/UriResolver.php
10421037

1043-
-
1044-
message: "#^Parameter \\#3 \\$length of function array_slice expects int\\|null, float\\|int\\<1, max\\> given\\.$#"
1045-
count: 1
1046-
path: src/JsonSchema/Uri/UriResolver.php
1047-
10481038
-
10491039
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
10501040
count: 1

src/JsonSchema/Uri/UriResolver.php

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,25 +125,37 @@ public function resolve($uri, $baseUri = null)
125125
public static function combineRelativePathWithBasePath($relativePath, $basePath)
126126
{
127127
$relativePath = self::normalizePath($relativePath);
128-
if ($relativePath == '') {
128+
if (!$relativePath) {
129129
return $basePath;
130130
}
131-
if ($relativePath[0] == '/') {
131+
if ($relativePath[0] === '/') {
132132
return $relativePath;
133133
}
134-
135-
$basePathSegments = explode('/', $basePath);
136-
137-
preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
138-
$numLevelUp = strlen($match[0]) /3 + 1;
139-
if ($numLevelUp >= count($basePathSegments)) {
134+
if (!$basePath) {
140135
throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
141136
}
142137

143-
$basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
144-
$path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
138+
$dirname = $basePath[strlen($basePath) - 1] === '/' ? $basePath : dirname($basePath);
139+
$combined = rtrim($dirname, '/') . '/' . ltrim($relativePath, '/');
140+
$combinedSegments = explode('/', $combined);
141+
$collapsedSegments = [];
142+
while ($combinedSegments) {
143+
$segment = array_shift($combinedSegments);
144+
if ($segment === '..') {
145+
if (count($collapsedSegments) <= 1) {
146+
// Do not remove the top level (domain)
147+
// This is not ideal - the domain should not be part of the path here. parse() and generate()
148+
// should handle the "domain" separately, like the schema.
149+
// Then the if-condition here would be `if (!$collapsedSegments) {`.
150+
throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
151+
}
152+
array_pop($collapsedSegments);
153+
} else {
154+
$collapsedSegments[] = $segment;
155+
}
156+
}
145157

146-
return implode('/', $basePathSegments) . '/' . $path;
158+
return implode('/', $collapsedSegments);
147159
}
148160

149161
/**

tests/Uri/UriResolverTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
class UriResolverTest extends TestCase
99
{
10+
/**
11+
* @var UriResolver
12+
*/
1013
private $resolver;
1114

1215
public function setUp(): void
@@ -85,6 +88,21 @@ public function testCombineRelativePathWithBasePathNoPath(): void
8588
);
8689
}
8790

91+
/**
92+
* Covers https://github.com/justinrainbow/json-schema/issues/557
93+
* Relative paths yield wrong result.
94+
*/
95+
public function testCombineRelativePathWithBasePathTraversingUp(): void
96+
{
97+
$this->assertEquals(
98+
'/var/packages/schema/UuidSchema.json',
99+
UriResolver::combineRelativePathWithBasePath(
100+
'../../../schema/UuidSchema.json',
101+
'/var/packages/foo/tests/UnitTests/DemoData/../../../schema/Foo/FooSchema_latest.json'
102+
)
103+
);
104+
}
105+
88106
public function testResolveAbsoluteUri(): void
89107
{
90108
$this->assertEquals(

0 commit comments

Comments
 (0)