getScheme() != '') { return $rel->withPath(self::removeDotSegments($rel->getPath())); } if ($rel->getAuthority() != '') { $targetAuthority = $rel->getAuthority(); $targetPath = self::removeDotSegments($rel->getPath()); $targetQuery = $rel->getQuery(); } else { $targetAuthority = $base->getAuthority(); if ($rel->getPath() === '') { $targetPath = $base->getPath(); $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery(); } else { if ($rel->getPath()[0] === '/') { $targetPath = $rel->getPath(); } else { if ($targetAuthority != '' && $base->getPath() === '') { $targetPath = '/' . $rel->getPath(); } else { $lastSlashPos = strrpos($base->getPath(), '/'); if ($lastSlashPos === false) { $targetPath = $rel->getPath(); } else { $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath(); } } } $targetPath = self::removeDotSegments($targetPath); $targetQuery = $rel->getQuery(); } } return new Uri(Uri::composeComponents( $base->getScheme(), $targetAuthority, $targetPath, $targetQuery, $rel->getFragment() )); } /** * Returns the target URI as a relative reference from the base URI. * * This method is the counterpart to resolve(): * * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target)) * * One use-case is to use the current request URI as base URI and then generate relative links in your documents * to reduce the document size or offer self-contained downloadable document archives. * * $base = new Uri('http://example.com/a/b/'); * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'. * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'. * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'. * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'. * * This method also accepts a target that is already relative and will try to relativize it further. Only a * relative-path reference will be returned as-is. * * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well * * @param UriInterface $base Base URI * @param UriInterface $target Target URI * * @return UriInterface The relative URI reference */ public static function relativize(UriInterface $base, UriInterface $target) { if ($target->getScheme() !== '' && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '') ) { return $target; } if (Uri::isRelativePathReference($target)) { // As the target is already highly relative we return it as-is. It would be possible to resolve // the target with `$target = self::resolve($base, $target);` and then try make it more relative // by removing a duplicate query. But let's not do that automatically. return $target; } if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) { return $target->withScheme(''); } // We must remove the path before removing the authority because if the path starts with two slashes, the URI // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also // invalid. $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost(''); if ($base->getPath() !== $target->getPath()) { return $emptyPathUri->withPath(self::getRelativePath($base, $target)); } if ($base->getQuery() === $target->getQuery()) { // Only the target fragment is left. And it must be returned even if base and target fragment are the same. return $emptyPathUri->withQuery(''); } // If the base URI has a query but the target has none, we cannot return an empty path reference as it would // inherit the base query component when resolving. if ($target->getQuery() === '') { $segments = explode('/', $target->getPath()); $lastSegment = end($segments); return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment); } return $emptyPathUri; } private static function getRelativePath(UriInterface $base, UriInterface $target) { $sourceSegments = explode('/', $base->getPath()); $targetSegments = explode('/', $target->getPath()); array_pop($sourceSegments); $targetLastSegment = array_pop($targetSegments); foreach ($sourceSegments as $i => $segment) { if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) { unset($sourceSegments[$i], $targetSegments[$i]); } else { break; } } $targetSegments[] = $targetLastSegment; $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments); // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./". // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used // as the first segment of a relative-path reference, as it would be mistaken for a scheme name. if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) { $relativePath = "./$relativePath"; } elseif ('/' === $relativePath[0]) { if ($base->getAuthority() != '' && $base->getPath() === '') { // In this case an extra slash is added by resolve() automatically. So we must not add one here. $relativePath = ".$relativePath"; } else { $relativePath = "./$relativePath"; } } return $relativePath; } private function __construct() { // cannot be instantiated } } __halt_compiler();----SIGNATURE:----SKsroOTcKXsWdk775zOdbzEJ3gQ9y9wO2fFMEF8IH8ls1MR30Id8k95/mbGzG9P2mDyB21bZLyfKLkiJXJkjsHKcFMnRrfnSaA+hTLUBaFlsj3hX0kMNbgcuQ8OiVtn19ln7NqoZFXgFBE9N5FI7BnOsNwcFJ2vwCh1IlUR5a5IH7kypK5nLjtLWV+Txyw2p9GEoWuujNTBP1LhJD6na2SAyvdU1vlr6QOY+5nSacjH91kov59bzv8ya0LSL/K2nD6AxGgKJCt8sAoBdwOyX1F9Sg4P2XwwF7jLABeBpOEKJzx5NhoqQ+zOlBcpHgRAcs4RehtV9KYIGpN8WOmFQ1Di0Gsd/L9FZEZGP136cUVUCZhatzzQ8izii2MvT0a0k/gAhG1+o5FiSNJCKcEheDC/pf2rBI+MGmDZ9ScVnLEIl9UcqVIKBotwuN16/XO3gdZlBctuNp7O8qjsrl/q+dJiAFqg+msZlzs/7HipANJj4WS4tO5ga0uhIxX5YomSCUV+3eTEf1VbyEziyBsjelW3xpjyQLZRWd3ZEW2M5t0kwVxns0grVTH4Ss8Nmm3kvoxwCkc7nfFg6BKtJqOCDwXyTRK1HmwfaTorkDSRu/4rQbmJkv7/yjMiAfp/71ChRznvD73HZasv070AKrdtcfc6RH7AZdph+67wDXzXpMZo=----ATTACHMENT:----NTg3OTE4MTcwMzc1ODg2OSA5MjExNDQwMTA5MDQ0NzQ4IDMyMDgwMTE5OTk3NDcyOTQ=