‪TYPO3CMS  11.5
Uri.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
16 namespace ‪TYPO3\CMS\Core\Http;
17 
18 use Psr\Http\Message\UriInterface;
20 
28 class ‪Uri implements UriInterface
29 {
35  public const ‪SUBDELIMITER_CHARLIST = '!\$&\'\‍(\‍)\*\+,;=';
36 
42  public const ‪UNRESERVED_CHARLIST = 'a-zA-Z0-9_\-\.~';
43 
48  protected ‪$scheme = '';
49 
53  protected ‪$supportedSchemes = [
54  'http' => 80,
55  'https' => 443,
56  ];
57 
62  protected ‪$authority = '';
63 
68  protected ‪$userInfo = '';
69 
74  protected ‪$host = '';
75 
80  protected ‪$port;
81 
86  protected ‪$path = '';
87 
92  protected ‪$query = '';
93 
98  protected ‪$fragment;
99 
104  public function ‪__construct($uri = '')
105  {
106  if (!is_string($uri)) {
107  $argumentType = is_object($uri) ? get_class($uri) : gettype($uri);
108  throw new \InvalidArgumentException('URI passed must be a string, but is of type "' . $argumentType . '"', 1436717320);
109  }
110  if (!empty($uri)) {
111  $this->‪parseUri($uri);
112  }
113  }
114 
120  protected function ‪parseUri($uri)
121  {
122  $uriParts = parse_url($uri);
123 
124  if ($uriParts === false) {
125  throw new \InvalidArgumentException('The parsedUri "' . $uri . '" appears to be malformed', 1436717322);
126  }
127 
128  if (isset($uriParts['scheme'])) {
129  $this->scheme = $this->‪sanitizeScheme($uriParts['scheme']);
130  }
131 
132  if (isset($uriParts['user'])) {
133  $this->userInfo = $uriParts['user'];
134  if (isset($uriParts['pass'])) {
135  $this->userInfo .= ':' . $uriParts['pass'];
136  }
137  }
138 
139  if (isset($uriParts['host'])) {
140  $this->host = $uriParts['host'];
141  }
142 
143  if (isset($uriParts['port'])) {
144  $this->port = (int)$uriParts['port'];
145  }
146 
147  if (isset($uriParts['path'])) {
148  $this->path = $this->‪sanitizePath($uriParts['path']);
149  }
150 
151  if (isset($uriParts['query'])) {
152  $this->query = $this->‪sanitizeQuery($uriParts['query']);
153  }
154 
155  if (isset($uriParts['fragment'])) {
156  $this->fragment = $this->‪sanitizeFragment($uriParts['fragment']);
157  }
158  }
159 
174  public function ‪getScheme()
175  {
176  return ‪$this->scheme;
177  }
178 
197  public function ‪getAuthority()
198  {
199  if (empty($this->host)) {
200  return '';
201  }
202 
204  if (!empty($this->userInfo)) {
205  ‪$authority = $this->userInfo . '@' . ‪$authority;
206  }
207 
208  if ($this->‪isNonStandardPort($this->scheme, $this->host, $this->port)) {
209  ‪$authority .= ':' . ‪$this->port;
210  }
211 
212  return ‪$authority;
213  }
214 
230  public function ‪getUserInfo()
231  {
232  return ‪$this->userInfo;
233  }
234 
246  public function ‪getHost()
247  {
248  return ‪$this->host;
249  }
250 
266  public function ‪getPort()
267  {
268  return $this->‪isNonStandardPort($this->scheme, $this->host, $this->port) ? $this->port : null;
269  }
270 
296  public function ‪getPath()
297  {
298  return ‪$this->path;
299  }
300 
321  public function ‪getQuery()
322  {
323  return ‪$this->query;
324  }
325 
342  public function ‪getFragment()
343  {
344  return ‪$this->fragment;
345  }
346 
363  public function ‪withScheme(‪$scheme)
364  {
366 
367  $clonedObject = clone $this;
368  $clonedObject->scheme = ‪$scheme;
369  return $clonedObject;
370  }
371 
387  public function ‪withUserInfo($user, $password = null)
388  {
389  ‪$userInfo = $user;
390  if (!empty($password)) {
391  ‪$userInfo .= ':' . $password;
392  }
393 
394  $clonedObject = clone $this;
395  $clonedObject->userInfo = ‪$userInfo;
396  return $clonedObject;
397  }
398 
412  public function ‪withHost(‪$host)
413  {
414  $clonedObject = clone $this;
415  $clonedObject->host = ‪$host;
416  return $clonedObject;
417  }
418 
437  public function ‪withPort(‪$port)
438  {
439  if (‪$port !== null) {
441  $argumentType = is_object(‪$port) ? get_class(‪$port) : gettype(‪$port);
442  throw new \InvalidArgumentException('Invalid port "' . $argumentType . '" specified, must be an integer.', 1436717324);
443  }
444 
445  ‪$port = (int)‪$port;
446  if ($port < 1 || $port > 65535) {
447  throw new \InvalidArgumentException('Invalid port "' . ‪$port . '" specified, must be a valid TCP/UDP port.', 1436717326);
448  }
449  }
450 
451  $clonedObject = clone $this;
452  $clonedObject->port = ‪$port;
453  return $clonedObject;
454  }
455 
479  public function ‪withPath(‪$path)
480  {
481  if (!is_string(‪$path)) {
482  throw new \InvalidArgumentException('Invalid path provided. Must be of type string.', 1436717328);
483  }
484 
485  if (str_contains(‪$path, '?')) {
486  throw new \InvalidArgumentException('Invalid path provided. Must not contain a query string.', 1436717330);
487  }
488 
489  if (str_contains(‪$path, '#')) {
490  throw new \InvalidArgumentException('Invalid path provided; must not contain a URI fragment', 1436717332);
491  }
492 
494  $clonedObject = clone $this;
495  $clonedObject->path = ‪$path;
496  return $clonedObject;
497  }
498 
515  public function ‪withQuery(‪$query)
516  {
517  if (!is_string(‪$query)) {
518  throw new \InvalidArgumentException('Query string must be a string.', 1436717334);
519  }
520 
521  if (str_contains(‪$query, '#')) {
522  throw new \InvalidArgumentException('Query string must not include a URI fragment.', 1436717336);
523  }
524 
526  $clonedObject = clone $this;
527  $clonedObject->query = ‪$query;
528  return $clonedObject;
529  }
530 
546  public function ‪withFragment(‪$fragment)
547  {
549  $clonedObject = clone $this;
550  $clonedObject->fragment = ‪$fragment;
551  return $clonedObject;
552  }
553 
577  public function ‪__toString()
578  {
579  $uri = '';
580 
581  if (!empty($this->scheme)) {
582  $uri .= $this->scheme . ':';
583  }
584 
585  ‪$authority = $this->‪getAuthority();
586  if (!empty(‪$authority)) {
587  $uri .= '//' . ‪$authority;
588  }
589 
590  ‪$path = $this->‪getPath();
591  if (‪$path !== '' && !str_starts_with(‪$path, '/')) {
592  ‪$path = '/' . ‪$path;
593  }
594  $uri .= ‪$path;
595 
596  if ($this->query) {
597  $uri .= '?' . ‪$this->query;
598  }
599  if ($this->fragment) {
600  $uri .= '#' . ‪$this->fragment;
601  }
602  return $uri;
603  }
604 
613  protected function ‪isNonStandardPort(‪$scheme, ‪$host, ‪$port)
614  {
615  if (empty(‪$scheme)) {
616  return empty(‪$host) || !empty(‪$port);
617  }
618 
619  if (empty(‪$host) || empty(‪$port)) {
620  return false;
621  }
622 
623  return !isset($this->supportedSchemes[‪$scheme]) || ‪$port !== $this->supportedSchemes[‪$scheme];
624  }
625 
634  protected function ‪sanitizeScheme(‪$scheme)
635  {
636  ‪$scheme = strtolower(‪$scheme);
637  ‪$scheme = preg_replace('#:(//)?$#', '', ‪$scheme);
638 
639  if (empty(‪$scheme)) {
640  return '';
641  }
642 
643  if (!array_key_exists(‪$scheme, $this->supportedSchemes)) {
644  throw new \InvalidArgumentException('Unsupported scheme "' . ‪$scheme . '"; must be any empty string or in the set (' . implode(', ', array_keys($this->supportedSchemes)) . ')', 1436717338);
645  }
646 
647  return ‪$scheme;
648  }
649 
656  protected function ‪sanitizePath(‪$path)
657  {
658  return preg_replace_callback(
659  '/(?:[^' . self::UNRESERVED_CHARLIST . ':@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
660  static function ($matches) {
661  return rawurlencode($matches[0]);
662  },
663  ‪$path
664  );
665  }
666 
675  protected function ‪sanitizeQuery(‪$query)
676  {
677  if (!empty(‪$query) && strpos(‪$query, '?') === 0) {
678  ‪$query = substr(‪$query, 1);
679  }
680 
681  $parts = explode('&', ‪$query);
682  foreach ($parts as $index => $part) {
683  [$key, $value] = $this->‪splitQueryValue($part);
684  if ($value === null) {
685  $parts[$index] = $this->‪sanitizeQueryOrFragment($key);
686  continue;
687  }
688  $parts[$index] = $this->‪sanitizeQueryOrFragment($key) . '=' . $this->‪sanitizeQueryOrFragment($value);
689  }
690 
691  return implode('&', $parts);
692  }
693 
700  protected function ‪splitQueryValue($value)
701  {
702  $data = explode('=', $value, 2);
703  if (count($data) === 1) {
704  $data[] = null;
705  }
706  return $data;
707  }
708 
715  protected function ‪sanitizeFragment(‪$fragment)
716  {
717  if (‪$fragment === null) {
718  ‪$fragment = '';
719  }
720 
721  if (!empty(‪$fragment) && strpos(‪$fragment, '#') === 0) {
722  ‪$fragment = substr(‪$fragment, 1);
723  }
724 
726  }
727 
734  protected function ‪sanitizeQueryOrFragment($value)
735  {
736  return preg_replace_callback(
737  '/(?:[^' . self::UNRESERVED_CHARLIST . self::SUBDELIMITER_CHARLIST . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
738  static function ($matches) {
739  return rawurlencode($matches[0]);
740  },
741  $value
742  );
743  }
744 }
‪TYPO3\CMS\Core\Http\Uri\withPath
‪static withPath($path)
Definition: Uri.php:470
‪TYPO3\CMS\Core\Http\Uri\parseUri
‪parseUri($uri)
Definition: Uri.php:111
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Core\Http\Uri\$fragment
‪string $fragment
Definition: Uri.php:89
‪TYPO3\CMS\Core\Http\Uri\splitQueryValue
‪array splitQueryValue($value)
Definition: Uri.php:691
‪TYPO3\CMS\Core\Http\Uri\$host
‪string $host
Definition: Uri.php:69
‪TYPO3\CMS\Core\Http\Uri\getPath
‪string getPath()
Definition: Uri.php:287
‪TYPO3\CMS\Core\Http\Uri\sanitizeFragment
‪string sanitizeFragment($fragment)
Definition: Uri.php:706
‪TYPO3\CMS\Core\Http\Uri\__construct
‪__construct($uri='')
Definition: Uri.php:95
‪TYPO3\CMS\Core\Http\Uri\getPort
‪int null getPort()
Definition: Uri.php:257
‪TYPO3\CMS\Core\Http\Uri\sanitizeQueryOrFragment
‪string sanitizeQueryOrFragment($value)
Definition: Uri.php:725
‪TYPO3\CMS\Core\Http\Uri\getUserInfo
‪string getUserInfo()
Definition: Uri.php:221
‪TYPO3\CMS\Core\Http\Uri\$path
‪string $path
Definition: Uri.php:79
‪TYPO3\CMS\Core\Http\Uri\getAuthority
‪string getAuthority()
Definition: Uri.php:188
‪TYPO3\CMS\Core\Http\Uri\$port
‪int null $port
Definition: Uri.php:74
‪TYPO3\CMS\Core\Http\Uri\$query
‪string $query
Definition: Uri.php:84
‪TYPO3\CMS\Core\Http\Uri\sanitizePath
‪string sanitizePath($path)
Definition: Uri.php:647
‪TYPO3\CMS\Core\Http\Uri\getQuery
‪string getQuery()
Definition: Uri.php:312
‪TYPO3\CMS\Core\Http\Uri\withPort
‪static withPort($port)
Definition: Uri.php:428
‪TYPO3\CMS\Core\Http\Uri
Definition: Uri.php:29
‪TYPO3\CMS\Core\Http\Uri\SUBDELIMITER_CHARLIST
‪const SUBDELIMITER_CHARLIST
Definition: Uri.php:35
‪TYPO3\CMS\Core\Http\Uri\$supportedSchemes
‪int[] $supportedSchemes
Definition: Uri.php:51
‪TYPO3\CMS\Core\Http\Uri\withFragment
‪static withFragment($fragment)
Definition: Uri.php:537
‪TYPO3\CMS\Core\Http\Uri\withUserInfo
‪static withUserInfo($user, $password=null)
Definition: Uri.php:378
‪TYPO3\CMS\Core\Http\Uri\$authority
‪string $authority
Definition: Uri.php:59
‪TYPO3\CMS\Core\Http\Uri\withHost
‪static withHost($host)
Definition: Uri.php:403
‪TYPO3\CMS\Core\Http\Uri\$userInfo
‪string $userInfo
Definition: Uri.php:64
‪TYPO3\CMS\Core\Http\Uri\isNonStandardPort
‪bool isNonStandardPort($scheme, $host, $port)
Definition: Uri.php:604
‪TYPO3\CMS\Core\Http\Uri\withQuery
‪static withQuery($query)
Definition: Uri.php:506
‪TYPO3\CMS\Core\Http\Uri\getFragment
‪string getFragment()
Definition: Uri.php:333
‪TYPO3\CMS\Core\Http\Uri\UNRESERVED_CHARLIST
‪const UNRESERVED_CHARLIST
Definition: Uri.php:42
‪TYPO3\CMS\Core\Http\Uri\getHost
‪string getHost()
Definition: Uri.php:237
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Http\Uri\getScheme
‪string getScheme()
Definition: Uri.php:165
‪TYPO3\CMS\Core\Http\Uri\__toString
‪string __toString()
Definition: Uri.php:568
‪TYPO3\CMS\Core\Http\Uri\withScheme
‪static withScheme($scheme)
Definition: Uri.php:354
‪TYPO3\CMS\Core\Http\Uri\sanitizeQuery
‪string sanitizeQuery($query)
Definition: Uri.php:666
‪TYPO3\CMS\Core\Http\Uri\$scheme
‪string $scheme
Definition: Uri.php:47
‪TYPO3\CMS\Core\Http
Definition: AbstractApplication.php:18
‪TYPO3\CMS\Core\Http\Uri\sanitizeScheme
‪string sanitizeScheme($scheme)
Definition: Uri.php:625