25 if ($path ===
'' || $path ===
'/') {
30 $segments = explode(
'/', $path);
31 foreach ($segments as $segment) {
32 if ($segment ===
'..') {
34 } elseif ($segment !==
'.') {
35 $results[] = $segment;
39 $newPath = implode(
'/', $results);
41 if ($path[0] ===
'/' && (!isset($newPath[0]) || $newPath[0] !==
'/')) {
43 $newPath =
'/' . $newPath;
44 } elseif ($newPath !==
'' && ($segment ===
'.' || $segment ===
'..')) {
64 if ((
string) $rel ===
'') {
83 if ($rel->
getPath()[0] ===
'/') {
86 if ($targetAuthority !=
'' && $base->
getPath() ===
'') {
87 $targetPath =
'/' . $rel->
getPath();
89 $lastSlashPos = strrpos($base->
getPath(),
'/');
90 if ($lastSlashPos ===
false) {
93 $targetPath = substr($base->
getPath(), 0, $lastSlashPos + 1) . $rel->
getPath();
159 $emptyPathUri = $target->
withScheme(
'')->withPath(
'')->withUserInfo(
'')->withPort(
null)->withHost(
'');
162 return $emptyPathUri->withPath(self::getRelativePath($base, $target));
167 return $emptyPathUri->withQuery(
'');
173 $segments = explode(
'/', $target->
getPath());
174 $lastSegment = end($segments);
176 return $emptyPathUri->withPath($lastSegment ===
'' ?
'./' : $lastSegment);
179 return $emptyPathUri;
184 $sourceSegments = explode(
'/', $base->
getPath());
185 $targetSegments = explode(
'/', $target->
getPath());
186 array_pop($sourceSegments);
187 $targetLastSegment = array_pop($targetSegments);
188 foreach ($sourceSegments as $i => $segment) {
189 if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
190 unset($sourceSegments[$i], $targetSegments[$i]);
195 $targetSegments[] = $targetLastSegment;
196 $relativePath = str_repeat(
'../',
count($sourceSegments)) . implode(
'/', $targetSegments);
201 if (
'' === $relativePath ||
false !== strpos(explode(
'/', $relativePath, 2)[0],
':')) {
202 $relativePath =
"./$relativePath";
203 } elseif (
'/' === $relativePath[0]) {
206 $relativePath =
".$relativePath";
208 $relativePath =
"./$relativePath";
212 return $relativePath;
215 private function __construct()