PluginProbe ʕ •ᴥ•ʔ
Check & Log Email – Easy Email Testing & Mail logging / 2.0.15
Check & Log Email – Easy Email Testing & Mail logging v2.0.15
2.0.15 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 2.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.13.1 2.0.13.2 2.0.14 2.0.2 2.0.3 2.0.4 2.0.5 2.0.5.1 2.0.6 2.0.7 2.0.8 2.0.9 trunk 0.5.7 0.6.0 0.6.1 0.6.2 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.12.1 1.0.13 1.0.13.1 1.0.2 1.0.3
check-email / vendor / guzzlehttp / psr7 / src / UriResolver.php
check-email / vendor / guzzlehttp / psr7 / src Last commit date
Exception 1 week ago AppendStream.php 1 week ago BufferStream.php 1 week ago CachingStream.php 1 week ago DroppingStream.php 1 week ago FnStream.php 1 week ago Header.php 1 week ago HttpFactory.php 1 week ago InflateStream.php 1 week ago LazyOpenStream.php 1 week ago LimitStream.php 1 week ago Message.php 1 week ago MessageTrait.php 1 week ago MimeType.php 1 week ago MultipartStream.php 1 week ago NoSeekStream.php 1 week ago PumpStream.php 1 week ago Query.php 1 week ago Request.php 1 week ago Response.php 1 week ago Rfc7230.php 1 week ago ServerRequest.php 1 week ago Stream.php 1 week ago StreamDecoratorTrait.php 1 week ago StreamWrapper.php 1 week ago UploadedFile.php 1 week ago Uri.php 1 week ago UriComparator.php 1 week ago UriNormalizer.php 1 week ago UriResolver.php 1 week ago Utils.php 1 week ago
UriResolver.php
212 lines
1 <?php
2
3 declare(strict_types=1);
4
5 namespace GuzzleHttp\Psr7;
6
7 use Psr\Http\Message\UriInterface;
8
9 /**
10 * Resolves a URI reference in the context of a base URI and the opposite way.
11 *
12 * @author Tobias Schultze
13 *
14 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5
15 */
16 final class UriResolver
17 {
18 /**
19 * Removes dot segments from a path and returns the new path.
20 *
21 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
22 */
23 public static function removeDotSegments(string $path): string
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 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2
57 */
58 public static function resolve(UriInterface $base, UriInterface $rel): UriInterface
59 {
60 if ((string) $rel === '') {
61 // we can simply return the same base URI instance for this same-document reference
62 return $base;
63 }
64
65 if ($rel->getScheme() != '') {
66 return $rel->withPath(self::removeDotSegments($rel->getPath()));
67 }
68
69 if ($rel->getAuthority() != '') {
70 $targetAuthority = $rel->getAuthority();
71 $targetPath = self::removeDotSegments($rel->getPath());
72 $targetQuery = $rel->getQuery();
73 } else {
74 $targetAuthority = $base->getAuthority();
75 if ($rel->getPath() === '') {
76 $targetPath = $base->getPath();
77 $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
78 } else {
79 if ($rel->getPath()[0] === '/') {
80 $targetPath = $rel->getPath();
81 } else {
82 if ($targetAuthority != '' && $base->getPath() === '') {
83 $targetPath = '/'.$rel->getPath();
84 } else {
85 $lastSlashPos = strrpos($base->getPath(), '/');
86 if ($lastSlashPos === false) {
87 $targetPath = $rel->getPath();
88 } else {
89 $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1).$rel->getPath();
90 }
91 }
92 }
93 $targetPath = self::removeDotSegments($targetPath);
94 $targetQuery = $rel->getQuery();
95 }
96 }
97
98 return new Uri(Uri::composeComponents(
99 $base->getScheme(),
100 $targetAuthority,
101 $targetPath,
102 $targetQuery,
103 $rel->getFragment()
104 ));
105 }
106
107 /**
108 * Returns the target URI as a relative reference from the base URI.
109 *
110 * This method is the counterpart to resolve():
111 *
112 * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
113 *
114 * One use-case is to use the current request URI as base URI and then generate relative links in your documents
115 * to reduce the document size or offer self-contained downloadable document archives.
116 *
117 * $base = new Uri('http://example.com/a/b/');
118 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
119 * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
120 * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
121 * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
122 *
123 * This method also accepts a target that is already relative and will try to relativize it further. Only a
124 * relative-path reference will be returned as-is.
125 *
126 * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
127 */
128 public static function relativize(UriInterface $base, UriInterface $target): UriInterface
129 {
130 if ($target->getScheme() !== ''
131 && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
132 ) {
133 return $target;
134 }
135
136 if (Uri::isRelativePathReference($target)) {
137 // As the target is already highly relative we return it as-is. It would be possible to resolve
138 // the target with `$target = self::resolve($base, $target);` and then try make it more relative
139 // by removing a duplicate query. But let's not do that automatically.
140 return $target;
141 }
142
143 if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
144 return $target->withScheme('');
145 }
146
147 // We must remove the path before removing the authority because if the path starts with two slashes, the URI
148 // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
149 // invalid.
150 $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
151
152 if ($base->getPath() !== $target->getPath()) {
153 return $emptyPathUri->withPath(self::getRelativePath($base, $target));
154 }
155
156 if ($base->getQuery() === $target->getQuery()) {
157 // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
158 return $emptyPathUri->withQuery('');
159 }
160
161 // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
162 // inherit the base query component when resolving.
163 if ($target->getQuery() === '') {
164 $segments = explode('/', $target->getPath());
165 /** @var string $lastSegment */
166 $lastSegment = end($segments);
167
168 return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
169 }
170
171 return $emptyPathUri;
172 }
173
174 private static function getRelativePath(UriInterface $base, UriInterface $target): string
175 {
176 $sourceSegments = explode('/', $base->getPath());
177 $targetSegments = explode('/', $target->getPath());
178 array_pop($sourceSegments);
179 $targetLastSegment = array_pop($targetSegments);
180 foreach ($sourceSegments as $i => $segment) {
181 if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
182 unset($sourceSegments[$i], $targetSegments[$i]);
183 } else {
184 break;
185 }
186 }
187 $targetSegments[] = $targetLastSegment;
188 $relativePath = str_repeat('../', count($sourceSegments)).implode('/', $targetSegments);
189
190 // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
191 // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
192 // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
193 if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
194 $relativePath = "./$relativePath";
195 } elseif ('/' === $relativePath[0]) {
196 if ($base->getAuthority() != '' && $base->getPath() === '') {
197 // In this case an extra slash is added by resolve() automatically. So we must not add one here.
198 $relativePath = ".$relativePath";
199 } else {
200 $relativePath = "./$relativePath";
201 }
202 }
203
204 return $relativePath;
205 }
206
207 private function __construct()
208 {
209 // cannot be instantiated
210 }
211 }
212