[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 namespace GuzzleHttp; 3 4 use GuzzleHttp\Ring\Core; 5 6 /** 7 * Parses and generates URLs based on URL parts 8 */ 9 class Url 10 { 11 private $scheme; 12 private $host; 13 private $port; 14 private $username; 15 private $password; 16 private $path = ''; 17 private $fragment; 18 private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21]; 19 private static $pathPattern = '/[^a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@\/]+|%(?![A-Fa-f0-9]{2})/'; 20 private static $queryPattern = '/[^a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;%:@\/\?=&]+|%(?![A-Fa-f0-9]{2})/'; 21 /** @var Query|string Query part of the URL */ 22 private $query; 23 24 /** 25 * Factory method to create a new URL from a URL string 26 * 27 * @param string $url Full URL used to create a Url object 28 * 29 * @return Url 30 * @throws \InvalidArgumentException 31 */ 32 public static function fromString($url) 33 { 34 static $defaults = ['scheme' => null, 'host' => null, 35 'path' => null, 'port' => null, 'query' => null, 36 'user' => null, 'pass' => null, 'fragment' => null]; 37 38 if (false === ($parts = parse_url($url))) { 39 throw new \InvalidArgumentException('Unable to parse malformed ' 40 . 'url: ' . $url); 41 } 42 43 $parts += $defaults; 44 45 // Convert the query string into a Query object 46 if ($parts['query'] || 0 !== strlen($parts['query'])) { 47 $parts['query'] = Query::fromString($parts['query']); 48 } 49 50 return new static($parts['scheme'], $parts['host'], $parts['user'], 51 $parts['pass'], $parts['port'], $parts['path'], $parts['query'], 52 $parts['fragment']); 53 } 54 55 /** 56 * Build a URL from parse_url parts. The generated URL will be a relative 57 * URL if a scheme or host are not provided. 58 * 59 * @param array $parts Array of parse_url parts 60 * 61 * @return string 62 */ 63 public static function buildUrl(array $parts) 64 { 65 $url = $scheme = ''; 66 67 if (!empty($parts['scheme'])) { 68 $scheme = $parts['scheme']; 69 $url .= $scheme . ':'; 70 } 71 72 if (!empty($parts['host'])) { 73 $url .= '//'; 74 if (isset($parts['user'])) { 75 $url .= $parts['user']; 76 if (isset($parts['pass'])) { 77 $url .= ':' . $parts['pass']; 78 } 79 $url .= '@'; 80 } 81 82 $url .= $parts['host']; 83 84 // Only include the port if it is not the default port of the scheme 85 if (isset($parts['port']) && 86 (!isset(self::$defaultPorts[$scheme]) || 87 $parts['port'] != self::$defaultPorts[$scheme]) 88 ) { 89 $url .= ':' . $parts['port']; 90 } 91 } 92 93 // Add the path component if present 94 if (isset($parts['path']) && strlen($parts['path'])) { 95 // Always ensure that the path begins with '/' if set and something 96 // is before the path 97 if (!empty($parts['host']) && $parts['path'][0] != '/') { 98 $url .= '/'; 99 } 100 $url .= $parts['path']; 101 } 102 103 // Add the query string if present 104 if (isset($parts['query'])) { 105 $queryStr = (string) $parts['query']; 106 if ($queryStr || $queryStr === '0') { 107 $url .= '?' . $queryStr; 108 } 109 } 110 111 // Ensure that # is only added to the url if fragment contains anything. 112 if (isset($parts['fragment'])) { 113 $url .= '#' . $parts['fragment']; 114 } 115 116 return $url; 117 } 118 119 /** 120 * Create a new URL from URL parts 121 * 122 * @param string $scheme Scheme of the URL 123 * @param string $host Host of the URL 124 * @param string $username Username of the URL 125 * @param string $password Password of the URL 126 * @param int $port Port of the URL 127 * @param string $path Path of the URL 128 * @param Query|array|string $query Query string of the URL 129 * @param string $fragment Fragment of the URL 130 */ 131 public function __construct( 132 $scheme, 133 $host, 134 $username = null, 135 $password = null, 136 $port = null, 137 $path = null, 138 $query = null, 139 $fragment = null 140 ) { 141 $this->scheme = strtolower($scheme); 142 $this->host = $host; 143 $this->port = $port; 144 $this->username = $username; 145 $this->password = $password; 146 $this->fragment = $fragment; 147 148 if ($query) { 149 $this->setQuery($query); 150 } 151 152 $this->setPath($path); 153 } 154 155 /** 156 * Clone the URL 157 */ 158 public function __clone() 159 { 160 if ($this->query instanceof Query) { 161 $this->query = clone $this->query; 162 } 163 } 164 165 /** 166 * Returns the URL as a URL string 167 * 168 * @return string 169 */ 170 public function __toString() 171 { 172 return static::buildUrl($this->getParts()); 173 } 174 175 /** 176 * Get the parts of the URL as an array 177 * 178 * @return array 179 */ 180 public function getParts() 181 { 182 return array( 183 'scheme' => $this->scheme, 184 'user' => $this->username, 185 'pass' => $this->password, 186 'host' => $this->host, 187 'port' => $this->port, 188 'path' => $this->path, 189 'query' => $this->query, 190 'fragment' => $this->fragment, 191 ); 192 } 193 194 /** 195 * Set the host of the request. 196 * 197 * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com) 198 * 199 * @return Url 200 */ 201 public function setHost($host) 202 { 203 if (strpos($host, ':') === false) { 204 $this->host = $host; 205 } else { 206 list($host, $port) = explode(':', $host); 207 $this->host = $host; 208 $this->setPort($port); 209 } 210 } 211 212 /** 213 * Get the host part of the URL 214 * 215 * @return string 216 */ 217 public function getHost() 218 { 219 return $this->host; 220 } 221 222 /** 223 * Set the scheme part of the URL (http, https, ftp, etc.) 224 * 225 * @param string $scheme Scheme to set 226 */ 227 public function setScheme($scheme) 228 { 229 // Remove the default port if one is specified 230 if ($this->port 231 && isset(self::$defaultPorts[$this->scheme]) 232 && self::$defaultPorts[$this->scheme] == $this->port 233 ) { 234 $this->port = null; 235 } 236 237 $this->scheme = strtolower($scheme); 238 } 239 240 /** 241 * Get the scheme part of the URL 242 * 243 * @return string 244 */ 245 public function getScheme() 246 { 247 return $this->scheme; 248 } 249 250 /** 251 * Set the port part of the URL 252 * 253 * @param int $port Port to set 254 */ 255 public function setPort($port) 256 { 257 $this->port = $port; 258 } 259 260 /** 261 * Get the port part of the URl. 262 * 263 * If no port was set, this method will return the default port for the 264 * scheme of the URI. 265 * 266 * @return int|null 267 */ 268 public function getPort() 269 { 270 if ($this->port) { 271 return $this->port; 272 } elseif (isset(self::$defaultPorts[$this->scheme])) { 273 return self::$defaultPorts[$this->scheme]; 274 } 275 276 return null; 277 } 278 279 /** 280 * Set the path part of the URL. 281 * 282 * The provided URL is URL encoded as necessary. 283 * 284 * @param string $path Path string to set 285 */ 286 public function setPath($path) 287 { 288 $this->path = self::encodePath($path); 289 } 290 291 /** 292 * Removes dot segments from a URL 293 * @link http://tools.ietf.org/html/rfc3986#section-5.2.4 294 */ 295 public function removeDotSegments() 296 { 297 static $noopPaths = ['' => true, '/' => true, '*' => true]; 298 static $ignoreSegments = ['.' => true, '..' => true]; 299 300 if (isset($noopPaths[$this->path])) { 301 return; 302 } 303 304 $results = []; 305 $segments = $this->getPathSegments(); 306 foreach ($segments as $segment) { 307 if ($segment == '..') { 308 array_pop($results); 309 } elseif (!isset($ignoreSegments[$segment])) { 310 $results[] = $segment; 311 } 312 } 313 314 $newPath = implode('/', $results); 315 316 // Add the leading slash if necessary 317 if (substr($this->path, 0, 1) === '/' && 318 substr($newPath, 0, 1) !== '/' 319 ) { 320 $newPath = '/' . $newPath; 321 } 322 323 // Add the trailing slash if necessary 324 if ($newPath != '/' && isset($ignoreSegments[end($segments)])) { 325 $newPath .= '/'; 326 } 327 328 $this->path = $newPath; 329 } 330 331 /** 332 * Add a relative path to the currently set path. 333 * 334 * @param string $relativePath Relative path to add 335 */ 336 public function addPath($relativePath) 337 { 338 if ($relativePath != '/' && 339 is_string($relativePath) && 340 strlen($relativePath) > 0 341 ) { 342 // Add a leading slash if needed 343 if ($relativePath[0] !== '/' && 344 substr($this->path, -1, 1) !== '/' 345 ) { 346 $relativePath = '/' . $relativePath; 347 } 348 349 $this->setPath($this->path . $relativePath); 350 } 351 } 352 353 /** 354 * Get the path part of the URL 355 * 356 * @return string 357 */ 358 public function getPath() 359 { 360 return $this->path; 361 } 362 363 /** 364 * Get the path segments of the URL as an array 365 * 366 * @return array 367 */ 368 public function getPathSegments() 369 { 370 return explode('/', $this->path); 371 } 372 373 /** 374 * Set the password part of the URL 375 * 376 * @param string $password Password to set 377 */ 378 public function setPassword($password) 379 { 380 $this->password = $password; 381 } 382 383 /** 384 * Get the password part of the URL 385 * 386 * @return null|string 387 */ 388 public function getPassword() 389 { 390 return $this->password; 391 } 392 393 /** 394 * Set the username part of the URL 395 * 396 * @param string $username Username to set 397 */ 398 public function setUsername($username) 399 { 400 $this->username = $username; 401 } 402 403 /** 404 * Get the username part of the URl 405 * 406 * @return null|string 407 */ 408 public function getUsername() 409 { 410 return $this->username; 411 } 412 413 /** 414 * Get the query part of the URL as a Query object 415 * 416 * @return Query 417 */ 418 public function getQuery() 419 { 420 // Convert the query string to a query object if not already done. 421 if (!$this->query instanceof Query) { 422 $this->query = $this->query === null 423 ? new Query() 424 : Query::fromString($this->query); 425 } 426 427 return $this->query; 428 } 429 430 /** 431 * Set the query part of the URL. 432 * 433 * You may provide a query string as a string and pass $rawString as true 434 * to provide a query string that is not parsed until a call to getQuery() 435 * is made. Setting a raw query string will still encode invalid characters 436 * in a query string. 437 * 438 * @param Query|string|array $query Query string value to set. Can 439 * be a string that will be parsed into a Query object, an array 440 * of key value pairs, or a Query object. 441 * @param bool $rawString Set to true when providing a raw query string. 442 * 443 * @throws \InvalidArgumentException 444 */ 445 public function setQuery($query, $rawString = false) 446 { 447 if ($query instanceof Query) { 448 $this->query = $query; 449 } elseif (is_string($query)) { 450 if (!$rawString) { 451 $this->query = Query::fromString($query); 452 } else { 453 // Ensure the query does not have illegal characters. 454 $this->query = preg_replace_callback( 455 self::$queryPattern, 456 [__CLASS__, 'encodeMatch'], 457 $query 458 ); 459 } 460 461 } elseif (is_array($query)) { 462 $this->query = new Query($query); 463 } else { 464 throw new \InvalidArgumentException('Query must be a Query, ' 465 . 'array, or string. Got ' . Core::describeType($query)); 466 } 467 } 468 469 /** 470 * Get the fragment part of the URL 471 * 472 * @return null|string 473 */ 474 public function getFragment() 475 { 476 return $this->fragment; 477 } 478 479 /** 480 * Set the fragment part of the URL 481 * 482 * @param string $fragment Fragment to set 483 */ 484 public function setFragment($fragment) 485 { 486 $this->fragment = $fragment; 487 } 488 489 /** 490 * Check if this is an absolute URL 491 * 492 * @return bool 493 */ 494 public function isAbsolute() 495 { 496 return $this->scheme && $this->host; 497 } 498 499 /** 500 * Combine the URL with another URL and return a new URL instance. 501 * 502 * Follows the rules specific in RFC 3986 section 5.4. 503 * 504 * @param string $url Relative URL to combine with 505 * 506 * @return Url 507 * @throws \InvalidArgumentException 508 * @link http://tools.ietf.org/html/rfc3986#section-5.4 509 */ 510 public function combine($url) 511 { 512 $url = static::fromString($url); 513 514 // Use the more absolute URL as the base URL 515 if (!$this->isAbsolute() && $url->isAbsolute()) { 516 $url = $url->combine($this); 517 } 518 519 $parts = $url->getParts(); 520 521 // Passing a URL with a scheme overrides everything 522 if ($parts['scheme']) { 523 return clone $url; 524 } 525 526 // Setting a host overrides the entire rest of the URL 527 if ($parts['host']) { 528 return new static( 529 $this->scheme, 530 $parts['host'], 531 $parts['user'], 532 $parts['pass'], 533 $parts['port'], 534 $parts['path'], 535 $parts['query'] instanceof Query 536 ? clone $parts['query'] 537 : $parts['query'], 538 $parts['fragment'] 539 ); 540 } 541 542 if (!$parts['path'] && $parts['path'] !== '0') { 543 // The relative URL has no path, so check if it is just a query 544 $path = $this->path ?: ''; 545 $query = $parts['query'] ?: $this->query; 546 } else { 547 $query = $parts['query']; 548 if ($parts['path'][0] == '/' || !$this->path) { 549 // Overwrite the existing path if the rel path starts with "/" 550 $path = $parts['path']; 551 } else { 552 // If the relative URL does not have a path or the base URL 553 // path does not end in a "/" then overwrite the existing path 554 // up to the last "/" 555 $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path']; 556 } 557 } 558 559 $result = new self( 560 $this->scheme, 561 $this->host, 562 $this->username, 563 $this->password, 564 $this->port, 565 $path, 566 $query instanceof Query ? clone $query : $query, 567 $parts['fragment'] 568 ); 569 570 if ($path) { 571 $result->removeDotSegments(); 572 } 573 574 return $result; 575 } 576 577 /** 578 * Encodes the path part of a URL without double-encoding percent-encoded 579 * key value pairs. 580 * 581 * @param string $path Path to encode 582 * 583 * @return string 584 */ 585 public static function encodePath($path) 586 { 587 static $cb = [__CLASS__, 'encodeMatch']; 588 return preg_replace_callback(self::$pathPattern, $cb, $path); 589 } 590 591 private static function encodeMatch(array $match) 592 { 593 return rawurlencode($match[0]); 594 } 595 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |