‪TYPO3CMS  9.5
Uri.php
Go to the documentation of this file.
1 <?php
2 namespace ‪TYPO3\CMS\Core\Http;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Psr\Http\Message\UriInterface;
18 
26 class ‪Uri implements UriInterface
27 {
33  const ‪SUBDELIMITER_CHARLIST = '!\$&\'\‍(\‍)\*\+,;=';
34 
40  const ‪UNRESERVED_CHARLIST = 'a-zA-Z0-9_\-\.~';
41 
46  protected ‪$scheme;
47 
51  protected ‪$supportedSchemes = [
52  'http' => 80,
53  'https' => 443
54  ];
55 
60  protected ‪$authority = '';
61 
66  protected ‪$userInfo = '';
67 
72  protected ‪$host = '';
73 
78  protected ‪$port;
79 
84  protected ‪$path = '';
85 
90  protected ‪$query = '';
91 
96  protected ‪$fragment;
97 
102  public function ‪__construct($uri = '')
103  {
104  if (!is_string($uri)) {
105  $argumentType = is_object($uri) ? get_class($uri) : gettype($uri);
106  throw new \InvalidArgumentException('URI passed must be a string, but is of type "' . $argumentType . '"', 1436717320);
107  }
108  if (!empty($uri)) {
109  $this->‪parseUri($uri);
110  }
111  }
112 
118  protected function ‪parseUri($uri)
119  {
120  $uriParts = parse_url($uri);
121 
122  if ($uriParts === false) {
123  throw new \InvalidArgumentException('The parsedUri string appears to be malformed', 1436717322);
124  }
125 
126  if (isset($uriParts['scheme'])) {
127  $this->scheme = $this->‪sanitizeScheme($uriParts['scheme']);
128  }
129 
130  if (isset($uriParts['user'])) {
131  $this->userInfo = $uriParts['user'];
132  if (isset($uriParts['pass'])) {
133  $this->userInfo .= ':' . $uriParts['pass'];
134  }
135  }
136 
137  if (isset($uriParts['host'])) {
138  $this->host = $uriParts['host'];
139  }
140 
141  if (isset($uriParts['port'])) {
142  $this->port = (int)$uriParts['port'];
143  }
144 
145  if (isset($uriParts['path'])) {
146  $this->path = $this->‪sanitizePath($uriParts['path']);
147  }
148 
149  if (isset($uriParts['query'])) {
150  $this->query = $this->‪sanitizeQuery($uriParts['query']);
151  }
152 
153  if (isset($uriParts['fragment'])) {
154  $this->fragment = $this->‪sanitizeFragment($uriParts['fragment']);
155  }
156  }
157 
172  public function ‪getScheme()
173  {
174  return ‪$this->scheme;
175  }
176 
195  public function ‪getAuthority()
196  {
197  if (empty($this->host)) {
198  return '';
199  }
200 
202  if (!empty($this->userInfo)) {
203  ‪$authority = $this->userInfo . '@' . ‪$authority;
204  }
205 
206  if ($this->‪isNonStandardPort($this->scheme, $this->host, $this->port)) {
207  ‪$authority .= ':' . ‪$this->port;
208  }
209 
210  return ‪$authority;
211  }
212 
228  public function ‪getUserInfo()
229  {
230  return ‪$this->userInfo;
231  }
232 
244  public function ‪getHost()
245  {
246  return ‪$this->host;
247  }
248 
264  public function ‪getPort()
265  {
266  return $this->‪isNonStandardPort($this->scheme, $this->host, $this->port) ? $this->port : null;
267  }
268 
294  public function ‪getPath()
295  {
296  return ‪$this->path;
297  }
298 
319  public function ‪getQuery()
320  {
321  return ‪$this->query;
322  }
323 
340  public function ‪getFragment()
341  {
342  return ‪$this->fragment;
343  }
344 
361  public function ‪withScheme(‪$scheme)
362  {
364 
365  $clonedObject = clone $this;
366  $clonedObject->scheme = ‪$scheme;
367  return $clonedObject;
368  }
369 
385  public function ‪withUserInfo($user, $password = null)
386  {
387  ‪$userInfo = $user;
388  if (!empty($password)) {
389  ‪$userInfo .= ':' . $password;
390  }
391 
392  $clonedObject = clone $this;
393  $clonedObject->userInfo = ‪$userInfo;
394  return $clonedObject;
395  }
396 
410  public function ‪withHost(‪$host)
411  {
412  $clonedObject = clone $this;
413  $clonedObject->host = ‪$host;
414  return $clonedObject;
415  }
416 
435  public function ‪withPort(‪$port)
436  {
437  if (‪$port !== null) {
438  if (\‪TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger(‪$port) === false) {
439  $argumentType = is_object(‪$port) ? get_class(‪$port) : gettype(‪$port);
440  throw new \InvalidArgumentException('Invalid port "' . $argumentType . '" specified, must be an integer.', 1436717324);
441  }
442 
443  ‪$port = (int)‪$port;
444  if ($port < 1 || $port > 65535) {
445  throw new \InvalidArgumentException('Invalid port "' . ‪$port . '" specified, must be a valid TCP/UDP port.', 1436717326);
446  }
447  }
448 
449  $clonedObject = clone $this;
450  $clonedObject->port = ‪$port;
451  return $clonedObject;
452  }
453 
477  public function ‪withPath(‪$path)
478  {
479  if (!is_string(‪$path)) {
480  throw new \InvalidArgumentException('Invalid path provided. Must be of type string.', 1436717328);
481  }
482 
483  if (strpos(‪$path, '?') !== false) {
484  throw new \InvalidArgumentException('Invalid path provided. Must not contain a query string.', 1436717330);
485  }
486 
487  if (strpos(‪$path, '#') !== false) {
488  throw new \InvalidArgumentException('Invalid path provided; must not contain a URI fragment', 1436717332);
489  }
490 
492  $clonedObject = clone $this;
493  $clonedObject->path = ‪$path;
494  return $clonedObject;
495  }
496 
513  public function ‪withQuery(‪$query)
514  {
515  if (!is_string(‪$query)) {
516  throw new \InvalidArgumentException('Query string must be a string.', 1436717334);
517  }
518 
519  if (strpos(‪$query, '#') !== false) {
520  throw new \InvalidArgumentException('Query string must not include a URI fragment.', 1436717336);
521  }
522 
524  $clonedObject = clone $this;
525  $clonedObject->query = ‪$query;
526  return $clonedObject;
527  }
528 
544  public function ‪withFragment(‪$fragment)
545  {
547  $clonedObject = clone $this;
548  $clonedObject->fragment = ‪$fragment;
549  return $clonedObject;
550  }
551 
575  public function ‪__toString()
576  {
577  $uri = '';
578 
579  if (!empty($this->scheme)) {
580  $uri .= $this->scheme . ':';
581  }
582 
583  ‪$authority = $this->‪getAuthority();
584  if (!empty(‪$authority)) {
585  $uri .= '//' . ‪$authority;
586  }
587 
588  ‪$path = $this->‪getPath();
589  if (!empty(‪$path)) {
590  $uri .= '/' . ltrim(‪$path, '/');
591  }
592 
593  if ($this->query) {
594  $uri .= '?' . ‪$this->query;
595  }
596  if ($this->fragment) {
597  $uri .= '#' . ‪$this->fragment;
598  }
599  return $uri;
600  }
601 
610  protected function ‪isNonStandardPort(‪$scheme, ‪$host, ‪$port)
611  {
612  if (empty(‪$scheme)) {
613  return empty(‪$host) || !empty(‪$port);
614  }
615 
616  if (empty(‪$host) || empty(‪$port)) {
617  return false;
618  }
619 
620  return !isset($this->supportedSchemes[‪$scheme]) || ‪$port !== $this->supportedSchemes[‪$scheme];
621  }
622 
631  protected function ‪sanitizeScheme(‪$scheme)
632  {
633  ‪$scheme = strtolower(‪$scheme);
634  ‪$scheme = preg_replace('#:(//)?$#', '', ‪$scheme);
635 
636  if (empty(‪$scheme)) {
637  return '';
638  }
639 
640  if (!array_key_exists(‪$scheme, $this->supportedSchemes)) {
641  throw new \InvalidArgumentException('Unsupported scheme "' . ‪$scheme . '"; must be any empty string or in the set (' . implode(', ', array_keys($this->supportedSchemes)) . ')', 1436717338);
642  }
643 
644  return ‪$scheme;
645  }
646 
653  protected function ‪sanitizePath(‪$path)
654  {
655  return preg_replace_callback(
656  '/(?:[^' . self::UNRESERVED_CHARLIST . ':@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
657  function ($matches) {
658  return rawurlencode($matches[0]);
659  },
660  ‪$path
661  );
662  }
663 
672  protected function ‪sanitizeQuery(‪$query)
673  {
674  if (!empty(‪$query) && strpos(‪$query, '?') === 0) {
675  ‪$query = substr(‪$query, 1);
676  }
677 
678  $parts = explode('&', ‪$query);
679  foreach ($parts as $index => $part) {
680  list($key, $value) = $this->‪splitQueryValue($part);
681  if ($value === null) {
682  $parts[$index] = $this->‪sanitizeQueryOrFragment($key);
683  continue;
684  }
685  $parts[$index] = $this->‪sanitizeQueryOrFragment($key) . '=' . $this->‪sanitizeQueryOrFragment($value);
686  }
687 
688  return implode('&', $parts);
689  }
690 
697  protected function ‪splitQueryValue($value)
698  {
699  $data = explode('=', $value, 2);
700  if (count($data) === 1) {
701  $data[] = null;
702  }
703  return $data;
704  }
705 
712  protected function ‪sanitizeFragment(‪$fragment)
713  {
714  if (‪$fragment === null) {
715  ‪$fragment = '';
716  }
717 
718  if (!empty(‪$fragment) && strpos(‪$fragment, '#') === 0) {
719  ‪$fragment = substr(‪$fragment, 1);
720  }
721 
723  }
724 
731  protected function ‪sanitizeQueryOrFragment($value)
732  {
733  return preg_replace_callback(
734  '/(?:[^' . self::UNRESERVED_CHARLIST . self::SUBDELIMITER_CHARLIST . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
735  function ($matches) {
736  return rawurlencode($matches[0]);
737  },
738  $value
739  );
740  }
741 }
‪TYPO3\CMS\Core\Http\Uri\withPath
‪static withPath($path)
Definition: Uri.php:468
‪TYPO3\CMS\Core\Http\Uri\parseUri
‪parseUri($uri)
Definition: Uri.php:109
‪TYPO3\CMS\Core\Http\Uri\$fragment
‪string $fragment
Definition: Uri.php:87
‪TYPO3\CMS\Core\Http\Uri\splitQueryValue
‪array splitQueryValue($value)
Definition: Uri.php:688
‪TYPO3\CMS\Core\Http\Uri\$host
‪string $host
Definition: Uri.php:67
‪TYPO3
‪TYPO3\CMS\Core\Http\Uri\getPath
‪string getPath()
Definition: Uri.php:285
‪TYPO3\CMS\Core\Http\Uri\sanitizeFragment
‪string sanitizeFragment($fragment)
Definition: Uri.php:703
‪TYPO3\CMS\Core\Http\Uri\__construct
‪__construct($uri='')
Definition: Uri.php:93
‪TYPO3\CMS\Core\Http\Uri\getPort
‪int null getPort()
Definition: Uri.php:255
‪TYPO3\CMS\Core\Http\Uri\sanitizeQueryOrFragment
‪string sanitizeQueryOrFragment($value)
Definition: Uri.php:722
‪TYPO3\CMS\Core\Http\Uri\getUserInfo
‪string getUserInfo()
Definition: Uri.php:219
‪TYPO3\CMS\Core\Http\Uri\$path
‪string $path
Definition: Uri.php:77
‪TYPO3\CMS\Core\Http\Uri\getAuthority
‪string getAuthority()
Definition: Uri.php:186
‪TYPO3\CMS\Core\Http\Uri\$port
‪int null $port
Definition: Uri.php:72
‪TYPO3\CMS\Core\Http\Uri\$query
‪string $query
Definition: Uri.php:82
‪TYPO3\CMS\Core\Http\Uri\sanitizePath
‪string sanitizePath($path)
Definition: Uri.php:644
‪TYPO3\CMS\Core\Http\Uri\getQuery
‪string getQuery()
Definition: Uri.php:310
‪TYPO3\CMS\Core\Http\Uri\withPort
‪static withPort($port)
Definition: Uri.php:426
‪TYPO3\CMS\Core\Http\Uri
Definition: Uri.php:27
‪TYPO3\CMS\Core\Http\Uri\SUBDELIMITER_CHARLIST
‪const SUBDELIMITER_CHARLIST
Definition: Uri.php:33
‪TYPO3\CMS\Core\Http\Uri\$supportedSchemes
‪int[] $supportedSchemes
Definition: Uri.php:49
‪TYPO3\CMS\Core\Http\Uri\withFragment
‪static withFragment($fragment)
Definition: Uri.php:535
‪TYPO3\CMS\Core\Http\Uri\withUserInfo
‪static withUserInfo($user, $password=null)
Definition: Uri.php:376
‪TYPO3\CMS\Core\Http\Uri\$authority
‪string $authority
Definition: Uri.php:57
‪TYPO3\CMS\Core\Http\Uri\withHost
‪static withHost($host)
Definition: Uri.php:401
‪TYPO3\CMS\Core\Http\Uri\$userInfo
‪string $userInfo
Definition: Uri.php:62
‪TYPO3\CMS\Core\Http\Uri\isNonStandardPort
‪bool isNonStandardPort($scheme, $host, $port)
Definition: Uri.php:601
‪TYPO3\CMS\Core\Http\Uri\withQuery
‪static withQuery($query)
Definition: Uri.php:504
‪TYPO3\CMS\Core\Http\Uri\getFragment
‪string getFragment()
Definition: Uri.php:331
‪TYPO3\CMS\Core\Http\Uri\UNRESERVED_CHARLIST
‪const UNRESERVED_CHARLIST
Definition: Uri.php:40
‪TYPO3\CMS\Core\Http\Uri\getHost
‪string getHost()
Definition: Uri.php:235
‪TYPO3\CMS\Core\Http\Uri\getScheme
‪string getScheme()
Definition: Uri.php:163
‪TYPO3\CMS\Core\Http\Uri\__toString
‪string __toString()
Definition: Uri.php:566
‪TYPO3\CMS\Core\Http\Uri\withScheme
‪static withScheme($scheme)
Definition: Uri.php:352
‪TYPO3\CMS\Core\Http\Uri\sanitizeQuery
‪string sanitizeQuery($query)
Definition: Uri.php:663
‪TYPO3\CMS\Core\Http\Uri\$scheme
‪string $scheme
Definition: Uri.php:45
‪TYPO3\CMS\Core\Http
Definition: AbstractApplication.php:3
‪TYPO3\CMS\Core\Http\Uri\sanitizeScheme
‪string sanitizeScheme($scheme)
Definition: Uri.php:622