Url; ++$index; } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos); } // Does the baseUrl have anything in common with the request_uri? $requestUri = $this->getRequestUri(); if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { // full $baseUrl matches return $prefix; } if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) { // directory portion of $baseUrl matches return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR); } $truncatedRequestUri = $requestUri; if (false !== $pos = strpos($requestUri, '?')) { $truncatedRequestUri = substr($requestUri, 0, $pos); } $basename = basename($baseUrl); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { // no match whatsoever; set it blank return ''; } // If using mod_rewrite or ISAPI_Rewrite strip the script filename // out of baseUrl. $pos !== 0 makes sure it is not matching a value // from PATH_INFO or QUERY_STRING if (\strlen($requestUri) >= \strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) { $baseUrl = substr($requestUri, 0, $pos + \strlen($baseUrl)); } return rtrim($baseUrl, '/'.\DIRECTORY_SEPARATOR); } /** * Prepares the base path. * * @return string base path */ protected function prepareBasePath() { $baseUrl = $this->getBaseUrl(); if (empty($baseUrl)) { return ''; } $filename = basename($this->server->get('SCRIPT_FILENAME')); if (basename($baseUrl) === $filename) { $basePath = \dirname($baseUrl); } else { $basePath = $baseUrl; } if ('\\' === \DIRECTORY_SEPARATOR) { $basePath = str_replace('\\', '/', $basePath); } return rtrim($basePath, '/'); } /** * Prepares the path info. * * @return string path info */ protected function preparePathInfo() { if (null === ($requestUri = $this->getRequestUri())) { return '/'; } // Remove the query string from REQUEST_URI if (false !== $pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); } if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } if (null === ($baseUrl = $this->getBaseUrl())) { return $requestUri; } $pathInfo = substr($requestUri, \strlen($baseUrl)); if (false === $pathInfo || '' === $pathInfo) { // If substr() returns false then PATH_INFO is set to an empty string return '/'; } return (string) $pathInfo; } /** * Initializes HTTP request formats. */ protected static function initializeFormats() { static::$formats = [ 'html' => ['text/html', 'application/xhtml+xml'], 'txt' => ['text/plain'], 'js' => ['application/javascript', 'application/x-javascript', 'text/javascript'], 'css' => ['text/css'], 'json' => ['application/json', 'application/x-json'], 'jsonld' => ['application/ld+json'], 'xml' => ['text/xml', 'application/xml', 'application/x-xml'], 'rdf' => ['application/rdf+xml'], 'atom' => ['application/atom+xml'], 'rss' => ['application/rss+xml'], 'form' => ['application/x-www-form-urlencoded'], ]; } /** * Sets the default PHP locale. * * @param string $locale */ private function setPhpDefaultLocale($locale) { // if either the class Locale doesn't exist, or an exception is thrown when // setting the default locale, the intl module is not installed, and // the call can be ignored: try { if (class_exists('Locale', false)) { \Locale::setDefault($locale); } } catch (\Exception $e) { } } /** * Returns the prefix as encoded in the string when the string starts with * the given prefix, false otherwise. * * @param string $string The urlencoded string * @param string $prefix The prefix not encoded * * @return string|false The prefix as it is encoded in $string, or false */ private function getUrlencodedPrefix($string, $prefix) { if (0 !== strpos(rawurldecode($string), $prefix)) { return false; } $len = \strlen($prefix); if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) { return $match[0]; } return false; } private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) { if (self::$requestFactory) { $request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content); if (!$request instanceof self) { throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.'); } return $request; } return new static($query, $request, $attributes, $cookies, $files, $server, $content); } /** * Indicates whether this request originated from a trusted proxy. * * This can be useful to determine whether or not to trust the * contents of a proxy-specific header. * * @return bool true if the request came from a trusted proxy, false otherwise */ public function isFromTrustedProxy() { return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies); } private function getTrustedValues($type, $ip = null) { $clientValues = []; $forwardedValues = []; if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) { foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) { $clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v); } } if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); $forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : []; if (self::HEADER_CLIENT_PORT === $type) { foreach ($forwardedValues as $k => $v) { if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) { $v = $this->isSecure() ? ':443' : ':80'; } $forwardedValues[$k] = '0.0.0.0'.$v; } } } if (null !== $ip) { $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip); $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip); } if ($forwardedValues === $clientValues || !$clientValues) { return $forwardedValues; } if (!$forwardedValues) { return $clientValues; } if (!$this->isForwardedValid) { return null !== $ip ? ['0.0.0.0', $ip] : []; } $this->isForwardedValid = false; throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::$trustedHeaders[self::HEADER_FORWARDED], self::$trustedHeaders[$type])); } private function normalizeAndFilterClientIps(array $clientIps, $ip) { if (!$clientIps) { return []; } $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from $firstTrustedIp = null; foreach ($clientIps as $key => $clientIp) { if (strpos($clientIp, '.')) { // Strip :port from IPv4 addresses. This is allowed in Forwarded // and may occur in X-Forwarded-For. $i = strpos($clientIp, ':'); if ($i) { $clientIps[$key] = $clientIp = substr($clientIp, 0, $i); } } elseif (0 === strpos($clientIp, '[')) { // Strip brackets and :port from IPv6 addresses. $i = strpos($clientIp, ']', 1); $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); } if (!filter_var($clientIp, \FILTER_VALIDATE_IP)) { unset($clientIps[$key]); continue; } if (IpUtils::checkIp($clientIp, self::$trustedProxies)) { unset($clientIps[$key]); // Fallback to this when the client IP falls into the range of trusted proxies if (null === $firstTrustedIp) { $firstTrustedIp = $clientIp; } } } // Now the IP chain contains only untrusted proxies and the client IP return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp]; } }