public function testEnterTd() { // ASCII. $res = CRegex::enterTd(".(]/", "/"); $this->assertTrue(CString::equals($res, "\\.\\(\\]\\/")); $res = CRegex::enterTd(".(]#", "#"); $this->assertTrue(CString::equals($res, "\\.\\(\\]\\#")); // Unicode. $res = CRegex::enterTd(".(señor]/", "/"); $this->assertTrue(CString::equals($res, "\\.\\(señor\\]\\/")); $res = CRegex::enterTd(".(señor]#", "#"); $this->assertTrue(CString::equals($res, "\\.\\(señor\\]\\#")); }
protected function removeHeader($headerName) { $headerName = CString::trim($headerName); CArray::removeByValue($this->m_requestHeaders, $headerName, function ($element0, $element1) { return CRegex::find($element0, "/^\\h*" . CRegex::enterTd($element1) . "\\h*:/i"); }); }
/** * Creates a parsed URL from a URL string. * * The URL string is expected to be by all means valid, with characters being percent-encoded where it is required * by the URL standard and without any leading or trailing whitespace. It is only when the URL string does not * indicate any protocol that the URL may still be considered valid and the default protocol is assigned to the * URL, which is "http". * * @param string $url The URL string. */ public function __construct($url) { assert('is_cstring($url)', vs(isset($this), get_defined_vars())); assert('self::isValid($url, true)', vs(isset($this), get_defined_vars())); $this->m_url = $url; $parsedUrl = parse_url($url); assert('is_cmap($parsedUrl)', vs(isset($this), get_defined_vars())); // should not rise for a valid URL // Protocol (scheme). if (CMap::hasKey($parsedUrl, "scheme")) { $this->m_hasProtocol = true; $this->m_protocol = $parsedUrl["scheme"]; // Normalize by converting to lowercase. $this->m_normProtocol = CString::toLowerCase($this->m_protocol); } else { $this->m_hasProtocol = false; $this->m_normProtocol = self::DEFAULT_PROTOCOL; if (!CMap::hasKey($parsedUrl, "host")) { // Most likely, `parse_url` function has not parsed the host because the protocol (scheme) is absent // and there are no "//" in the front, so try parsing the host with the default protocol in the URL. $parsedUrl = parse_url(self::ensureProtocol($url)); assert('is_cmap($parsedUrl)', vs(isset($this), get_defined_vars())); CMap::remove($parsedUrl, "scheme"); } } // Host (domain). $this->m_hostIsInBrackets = false; if (CMap::hasKey($parsedUrl, "host")) { $this->m_host = $parsedUrl["host"]; if (CRegex::find($this->m_host, "/^\\[.*\\]\\z/")) { // Most likely, an IPv6 enclosed in "[]". $this->m_hostIsInBrackets = true; $this->m_host = CString::substr($this->m_host, 1, CString::length($this->m_host) - 2); } // Normalize by converting to lowercase. $this->m_normHost = CString::toLowerCase($this->m_host); } else { // Same as invalid. assert('false', vs(isset($this), get_defined_vars())); } // Port. if (CMap::hasKey($parsedUrl, "port")) { $this->m_hasPort = true; $this->m_port = $parsedUrl["port"]; // Should be `int`, but look into the type just in case. if (is_cstring($this->m_port)) { $this->m_port = CString::toInt($this->m_port); } } else { $this->m_hasPort = false; } // Path. if (CMap::hasKey($parsedUrl, "path")) { $this->m_hasPath = true; $this->m_path = $parsedUrl["path"]; // Normalize by replacing percent-encoded bytes of unreserved characters with their literal equivalents and // ensuring that all percent-encoded parts are in uppercase. $pathDelimitersReEsc = CRegex::enterTd(self::$ms_delimiters); $this->m_normPath = CRegex::replaceWithCallback($this->m_path, "/[^{$pathDelimitersReEsc}]+/", function ($matches) { return CUrl::enterTdNew(CUrl::leaveTdNew($matches[0])); }); } else { $this->m_hasPath = false; $this->m_normPath = "/"; } $this->m_urlPath = new CUrlPath($this->m_normPath); // Query string. $this->m_hasQuery = false; if (CMap::hasKey($parsedUrl, "query")) { $this->m_hasQuery = true; $this->m_queryString = $parsedUrl["query"]; $parsingWasFruitful; $this->m_urlQuery = new CUrlQuery($this->m_queryString, $parsingWasFruitful); if ($parsingWasFruitful) { $this->m_hasQuery = true; $this->m_normQueryString = $this->m_urlQuery->queryString(true); } } // Fragment ID. if (CMap::hasKey($parsedUrl, "fragment")) { $this->m_hasFragmentId = true; $this->m_fragmentId = $parsedUrl["fragment"]; // Normalize by replacing percent-encoded bytes of unreserved characters with their literal equivalents and // ensuring that all percent-encoded parts are in uppercase. $fiDelimitersReEsc = CRegex::enterTd(self::$ms_delimiters); $this->m_normFragmentId = CRegex::replaceWithCallback($this->m_fragmentId, "/[^{$fiDelimitersReEsc}]+/", function ($matches) { // Use the newer flavor of percent-encoding. return CUrl::enterTdNew(CUrl::leaveTdNew($matches[0])); }); } else { $this->m_hasFragmentId = false; } // User. if (CMap::hasKey($parsedUrl, "user")) { $this->m_hasUser = true; $this->m_user = $parsedUrl["user"]; } else { $this->m_hasUser = false; } // Password. if (CMap::hasKey($parsedUrl, "pass")) { $this->m_hasPassword = true; $this->m_password = $parsedUrl["pass"]; } else { $this->m_hasPassword = false; } // Compose the normalized URL string. $this->m_normUrl = ""; $this->m_normUrl .= $this->m_normProtocol . "://"; if ($this->m_hasUser) { $this->m_normUrl .= $this->m_user; } if ($this->m_hasPassword) { $this->m_normUrl .= ":" . $this->m_password; } if ($this->m_hasUser || $this->m_hasPassword) { $this->m_normUrl .= "@"; } if (!$this->m_hostIsInBrackets) { $this->m_normUrl .= $this->m_normHost; } else { $this->m_normUrl .= "[" . $this->m_normHost . "]"; } if ($this->m_hasPort) { // Normalize by skipping port indication if the port is the default one for the protocol. if (!(CMap::hasKey(self::$ms_knownProtocolToDefaultPort, $this->m_normProtocol) && self::$ms_knownProtocolToDefaultPort[$this->m_normProtocol] == $this->m_port)) { $this->m_normUrl .= ":" . $this->m_port; } } $this->m_normUrl .= $this->m_normPath; if ($this->m_hasQuery) { $this->m_normUrl .= "?" . $this->m_normQueryString; } $this->m_normUrlWithoutFragmentId = $this->m_normUrl; if ($this->m_hasFragmentId) { $this->m_normUrl .= "#" . $this->m_normFragmentId; } }
/** * Escapes all characters that have a special meaning in the regular expression domain, and returns the escaped * string. * * With this method, you can prepare an arbitrary string to be used as a part of a regular expression. * * @param string $delimiter **OPTIONAL. Default is** "/". The pattern delimiter that is going to be used by the * resulting regular expression and therefore needs to be escaped as well. * * @return CUStringObject The escaped string. */ public function reEnterTd($delimiter = CRegex::DEFAULT_PATTERN_DELIMITER) { return CRegex::enterTd($this, $delimiter); }