diff --git a/lib/Url.php b/lib/Url.php index b076873..e81bbbb 100644 --- a/lib/Url.php +++ b/lib/Url.php @@ -46,23 +46,8 @@ class Url implements UriInterface { (\#.*)? # fragment part $>six PCRE; - protected const AUTHORITY_PATTERN = <<<'PCRE' -<^ -// -(?: - ([^@:]*) # username part - (?::([^@]*))? # password part - @ -)? -( - \[[a-f0-9:]*\] | # IPv6 address - [^:]* # domain or IPv4 address -) -(?: - :([^/]*) # port part -)? -$>six -PCRE; + protected const HOST_PATTERN = '/^(\[[a-f0-9:]*\]|[^:]*)(?::([^\/]*))?$/si'; + protected const USER_PATTERN = '/^([^:]*)(?::(.*))?$/s'; protected const SCHEME_PATTERN = '/^(?:[a-z][a-z0-9\.\-\+]*|)$/i'; protected const IPV6_PATTERN = '/^\[[a-f0-9:]+\]$/i'; protected const PORT_PATTERN = '/^\d*$/'; @@ -70,7 +55,7 @@ PCRE; protected const WHITESPACE_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20"; protected const ESCAPE_CHARS = [ 'user' => [":", "@", "/", "?", "#"], - 'pass' => ["@", "/", "?", "#"], + 'pass' => [":", "@", "/", "?", "#"], 'path' => ["?", "#"], 'query' => ["#"], ]; @@ -117,14 +102,21 @@ PCRE; } } if (strlen($authority)) { - if (preg_match(self::AUTHORITY_PATTERN, $authority, $match)) { - [$authority, $user, $pass, $host, $port] = array_pad($match, 5, ""); - foreach (["user", "pass", "host", "port"] as $part) { - $this->set($part, $$part); + $authority = substr($authority, 2); + if (($cleft = strrpos($authority, "@")) !== false) { + if (preg_match(self::USER_PATTERN, substr($authority, 0, $cleft), $match)) { + $this->set("user", $match[1]); + $this->set("pass", $match[2] ?? ""); } - } else { - assert(false, "Authority did not match pattern"); + if (preg_match(self::HOST_PATTERN, substr($authority, $cleft + 1), $match)) { + $this->set("host", $match[1]); + $this->set("port", $match[2] ?? ""); + } + } elseif (preg_match(self::HOST_PATTERN, $authority, $match)) { + $this->set("host", $match[1]); + $this->set("port", $match[2] ?? ""); } + } if ((!$this->scheme || ($this->host === null && array_key_exists($this->scheme, self::SPECIAL_SCHEMES))) && strlen($baseUrl ?? "")) { $this->resolve(new static($baseUrl)); @@ -233,12 +225,15 @@ PCRE; } public function __toString() { - $auth = $this->getAuthority(); $out = ""; $out .= strlen($this->scheme) ? $this->scheme.":" : ""; if (is_null($this->host)) { $out .= $this->path; } else { + $auth = $this->host; + $auth .= (strlen($auth) && !is_null($this->port)) ? ":".$this->port : ""; + $user = $this->user.(strlen($this->pass) ? ":".$this->pass : ""); + $auth = (strlen($auth) && strlen($user)) ? "$user@$auth" : $auth; $out .= "//"; $out .= $auth; $out .= ($this->path[0] ?? "") !== "/" && strlen($auth) ? "/" : "";