friendship ended with social-app. php is my new best friend
1<?php 2 3namespace React\Http\Message; 4 5use Psr\Http\Message\UriInterface; 6 7/** 8 * Respresents a URI (or URL). 9 * 10 * This class implements the 11 * [PSR-7 `UriInterface`](https://www.php-fig.org/psr/psr-7/#35-psrhttpmessageuriinterface). 12 * 13 * This is mostly used internally to represent the URI of each HTTP request 14 * message for our HTTP client and server implementations. Likewise, you may 15 * also use this class with other HTTP implementations and for tests. 16 * 17 * @see UriInterface 18 */ 19final class Uri implements UriInterface 20{ 21 /** @var string */ 22 private $scheme = ''; 23 24 /** @var string */ 25 private $userInfo = ''; 26 27 /** @var string */ 28 private $host = ''; 29 30 /** @var ?int */ 31 private $port = null; 32 33 /** @var string */ 34 private $path = ''; 35 36 /** @var string */ 37 private $query = ''; 38 39 /** @var string */ 40 private $fragment = ''; 41 42 /** 43 * @param string $uri 44 * @throws \InvalidArgumentException if given $uri is invalid 45 */ 46 public function __construct($uri) 47 { 48 // @codeCoverageIgnoreStart 49 if (\PHP_VERSION_ID < 50407 && \strpos($uri, '//') === 0) { 50 // @link https://3v4l.org/UrAQP 51 $parts = \parse_url('http:' . $uri); 52 unset($parts['schema']); 53 } else { 54 $parts = \parse_url($uri); 55 } 56 // @codeCoverageIgnoreEnd 57 58 if ($parts === false || (isset($parts['scheme']) && !\preg_match('#^[a-z]+$#i', $parts['scheme'])) || (isset($parts['host']) && \preg_match('#[\s%+]#', $parts['host']))) { 59 throw new \InvalidArgumentException('Invalid URI given'); 60 } 61 62 if (isset($parts['scheme'])) { 63 $this->scheme = \strtolower($parts['scheme']); 64 } 65 66 if (isset($parts['user']) || isset($parts['pass'])) { 67 $this->userInfo = $this->encode(isset($parts['user']) ? $parts['user'] : '', \PHP_URL_USER) . (isset($parts['pass']) ? ':' . $this->encode($parts['pass'], \PHP_URL_PASS) : ''); 68 } 69 70 if (isset($parts['host'])) { 71 $this->host = \strtolower($parts['host']); 72 } 73 74 if (isset($parts['port']) && !(($parts['port'] === 80 && $this->scheme === 'http') || ($parts['port'] === 443 && $this->scheme === 'https'))) { 75 $this->port = $parts['port']; 76 } 77 78 if (isset($parts['path'])) { 79 $this->path = $this->encode($parts['path'], \PHP_URL_PATH); 80 } 81 82 if (isset($parts['query'])) { 83 $this->query = $this->encode($parts['query'], \PHP_URL_QUERY); 84 } 85 86 if (isset($parts['fragment'])) { 87 $this->fragment = $this->encode($parts['fragment'], \PHP_URL_FRAGMENT); 88 } 89 } 90 91 public function getScheme() 92 { 93 return $this->scheme; 94 } 95 96 public function getAuthority() 97 { 98 if ($this->host === '') { 99 return ''; 100 } 101 102 return ($this->userInfo !== '' ? $this->userInfo . '@' : '') . $this->host . ($this->port !== null ? ':' . $this->port : ''); 103 } 104 105 public function getUserInfo() 106 { 107 return $this->userInfo; 108 } 109 110 public function getHost() 111 { 112 return $this->host; 113 } 114 115 public function getPort() 116 { 117 return $this->port; 118 } 119 120 public function getPath() 121 { 122 return $this->path; 123 } 124 125 public function getQuery() 126 { 127 return $this->query; 128 } 129 130 public function getFragment() 131 { 132 return $this->fragment; 133 } 134 135 public function withScheme($scheme) 136 { 137 $scheme = \strtolower($scheme); 138 if ($scheme === $this->scheme) { 139 return $this; 140 } 141 142 if (!\preg_match('#^[a-z]*$#', $scheme)) { 143 throw new \InvalidArgumentException('Invalid URI scheme given'); 144 } 145 146 $new = clone $this; 147 $new->scheme = $scheme; 148 149 if (($this->port === 80 && $scheme === 'http') || ($this->port === 443 && $scheme === 'https')) { 150 $new->port = null; 151 } 152 153 return $new; 154 } 155 156 public function withUserInfo($user, $password = null) 157 { 158 $userInfo = $this->encode($user, \PHP_URL_USER) . ($password !== null ? ':' . $this->encode($password, \PHP_URL_PASS) : ''); 159 if ($userInfo === $this->userInfo) { 160 return $this; 161 } 162 163 $new = clone $this; 164 $new->userInfo = $userInfo; 165 166 return $new; 167 } 168 169 public function withHost($host) 170 { 171 $host = \strtolower($host); 172 if ($host === $this->host) { 173 return $this; 174 } 175 176 if (\preg_match('#[\s%+]#', $host) || ($host !== '' && \parse_url('http://' . $host, \PHP_URL_HOST) !== $host)) { 177 throw new \InvalidArgumentException('Invalid URI host given'); 178 } 179 180 $new = clone $this; 181 $new->host = $host; 182 183 return $new; 184 } 185 186 public function withPort($port) 187 { 188 $port = $port === null ? null : (int) $port; 189 if (($port === 80 && $this->scheme === 'http') || ($port === 443 && $this->scheme === 'https')) { 190 $port = null; 191 } 192 193 if ($port === $this->port) { 194 return $this; 195 } 196 197 if ($port !== null && ($port < 1 || $port > 0xffff)) { 198 throw new \InvalidArgumentException('Invalid URI port given'); 199 } 200 201 $new = clone $this; 202 $new->port = $port; 203 204 return $new; 205 } 206 207 public function withPath($path) 208 { 209 $path = $this->encode($path, \PHP_URL_PATH); 210 if ($path === $this->path) { 211 return $this; 212 } 213 214 $new = clone $this; 215 $new->path = $path; 216 217 return $new; 218 } 219 220 public function withQuery($query) 221 { 222 $query = $this->encode($query, \PHP_URL_QUERY); 223 if ($query === $this->query) { 224 return $this; 225 } 226 227 $new = clone $this; 228 $new->query = $query; 229 230 return $new; 231 } 232 233 public function withFragment($fragment) 234 { 235 $fragment = $this->encode($fragment, \PHP_URL_FRAGMENT); 236 if ($fragment === $this->fragment) { 237 return $this; 238 } 239 240 $new = clone $this; 241 $new->fragment = $fragment; 242 243 return $new; 244 } 245 246 public function __toString() 247 { 248 $uri = ''; 249 if ($this->scheme !== '') { 250 $uri .= $this->scheme . ':'; 251 } 252 253 $authority = $this->getAuthority(); 254 if ($authority !== '') { 255 $uri .= '//' . $authority; 256 } 257 258 if ($authority !== '' && isset($this->path[0]) && $this->path[0] !== '/') { 259 $uri .= '/' . $this->path; 260 } elseif ($authority === '' && isset($this->path[0]) && $this->path[0] === '/') { 261 $uri .= '/' . \ltrim($this->path, '/'); 262 } else { 263 $uri .= $this->path; 264 } 265 266 if ($this->query !== '') { 267 $uri .= '?' . $this->query; 268 } 269 270 if ($this->fragment !== '') { 271 $uri .= '#' . $this->fragment; 272 } 273 274 return $uri; 275 } 276 277 /** 278 * @param string $part 279 * @param int $component 280 * @return string 281 */ 282 private function encode($part, $component) 283 { 284 return \preg_replace_callback( 285 '/(?:[^a-z0-9_\-\.~!\$&\'\(\)\*\+,;=' . ($component === \PHP_URL_PATH ? ':@\/' : ($component === \PHP_URL_QUERY || $component === \PHP_URL_FRAGMENT ? ':@\/\?' : '')) . '%]++|%(?![a-f0-9]{2}))/i', 286 function (array $match) { 287 return \rawurlencode($match[0]); 288 }, 289 $part 290 ); 291 } 292 293 /** 294 * [Internal] Resolve URI relative to base URI and return new absolute URI 295 * 296 * @internal 297 * @param UriInterface $base 298 * @param UriInterface $rel 299 * @return UriInterface 300 * @throws void 301 */ 302 public static function resolve(UriInterface $base, UriInterface $rel) 303 { 304 if ($rel->getScheme() !== '') { 305 return $rel->getPath() === '' ? $rel : $rel->withPath(self::removeDotSegments($rel->getPath())); 306 } 307 308 $reset = false; 309 $new = $base; 310 if ($rel->getAuthority() !== '') { 311 $reset = true; 312 $userInfo = \explode(':', $rel->getUserInfo(), 2); 313 $new = $base->withUserInfo($userInfo[0], isset($userInfo[1]) ? $userInfo[1]: null)->withHost($rel->getHost())->withPort($rel->getPort()); 314 } 315 316 if ($reset && $rel->getPath() === '') { 317 $new = $new->withPath(''); 318 } elseif (($path = $rel->getPath()) !== '') { 319 $start = ''; 320 if ($path === '' || $path[0] !== '/') { 321 $start = $base->getPath(); 322 if (\substr($start, -1) !== '/') { 323 $start .= '/../'; 324 } 325 } 326 $reset = true; 327 $new = $new->withPath(self::removeDotSegments($start . $path)); 328 } 329 if ($reset || $rel->getQuery() !== '') { 330 $reset = true; 331 $new = $new->withQuery($rel->getQuery()); 332 } 333 if ($reset || $rel->getFragment() !== '') { 334 $new = $new->withFragment($rel->getFragment()); 335 } 336 337 return $new; 338 } 339 340 /** 341 * @param string $path 342 * @return string 343 */ 344 private static function removeDotSegments($path) 345 { 346 $segments = array(); 347 foreach (\explode('/', $path) as $segment) { 348 if ($segment === '..') { 349 \array_pop($segments); 350 } elseif ($segment !== '.' && $segment !== '') { 351 $segments[] = $segment; 352 } 353 } 354 return '/' . \implode('/', $segments) . ($path !== '/' && \substr($path, -1) === '/' ? '/' : ''); 355 } 356}