PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / GuzzleHttp / Psr7 / UriResolver.php

UriResolver.php in Media Cloud Sync 1.3.11, at includes/sdk/s3/GuzzleHttp/Psr7/UriResolver.php

181 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare (strict_types=1);
4 namespace Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
5
6 use Dudlewebs\WPMCS\s3\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(UriInterface $base, UriInterface $rel) : 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 Uri(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(UriInterface $base, UriInterface $target) : UriInterface
112 {
113 if ($target->getScheme() !== '' && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')) {
114 return $target;
115 }
116 if (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(UriInterface $base, 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