PluginProbe
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more / 2.5.5
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more v2.5.5
3.7.2 3.7.1 3.7.0 3.6.0 3.6.1 3.5.2 trunk 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.6.0 2.6.1 All 73 releases
stockpack / vendor / guzzlehttp / psr7 / src / UriResolver.php

UriResolver.php in StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more 2.5.5, at vendor/guzzlehttp/psr7/src/UriResolver.php

220 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace GuzzleHttp\Psr7;
3
4 use Psr\Http\Message\UriInterface;
5
6 /**
7 * Resolves a URI reference in the context of a base URI and the opposite way.
8 *
9 * @author Tobias Schultze
10 *
11 * @link https://tools.ietf.org/html/rfc3986#section-5
12 */
13 final class UriResolver
14 {
15 /**
16 * Removes dot segments from a path and returns the new path.
17 *
18 * @param string $path
19 *
20 * @return string
21 * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
22 */
23 public static function removeDotSegments($path)
24 {
25 if ($path === '' || $path === '/') {
26 return $path;
27 }
28
29 $results = [];
30 $segments = explode('/', $path);
31 foreach ($segments as $segment) {
32 if ($segment === '..') {
33 array_pop($results);
34 } elseif ($segment !== '.') {
35 $results[] = $segment;
36 }
37 }
38
39 $newPath = implode('/', $results);
40
41 if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
42 // Re-add the leading slash if necessary for cases like "/.."
43 $newPath = '/' . $newPath;
44 } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
45 // Add the trailing slash if necessary
46 // If newPath is not empty, then $segment must be set and is the last segment from the foreach
47 $newPath .= '/';
48 }
49
50 return $newPath;
51 }
52
53 /**
54 * Converts the relative URI into a new URI that is resolved against the base URI.
55 *
56 * @param UriInterface $base Base URI
57 * @param UriInterface $rel Relative URI
58 *
59 * @return UriInterface
60 * @link http://tools.ietf.org/html/rfc3986#section-5.2
61 */
62 public static function resolve(UriInterface $base, UriInterface $rel)
63 {
64 if ((string) $rel === '') {
65 // we can simply return the same base URI instance for this same-document reference
66 return $base;
67 }
68
69 if ($rel->getScheme() != '') {
70 return $rel->withPath(self::removeDotSegments($rel->getPath()));
71 }
72
73 if ($rel->getAuthority() != '') {
74 $targetAuthority = $rel->getAuthority();
75 $targetPath = self::removeDotSegments($rel->getPath());
76 $targetQuery = $rel->getQuery();
77 } else {
78 $targetAuthority = $base->getAuthority();
79 if ($rel->getPath() === '') {
80 $targetPath = $base->getPath();
81 $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
82 } else {
83 if ($rel->getPath()[0] === '/') {
84 $targetPath = $rel->getPath();
85 } else {
86 if ($targetAuthority != '' && $base->getPath() === '') {
87 $targetPath = '/' . $rel->getPath();
88 } else {
89 $lastSlashPos = strrpos($base->getPath(), '/');
90 if ($lastSlashPos === false) {
91 $targetPath = $rel->getPath();
92 } else {
93 $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
94 }
95 }
96 }
97 $targetPath = self::removeDotSegments($targetPath);
98 $targetQuery = $rel->getQuery();
99 }
100 }
101
102 return new Uri(Uri::composeComponents(
103 $base->getScheme(),
104 $targetAuthority,
105 $targetPath,
106 $targetQuery,
107 $rel->getFragment()
108 ));
109 }
110
111 /**
112 * Returns the target URI as a relative reference from the base URI.
113 *
114 * This method is the counterpart to resolve():
115 *
116 * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
117 *
118 * One use-case is to use the current request URI as base URI and then generate relative links in your documents
119 * to reduce the document size or offer self-contained downloadable document archives.
120 *
121 * $base = new Uri('http://example.com/a/b/');
122 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
123 * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
124 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
125 * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
126 *
127 * This method also accepts a target that is already relative and will try to relativize it further. Only a
128 * relative-path reference will be returned as-is.
129 *
130 * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
131 *
132 * @param UriInterface $base Base URI
133 * @param UriInterface $target Target URI
134 *
135 * @return UriInterface The relative URI reference
136 */
137 public static function relativize(UriInterface $base, UriInterface $target)
138 {
139 if ($target->getScheme() !== '' &&
140 ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
141 ) {
142 return $target;
143 }
144
145 if (Uri::isRelativePathReference($target)) {
146 // As the target is already highly relative we return it as-is. It would be possible to resolve
147 // the target with `$target = self::resolve($base, $target);` and then try make it more relative
148 // by removing a duplicate query. But let's not do that automatically.
149 return $target;
150 }
151
152 if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
153 return $target->withScheme('');
154 }
155
156 // We must remove the path before removing the authority because if the path starts with two slashes, the URI
157 // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
158 // invalid.
159 $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
160
161 if ($base->getPath() !== $target->getPath()) {
162 return $emptyPathUri->withPath(self::getRelativePath($base, $target));
163 }
164
165 if ($base->getQuery() === $target->getQuery()) {
166 // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
167 return $emptyPathUri->withQuery('');
168 }
169
170 // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
171 // inherit the base query component when resolving.
172 if ($target->getQuery() === '') {
173 $segments = explode('/', $target->getPath());
174 $lastSegment = end($segments);
175
176 return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
177 }
178
179 return $emptyPathUri;
180 }
181
182 private static function getRelativePath(UriInterface $base, UriInterface $target)
183 {
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]);
191 } else {
192 break;
193 }
194 }
195 $targetSegments[] = $targetLastSegment;
196 $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
197
198 // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
199 // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
200 // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
201 if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
202 $relativePath = "./$relativePath";
203 } elseif ('/' === $relativePath[0]) {
204 if ($base->getAuthority() != '' && $base->getPath() === '') {
205 // In this case an extra slash is added by resolve() automatically. So we must not add one here.
206 $relativePath = ".$relativePath";
207 } else {
208 $relativePath = "./$relativePath";
209 }
210 }
211
212 return $relativePath;
213 }
214
215 private function __construct()
216 {
217 // cannot be instantiated
218 }
219 }
220