PluginProbe
Media Cloud Sync / 1.0.3
Media Cloud Sync v1.0.3
1.4.2 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 All 36 releases
media-cloud-sync / includes / sdk / s3 / GuzzleHttp / Psr7 / Uri.php

Uri.php in Media Cloud Sync 1.0.3, at includes/sdk/s3/GuzzleHttp/Psr7/Uri.php

639 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
4
5 use Dudlewebs\WPMCS\s3\Psr\Http\Message\UriInterface;
6 /**
7 * PSR-7 URI implementation.
8 *
9 * @author Michael Dowling
10 * @author Tobias Schultze
11 * @author Matthew Weier O'Phinney
12 */
13 class Uri implements UriInterface
14 {
15 /**
16 * Absolute http and https URIs require a host per RFC 7230 Section 2.7
17 * but in generic URIs the host can be empty. So for http(s) URIs
18 * we apply this default host when no host is given yet to form a
19 * valid URI.
20 */
21 const HTTP_DEFAULT_HOST = 'localhost';
22 private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21, 'gopher' => 70, 'nntp' => 119, 'news' => 119, 'telnet' => 23, 'tn3270' => 23, 'imap' => 143, 'pop' => 110, 'ldap' => 389];
23 private static $charUnreserved = 'a-zA-Z0-9_\\-\\.~';
24 private static $charSubDelims = '!\\$&\'\\(\\)\\*\\+,;=';
25 private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
26 /** @var string Uri scheme. */
27 private $scheme = '';
28 /** @var string Uri user info. */
29 private $userInfo = '';
30 /** @var string Uri host. */
31 private $host = '';
32 /** @var int|null Uri port. */
33 private $port;
34 /** @var string Uri path. */
35 private $path = '';
36 /** @var string Uri query string. */
37 private $query = '';
38 /** @var string Uri fragment. */
39 private $fragment = '';
40 /**
41 * @param string $uri URI to parse
42 */
43 public function __construct($uri = '')
44 {
45 // weak type check to also accept null until we can add scalar type hints
46 if ($uri != '') {
47 $parts = self::parse($uri);
48 if ($parts === \false) {
49 throw new \InvalidArgumentException("Unable to parse URI: {$uri}");
50 }
51 $this->applyParts($parts);
52 }
53 }
54 /**
55 * UTF-8 aware \parse_url() replacement.
56 *
57 * The internal function produces broken output for non ASCII domain names
58 * (IDN) when used with locales other than "C".
59 *
60 * On the other hand, cURL understands IDN correctly only when UTF-8 locale
61 * is configured ("C.UTF-8", "en_US.UTF-8", etc.).
62 *
63 * @see https://bugs.php.net/bug.php?id=52923
64 * @see https://www.php.net/manual/en/function.parse-url.php#114817
65 * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
66 *
67 * @param string $url
68 *
69 * @return array|false
70 */
71 private static function parse($url)
72 {
73 // If IPv6
74 $prefix = '';
75 if (\preg_match('%^(.*://\\[[0-9:a-f]+\\])(.*?)$%', $url, $matches)) {
76 $prefix = $matches[1];
77 $url = $matches[2];
78 }
79 $encodedUrl = \preg_replace_callback('%[^:/@?&=#]+%usD', static function ($matches) {
80 return \urlencode($matches[0]);
81 }, $url);
82 $result = \parse_url($prefix . $encodedUrl);
83 if ($result === \false) {
84 return \false;
85 }
86 return \array_map('urldecode', $result);
87 }
88 public function __toString()
89 {
90 return self::composeComponents($this->scheme, $this->getAuthority(), $this->path, $this->query, $this->fragment);
91 }
92 /**
93 * Composes a URI reference string from its various components.
94 *
95 * Usually this method does not need to be called manually but instead is used indirectly via
96 * `Psr\Http\Message\UriInterface::__toString`.
97 *
98 * PSR-7 UriInterface treats an empty component the same as a missing component as
99 * getQuery(), getFragment() etc. always return a string. This explains the slight
100 * difference to RFC 3986 Section 5.3.
101 *
102 * Another adjustment is that the authority separator is added even when the authority is missing/empty
103 * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
104 * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
105 * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
106 * that format).
107 *
108 * @param string $scheme
109 * @param string $authority
110 * @param string $path
111 * @param string $query
112 * @param string $fragment
113 *
114 * @return string
115 *
116 * @link https://tools.ietf.org/html/rfc3986#section-5.3
117 */
118 public static function composeComponents($scheme, $authority, $path, $query, $fragment)
119 {
120 $uri = '';
121 // weak type checks to also accept null until we can add scalar type hints
122 if ($scheme != '') {
123 $uri .= $scheme . ':';
124 }
125 if ($authority != '' || $scheme === 'file') {
126 $uri .= '//' . $authority;
127 }
128 $uri .= $path;
129 if ($query != '') {
130 $uri .= '?' . $query;
131 }
132 if ($fragment != '') {
133 $uri .= '#' . $fragment;
134 }
135 return $uri;
136 }
137 /**
138 * Whether the URI has the default port of the current scheme.
139 *
140 * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
141 * independently of the implementation.
142 *
143 * @param UriInterface $uri
144 *
145 * @return bool
146 */
147 public static function isDefaultPort(UriInterface $uri)
148 {
149 return $uri->getPort() === null || isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()];
150 }
151 /**
152 * Whether the URI is absolute, i.e. it has a scheme.
153 *
154 * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
155 * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
156 * to another URI, the base URI. Relative references can be divided into several forms:
157 * - network-path references, e.g. '//example.com/path'
158 * - absolute-path references, e.g. '/path'
159 * - relative-path references, e.g. 'subpath'
160 *
161 * @param UriInterface $uri
162 *
163 * @return bool
164 *
165 * @see Uri::isNetworkPathReference
166 * @see Uri::isAbsolutePathReference
167 * @see Uri::isRelativePathReference
168 * @link https://tools.ietf.org/html/rfc3986#section-4
169 */
170 public static function isAbsolute(UriInterface $uri)
171 {
172 return $uri->getScheme() !== '';
173 }
174 /**
175 * Whether the URI is a network-path reference.
176 *
177 * A relative reference that begins with two slash characters is termed an network-path reference.
178 *
179 * @param UriInterface $uri
180 *
181 * @return bool
182 *
183 * @link https://tools.ietf.org/html/rfc3986#section-4.2
184 */
185 public static function isNetworkPathReference(UriInterface $uri)
186 {
187 return $uri->getScheme() === '' && $uri->getAuthority() !== '';
188 }
189 /**
190 * Whether the URI is a absolute-path reference.
191 *
192 * A relative reference that begins with a single slash character is termed an absolute-path reference.
193 *
194 * @param UriInterface $uri
195 *
196 * @return bool
197 *
198 * @link https://tools.ietf.org/html/rfc3986#section-4.2
199 */
200 public static function isAbsolutePathReference(UriInterface $uri)
201 {
202 return $uri->getScheme() === '' && $uri->getAuthority() === '' && isset($uri->getPath()[0]) && $uri->getPath()[0] === '/';
203 }
204 /**
205 * Whether the URI is a relative-path reference.
206 *
207 * A relative reference that does not begin with a slash character is termed a relative-path reference.
208 *
209 * @param UriInterface $uri
210 *
211 * @return bool
212 *
213 * @link https://tools.ietf.org/html/rfc3986#section-4.2
214 */
215 public static function isRelativePathReference(UriInterface $uri)
216 {
217 return $uri->getScheme() === '' && $uri->getAuthority() === '' && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
218 }
219 /**
220 * Whether the URI is a same-document reference.
221 *
222 * A same-document reference refers to a URI that is, aside from its fragment
223 * component, identical to the base URI. When no base URI is given, only an empty
224 * URI reference (apart from its fragment) is considered a same-document reference.
225 *
226 * @param UriInterface $uri The URI to check
227 * @param UriInterface|null $base An optional base URI to compare against
228 *
229 * @return bool
230 *
231 * @link https://tools.ietf.org/html/rfc3986#section-4.4
232 */
233 public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
234 {
235 if ($base !== null) {
236 $uri = UriResolver::resolve($base, $uri);
237 return $uri->getScheme() === $base->getScheme() && $uri->getAuthority() === $base->getAuthority() && $uri->getPath() === $base->getPath() && $uri->getQuery() === $base->getQuery();
238 }
239 return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
240 }
241 /**
242 * Removes dot segments from a path and returns the new path.
243 *
244 * @param string $path
245 *
246 * @return string
247 *
248 * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
249 * @see UriResolver::removeDotSegments
250 */
251 public static function removeDotSegments($path)
252 {
253 return UriResolver::removeDotSegments($path);
254 }
255 /**
256 * Converts the relative URI into a new URI that is resolved against the base URI.
257 *
258 * @param UriInterface $base Base URI
259 * @param string|UriInterface $rel Relative URI
260 *
261 * @return UriInterface
262 *
263 * @deprecated since version 1.4. Use UriResolver::resolve instead.
264 * @see UriResolver::resolve
265 */
266 public static function resolve(UriInterface $base, $rel)
267 {
268 if (!$rel instanceof UriInterface) {
269 $rel = new self($rel);
270 }
271 return UriResolver::resolve($base, $rel);
272 }
273 /**
274 * Creates a new URI with a specific query string value removed.
275 *
276 * Any existing query string values that exactly match the provided key are
277 * removed.
278 *
279 * @param UriInterface $uri URI to use as a base.
280 * @param string $key Query string key to remove.
281 *
282 * @return UriInterface
283 */
284 public static function withoutQueryValue(UriInterface $uri, $key)
285 {
286 $result = self::getFilteredQueryString($uri, [$key]);
287 return $uri->withQuery(\implode('&', $result));
288 }
289 /**
290 * Creates a new URI with a specific query string value.
291 *
292 * Any existing query string values that exactly match the provided key are
293 * removed and replaced with the given key value pair.
294 *
295 * A value of null will set the query string key without a value, e.g. "key"
296 * instead of "key=value".
297 *
298 * @param UriInterface $uri URI to use as a base.
299 * @param string $key Key to set.
300 * @param string|null $value Value to set
301 *
302 * @return UriInterface
303 */
304 public static function withQueryValue(UriInterface $uri, $key, $value)
305 {
306 $result = self::getFilteredQueryString($uri, [$key]);
307 $result[] = self::generateQueryString($key, $value);
308 return $uri->withQuery(\implode('&', $result));
309 }
310 /**
311 * Creates a new URI with multiple specific query string values.
312 *
313 * It has the same behavior as withQueryValue() but for an associative array of key => value.
314 *
315 * @param UriInterface $uri URI to use as a base.
316 * @param array $keyValueArray Associative array of key and values
317 *
318 * @return UriInterface
319 */
320 public static function withQueryValues(UriInterface $uri, array $keyValueArray)
321 {
322 $result = self::getFilteredQueryString($uri, \array_keys($keyValueArray));
323 foreach ($keyValueArray as $key => $value) {
324 $result[] = self::generateQueryString($key, $value);
325 }
326 return $uri->withQuery(\implode('&', $result));
327 }
328 /**
329 * Creates a URI from a hash of `parse_url` components.
330 *
331 * @param array $parts
332 *
333 * @return UriInterface
334 *
335 * @link http://php.net/manual/en/function.parse-url.php
336 *
337 * @throws \InvalidArgumentException If the components do not form a valid URI.
338 */
339 public static function fromParts(array $parts)
340 {
341 $uri = new self();
342 $uri->applyParts($parts);
343 $uri->validateState();
344 return $uri;
345 }
346 public function getScheme()
347 {
348 return $this->scheme;
349 }
350 public function getAuthority()
351 {
352 $authority = $this->host;
353 if ($this->userInfo !== '') {
354 $authority = $this->userInfo . '@' . $authority;
355 }
356 if ($this->port !== null) {
357 $authority .= ':' . $this->port;
358 }
359 return $authority;
360 }
361 public function getUserInfo()
362 {
363 return $this->userInfo;
364 }
365 public function getHost()
366 {
367 return $this->host;
368 }
369 public function getPort()
370 {
371 return $this->port;
372 }
373 public function getPath()
374 {
375 return $this->path;
376 }
377 public function getQuery()
378 {
379 return $this->query;
380 }
381 public function getFragment()
382 {
383 return $this->fragment;
384 }
385 public function withScheme($scheme)
386 {
387 $scheme = $this->filterScheme($scheme);
388 if ($this->scheme === $scheme) {
389 return $this;
390 }
391 $new = clone $this;
392 $new->scheme = $scheme;
393 $new->removeDefaultPort();
394 $new->validateState();
395 return $new;
396 }
397 public function withUserInfo($user, $password = null)
398 {
399 $info = $this->filterUserInfoComponent($user);
400 if ($password !== null) {
401 $info .= ':' . $this->filterUserInfoComponent($password);
402 }
403 if ($this->userInfo === $info) {
404 return $this;
405 }
406 $new = clone $this;
407 $new->userInfo = $info;
408 $new->validateState();
409 return $new;
410 }
411 public function withHost($host)
412 {
413 $host = $this->filterHost($host);
414 if ($this->host === $host) {
415 return $this;
416 }
417 $new = clone $this;
418 $new->host = $host;
419 $new->validateState();
420 return $new;
421 }
422 public function withPort($port)
423 {
424 $port = $this->filterPort($port);
425 if ($this->port === $port) {
426 return $this;
427 }
428 $new = clone $this;
429 $new->port = $port;
430 $new->removeDefaultPort();
431 $new->validateState();
432 return $new;
433 }
434 public function withPath($path)
435 {
436 $path = $this->filterPath($path);
437 if ($this->path === $path) {
438 return $this;
439 }
440 $new = clone $this;
441 $new->path = $path;
442 $new->validateState();
443 return $new;
444 }
445 public function withQuery($query)
446 {
447 $query = $this->filterQueryAndFragment($query);
448 if ($this->query === $query) {
449 return $this;
450 }
451 $new = clone $this;
452 $new->query = $query;
453 return $new;
454 }
455 public function withFragment($fragment)
456 {
457 $fragment = $this->filterQueryAndFragment($fragment);
458 if ($this->fragment === $fragment) {
459 return $this;
460 }
461 $new = clone $this;
462 $new->fragment = $fragment;
463 return $new;
464 }
465 /**
466 * Apply parse_url parts to a URI.
467 *
468 * @param array $parts Array of parse_url parts to apply.
469 */
470 private function applyParts(array $parts)
471 {
472 $this->scheme = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : '';
473 $this->userInfo = isset($parts['user']) ? $this->filterUserInfoComponent($parts['user']) : '';
474 $this->host = isset($parts['host']) ? $this->filterHost($parts['host']) : '';
475 $this->port = isset($parts['port']) ? $this->filterPort($parts['port']) : null;
476 $this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
477 $this->query = isset($parts['query']) ? $this->filterQueryAndFragment($parts['query']) : '';
478 $this->fragment = isset($parts['fragment']) ? $this->filterQueryAndFragment($parts['fragment']) : '';
479 if (isset($parts['pass'])) {
480 $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
481 }
482 $this->removeDefaultPort();
483 }
484 /**
485 * @param string $scheme
486 *
487 * @return string
488 *
489 * @throws \InvalidArgumentException If the scheme is invalid.
490 */
491 private function filterScheme($scheme)
492 {
493 if (!\is_string($scheme)) {
494 throw new \InvalidArgumentException('Scheme must be a string');
495 }
496 return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
497 }
498 /**
499 * @param string $component
500 *
501 * @return string
502 *
503 * @throws \InvalidArgumentException If the user info is invalid.
504 */
505 private function filterUserInfoComponent($component)
506 {
507 if (!\is_string($component)) {
508 throw new \InvalidArgumentException('User info must be a string');
509 }
510 return \preg_replace_callback('/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $component);
511 }
512 /**
513 * @param string $host
514 *
515 * @return string
516 *
517 * @throws \InvalidArgumentException If the host is invalid.
518 */
519 private function filterHost($host)
520 {
521 if (!\is_string($host)) {
522 throw new \InvalidArgumentException('Host must be a string');
523 }
524 return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
525 }
526 /**
527 * @param int|null $port
528 *
529 * @return int|null
530 *
531 * @throws \InvalidArgumentException If the port is invalid.
532 */
533 private function filterPort($port)
534 {
535 if ($port === null) {
536 return null;
537 }
538 $port = (int) $port;
539 if (0 > $port || 0xffff < $port) {
540 throw new \InvalidArgumentException(\sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
541 }
542 return $port;
543 }
544 /**
545 * @param UriInterface $uri
546 * @param array $keys
547 *
548 * @return array
549 */
550 private static function getFilteredQueryString(UriInterface $uri, array $keys)
551 {
552 $current = $uri->getQuery();
553 if ($current === '') {
554 return [];
555 }
556 $decodedKeys = \array_map('rawurldecode', $keys);
557 return \array_filter(\explode('&', $current), function ($part) use($decodedKeys) {
558 return !\in_array(\rawurldecode(\explode('=', $part)[0]), $decodedKeys, \true);
559 });
560 }
561 /**
562 * @param string $key
563 * @param string|null $value
564 *
565 * @return string
566 */
567 private static function generateQueryString($key, $value)
568 {
569 // Query string separators ("=", "&") within the key or value need to be encoded
570 // (while preventing double-encoding) before setting the query string. All other
571 // chars that need percent-encoding will be encoded by withQuery().
572 $queryString = \strtr($key, self::$replaceQuery);
573 if ($value !== null) {
574 $queryString .= '=' . \strtr($value, self::$replaceQuery);
575 }
576 return $queryString;
577 }
578 private function removeDefaultPort()
579 {
580 if ($this->port !== null && self::isDefaultPort($this)) {
581 $this->port = null;
582 }
583 }
584 /**
585 * Filters the path of a URI
586 *
587 * @param string $path
588 *
589 * @return string
590 *
591 * @throws \InvalidArgumentException If the path is invalid.
592 */
593 private function filterPath($path)
594 {
595 if (!\is_string($path)) {
596 throw new \InvalidArgumentException('Path must be a string');
597 }
598 return \preg_replace_callback('/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $path);
599 }
600 /**
601 * Filters the query string or fragment of a URI.
602 *
603 * @param string $str
604 *
605 * @return string
606 *
607 * @throws \InvalidArgumentException If the query or fragment is invalid.
608 */
609 private function filterQueryAndFragment($str)
610 {
611 if (!\is_string($str)) {
612 throw new \InvalidArgumentException('Query and fragment must be a string');
613 }
614 return \preg_replace_callback('/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\\/\\?]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $str);
615 }
616 private function rawurlencodeMatchZero(array $match)
617 {
618 return \rawurlencode($match[0]);
619 }
620 private function validateState()
621 {
622 if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
623 $this->host = self::HTTP_DEFAULT_HOST;
624 }
625 if ($this->getAuthority() === '') {
626 if (0 === \strpos($this->path, '//')) {
627 throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
628 }
629 if ($this->scheme === '' && \false !== \strpos(\explode('/', $this->path, 2)[0], ':')) {
630 throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
631 }
632 } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
633 @\trigger_error('The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' . 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.', \E_USER_DEPRECATED);
634 $this->path = '/' . $this->path;
635 //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
636 }
637 }
638 }
639