friendship ended with social-app. php is my new best friend
at main 3.6 kB view raw
1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\DomCrawler; 13 14/** 15 * The UriResolver class takes an URI (relative, absolute, fragment, etc.) 16 * and turns it into an absolute URI against another given base URI. 17 * 18 * @author Fabien Potencier <fabien@symfony.com> 19 * @author Grégoire Pineau <lyrixx@lyrixx.info> 20 */ 21class UriResolver 22{ 23 /** 24 * Resolves a URI according to a base URI. 25 * 26 * For example if $uri=/foo/bar and $baseUri=https://symfony.com it will 27 * return https://symfony.com/foo/bar 28 * 29 * If the $uri is not absolute you must pass an absolute $baseUri 30 */ 31 public static function resolve(string $uri, ?string $baseUri): string 32 { 33 $uri = trim($uri); 34 35 // absolute URL? 36 if (null !== parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#', \PHP_URL_SCHEME)) { 37 return $uri; 38 } 39 40 if (null === $baseUri) { 41 throw new \InvalidArgumentException('The URI is relative, so you must define its base URI passing an absolute URL.'); 42 } 43 44 // empty URI 45 if (!$uri) { 46 return $baseUri; 47 } 48 49 // an anchor 50 if ('#' === $uri[0]) { 51 return self::cleanupAnchor($baseUri).$uri; 52 } 53 54 $baseUriCleaned = self::cleanupUri($baseUri); 55 56 if ('?' === $uri[0]) { 57 return $baseUriCleaned.$uri; 58 } 59 60 // absolute URL with relative schema 61 if (str_starts_with($uri, '//')) { 62 return preg_replace('#^([^/]*)//.*$#', '$1', $baseUriCleaned).$uri; 63 } 64 65 $baseUriCleaned = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUriCleaned); 66 67 // absolute path 68 if ('/' === $uri[0]) { 69 return $baseUriCleaned.$uri; 70 } 71 72 // relative path 73 $path = parse_url(substr($baseUri, \strlen($baseUriCleaned)), \PHP_URL_PATH) ?? ''; 74 $path = self::canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri); 75 76 return $baseUriCleaned.('' === $path || '/' !== $path[0] ? '/' : '').$path; 77 } 78 79 /** 80 * Returns the canonicalized URI path (see RFC 3986, section 5.2.4). 81 */ 82 private static function canonicalizePath(string $path): string 83 { 84 if ('' === $path || '/' === $path) { 85 return $path; 86 } 87 88 if (str_ends_with($path, '.')) { 89 $path .= '/'; 90 } 91 92 $output = []; 93 94 foreach (explode('/', $path) as $segment) { 95 if ('..' === $segment) { 96 array_pop($output); 97 } elseif ('.' !== $segment) { 98 $output[] = $segment; 99 } 100 } 101 102 return implode('/', $output); 103 } 104 105 /** 106 * Removes the query string and the anchor from the given uri. 107 */ 108 private static function cleanupUri(string $uri): string 109 { 110 return self::cleanupQuery(self::cleanupAnchor($uri)); 111 } 112 113 /** 114 * Removes the query string from the uri. 115 */ 116 private static function cleanupQuery(string $uri): string 117 { 118 if (false !== $pos = strpos($uri, '?')) { 119 return substr($uri, 0, $pos); 120 } 121 122 return $uri; 123 } 124 125 /** 126 * Removes the anchor from the uri. 127 */ 128 private static function cleanupAnchor(string $uri): string 129 { 130 if (false !== $pos = strpos($uri, '#')) { 131 return substr($uri, 0, $pos); 132 } 133 134 return $uri; 135 } 136}