PluginProbe ʕ •ᴥ•ʔ
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 25.9
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v25.9
27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 19.1 19.10 19.11 19.12 19.13 19.14 19.2 19.3 19.4 19.5 19.5.1 19.6 19.6.1 19.7 19.7.1 19.7.2 19.8 19.9 20.0 20.1 20.10 20.11 20.12 20.13 20.2 20.2.1 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.8.1 21.9 21.9.1 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.8.1 24.9 25.0 25.1 25.2 25.3 25.3.1 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.1.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.1.1 27.2 27.3 27.4
wordpress-seo / vendor_prefixed / guzzlehttp / psr7 / src / UriResolver.php
wordpress-seo / vendor_prefixed / guzzlehttp / psr7 / src Last commit date
Exception 2 years ago AppendStream.php 2 years ago BufferStream.php 2 years ago CachingStream.php 2 years ago DroppingStream.php 2 years ago FnStream.php 2 years ago Header.php 2 years ago HttpFactory.php 2 years ago InflateStream.php 2 years ago LazyOpenStream.php 2 years ago LimitStream.php 2 years ago Message.php 2 years ago MessageTrait.php 2 years ago MimeType.php 2 years ago MultipartStream.php 2 years ago NoSeekStream.php 2 years ago PumpStream.php 2 years ago Query.php 2 years ago Request.php 2 years ago Response.php 2 years ago Rfc7230.php 2 years ago ServerRequest.php 2 years ago Stream.php 2 years ago StreamDecoratorTrait.php 2 years ago StreamWrapper.php 2 years ago UploadedFile.php 2 years ago Uri.php 2 years ago UriComparator.php 2 years ago UriNormalizer.php 2 years ago UriResolver.php 2 years ago Utils.php 2 years ago
UriResolver.php
181 lines
1 <?php
2
3 declare (strict_types=1);
4 namespace YoastSEO_Vendor\GuzzleHttp\Psr7;
5
6 use YoastSEO_Vendor\Psr\Http\Message\UriInterface;
7 /**
8 * Resolves a URI reference in the context of a base URI and the opposite way.
9 *
10 * @author Tobias Schultze
11 *
12 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5
13 */
14 final class UriResolver
15 {
16 /**
17 * Removes dot segments from a path and returns the new path.
18 *
19 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
20 */
21 public static function removeDotSegments(string $path) : string
22 {
23 if ($path === '' || $path === '/') {
24 return $path;
25 }
26 $results = [];
27 $segments = \explode('/', $path);
28 foreach ($segments as $segment) {
29 if ($segment === '..') {
30 \array_pop($results);
31 } elseif ($segment !== '.') {
32 $results[] = $segment;
33 }
34 }
35 $newPath = \implode('/', $results);
36 if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
37 // Re-add the leading slash if necessary for cases like "/.."
38 $newPath = '/' . $newPath;
39 } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
40 // Add the trailing slash if necessary
41 // If newPath is not empty, then $segment must be set and is the last segment from the foreach
42 $newPath .= '/';
43 }
44 return $newPath;
45 }
46 /**
47 * Converts the relative URI into a new URI that is resolved against the base URI.
48 *
49 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2
50 */
51 public static function resolve(\YoastSEO_Vendor\Psr\Http\Message\UriInterface $base, \YoastSEO_Vendor\Psr\Http\Message\UriInterface $rel) : \YoastSEO_Vendor\Psr\Http\Message\UriInterface
52 {
53 if ((string) $rel === '') {
54 // we can simply return the same base URI instance for this same-document reference
55 return $base;
56 }
57 if ($rel->getScheme() != '') {
58 return $rel->withPath(self::removeDotSegments($rel->getPath()));
59 }
60 if ($rel->getAuthority() != '') {
61 $targetAuthority = $rel->getAuthority();
62 $targetPath = self::removeDotSegments($rel->getPath());
63 $targetQuery = $rel->getQuery();
64 } else {
65 $targetAuthority = $base->getAuthority();
66 if ($rel->getPath() === '') {
67 $targetPath = $base->getPath();
68 $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
69 } else {
70 if ($rel->getPath()[0] === '/') {
71 $targetPath = $rel->getPath();
72 } else {
73 if ($targetAuthority != '' && $base->getPath() === '') {
74 $targetPath = '/' . $rel->getPath();
75 } else {
76 $lastSlashPos = \strrpos($base->getPath(), '/');
77 if ($lastSlashPos === \false) {
78 $targetPath = $rel->getPath();
79 } else {
80 $targetPath = \substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
81 }
82 }
83 }
84 $targetPath = self::removeDotSegments($targetPath);
85 $targetQuery = $rel->getQuery();
86 }
87 }
88 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Uri(\YoastSEO_Vendor\GuzzleHttp\Psr7\Uri::composeComponents($base->getScheme(), $targetAuthority, $targetPath, $targetQuery, $rel->getFragment()));
89 }
90 /**
91 * Returns the target URI as a relative reference from the base URI.
92 *
93 * This method is the counterpart to resolve():
94 *
95 * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
96 *
97 * One use-case is to use the current request URI as base URI and then generate relative links in your documents
98 * to reduce the document size or offer self-contained downloadable document archives.
99 *
100 * $base = new Uri('http://example.com/a/b/');
101 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
102 * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
103 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
104 * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
105 *
106 * This method also accepts a target that is already relative and will try to relativize it further. Only a
107 * relative-path reference will be returned as-is.
108 *
109 * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
110 */
111 public static function relativize(\YoastSEO_Vendor\Psr\Http\Message\UriInterface $base, \YoastSEO_Vendor\Psr\Http\Message\UriInterface $target) : \YoastSEO_Vendor\Psr\Http\Message\UriInterface
112 {
113 if ($target->getScheme() !== '' && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')) {
114 return $target;
115 }
116 if (\YoastSEO_Vendor\GuzzleHttp\Psr7\Uri::isRelativePathReference($target)) {
117 // As the target is already highly relative we return it as-is. It would be possible to resolve
118 // the target with `$target = self::resolve($base, $target);` and then try make it more relative
119 // by removing a duplicate query. But let's not do that automatically.
120 return $target;
121 }
122 if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
123 return $target->withScheme('');
124 }
125 // We must remove the path before removing the authority because if the path starts with two slashes, the URI
126 // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
127 // invalid.
128 $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
129 if ($base->getPath() !== $target->getPath()) {
130 return $emptyPathUri->withPath(self::getRelativePath($base, $target));
131 }
132 if ($base->getQuery() === $target->getQuery()) {
133 // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
134 return $emptyPathUri->withQuery('');
135 }
136 // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
137 // inherit the base query component when resolving.
138 if ($target->getQuery() === '') {
139 $segments = \explode('/', $target->getPath());
140 /** @var string $lastSegment */
141 $lastSegment = \end($segments);
142 return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
143 }
144 return $emptyPathUri;
145 }
146 private static function getRelativePath(\YoastSEO_Vendor\Psr\Http\Message\UriInterface $base, \YoastSEO_Vendor\Psr\Http\Message\UriInterface $target) : string
147 {
148 $sourceSegments = \explode('/', $base->getPath());
149 $targetSegments = \explode('/', $target->getPath());
150 \array_pop($sourceSegments);
151 $targetLastSegment = \array_pop($targetSegments);
152 foreach ($sourceSegments as $i => $segment) {
153 if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
154 unset($sourceSegments[$i], $targetSegments[$i]);
155 } else {
156 break;
157 }
158 }
159 $targetSegments[] = $targetLastSegment;
160 $relativePath = \str_repeat('../', \count($sourceSegments)) . \implode('/', $targetSegments);
161 // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
162 // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
163 // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
164 if ('' === $relativePath || \false !== \strpos(\explode('/', $relativePath, 2)[0], ':')) {
165 $relativePath = "./{$relativePath}";
166 } elseif ('/' === $relativePath[0]) {
167 if ($base->getAuthority() != '' && $base->getPath() === '') {
168 // In this case an extra slash is added by resolve() automatically. So we must not add one here.
169 $relativePath = ".{$relativePath}";
170 } else {
171 $relativePath = "./{$relativePath}";
172 }
173 }
174 return $relativePath;
175 }
176 private function __construct()
177 {
178 // cannot be instantiated
179 }
180 }
181