19 class_exists(AcceptHeader::class);
20 class_exists(FileBag::class);
21 class_exists(HeaderBag::class);
22 class_exists(HeaderUtils::class);
23 class_exists(ParameterBag::class);
24 class_exists(ServerBag::class);
206 private $preferredFormat;
207 private $isHostValid =
true;
208 private $isForwardedValid =
true;
210 private static $trustedHeaderSet = -1;
212 private static $forwardedParams = [
213 self::HEADER_X_FORWARDED_FOR =>
'for',
214 self::HEADER_X_FORWARDED_HOST =>
'host',
215 self::HEADER_X_FORWARDED_PROTO =>
'proto',
216 self::HEADER_X_FORWARDED_PORT =>
'host',
229 self::HEADER_FORWARDED =>
'FORWARDED',
230 self::HEADER_X_FORWARDED_FOR =>
'X_FORWARDED_FOR',
231 self::HEADER_X_FORWARDED_HOST =>
'X_FORWARDED_HOST',
232 self::HEADER_X_FORWARDED_PROTO =>
'X_FORWARDED_PROTO',
233 self::HEADER_X_FORWARDED_PORT =>
'X_FORWARDED_PORT',
265 $this->request =
new ParameterBag(
$request);
266 $this->query =
new ParameterBag(
$query);
268 $this->cookies =
new ParameterBag(
$cookies);
269 $this->files =
new FileBag(
$files);
270 $this->server =
new ServerBag(
$server);
271 $this->headers =
new HeaderBag($this->server->getHeaders());
274 $this->languages =
null;
275 $this->charsets =
null;
276 $this->encodings =
null;
277 $this->acceptableContentTypes =
null;
278 $this->pathInfo =
null;
279 $this->requestUri =
null;
280 $this->baseUrl =
null;
281 $this->basePath =
null;
282 $this->method =
null;
293 $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
295 if (0 === strpos(
$request->headers->get(
'CONTENT_TYPE'),
'application/x-www-form-urlencoded')
296 && \in_array(strtoupper(
$request->server->get(
'REQUEST_METHOD',
'GET')), [
'PUT',
'DELETE',
'PATCH'])
298 parse_str(
$request->getContent(), $data);
299 $request->request =
new ParameterBag($data);
324 'SERVER_NAME' =>
'localhost',
326 'HTTP_HOST' =>
'localhost',
327 'HTTP_USER_AGENT' =>
'Symfony',
328 'HTTP_ACCEPT' =>
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
329 'HTTP_ACCEPT_LANGUAGE' =>
'en-us,en;q=0.5',
330 'HTTP_ACCEPT_CHARSET' =>
'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
331 'REMOTE_ADDR' =>
'127.0.0.1',
333 'SCRIPT_FILENAME' =>
'',
334 'SERVER_PROTOCOL' =>
'HTTP/1.1',
335 'REQUEST_TIME' => time(),
341 $components = parse_url($uri);
342 if (isset($components[
'host'])) {
343 $server[
'SERVER_NAME'] = $components[
'host'];
344 $server[
'HTTP_HOST'] = $components[
'host'];
347 if (isset($components[
'scheme'])) {
348 if (
'https' === $components[
'scheme']) {
357 if (isset($components[
'port'])) {
358 $server[
'SERVER_PORT'] = $components[
'port'];
359 $server[
'HTTP_HOST'] .=
':'.$components[
'port'];
362 if (isset($components[
'user'])) {
363 $server[
'PHP_AUTH_USER'] = $components[
'user'];
366 if (isset($components[
'pass'])) {
367 $server[
'PHP_AUTH_PW'] = $components[
'pass'];
370 if (!isset($components[
'path'])) {
371 $components[
'path'] =
'/';
378 if (!isset(
$server[
'CONTENT_TYPE'])) {
379 $server[
'CONTENT_TYPE'] =
'application/x-www-form-urlencoded';
393 if (isset($components[
'query'])) {
394 parse_str(html_entity_decode($components[
'query']), $qs);
398 $queryString = http_build_query(
$query,
'',
'&');
401 $queryString = $components[
'query'];
404 $queryString = http_build_query(
$query,
'',
'&');
407 $server[
'REQUEST_URI'] = $components[
'path'].(
'' !== $queryString ?
'?'.$queryString :
'');
408 $server[
'QUERY_STRING'] = $queryString;
424 self::$requestFactory = $callable;
443 $dup->query =
new ParameterBag(
$query);
446 $dup->request =
new ParameterBag(
$request);
452 $dup->cookies =
new ParameterBag(
$cookies);
455 $dup->files =
new FileBag(
$files);
458 $dup->server =
new ServerBag(
$server);
459 $dup->headers =
new HeaderBag($dup->server->getHeaders());
461 $dup->languages =
null;
462 $dup->charsets =
null;
463 $dup->encodings =
null;
464 $dup->acceptableContentTypes =
null;
465 $dup->pathInfo =
null;
466 $dup->requestUri =
null;
467 $dup->baseUrl =
null;
468 $dup->basePath =
null;
472 if (!$dup->get(
'_format') && $this->get(
'_format')) {
473 $dup->attributes->set(
'_format', $this->
get(
'_format'));
476 if (!$dup->getRequestFormat(
null)) {
509 }
catch (\LogicException $e) {
510 if (\PHP_VERSION_ID >= 70400) {
514 return trigger_error($e, E_USER_ERROR);
520 foreach ($this->cookies as $k => $v) {
525 $cookieHeader =
'Cookie: '.implode(
'; ',
$cookies).
"\r\n";
529 sprintf(
'%s %s %s', $this->
getMethod(), $this->
getRequestUri(), $this->server->get(
'SERVER_PROTOCOL')).
"\r\n".
531 $cookieHeader.
"\r\n".
543 $this->server->set(
'QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(),
'',
'&')));
545 $_GET = $this->query->all();
546 $_POST = $this->request->all();
547 $_SERVER = $this->server->all();
548 $_COOKIE = $this->cookies->all();
550 foreach ($this->headers->all() as $key => $value) {
551 $key = strtoupper(str_replace(
'-',
'_', $key));
552 if (\in_array($key, [
'CONTENT_TYPE',
'CONTENT_LENGTH',
'CONTENT_MD5'],
true)) {
553 $_SERVER[$key] = implode(
', ', $value);
555 $_SERVER[
'HTTP_'.$key] = implode(
', ', $value);
559 $request = [
'g' => $_GET,
'p' => $_POST,
'c' => $_COOKIE];
561 $requestOrder = ini_get(
'request_order') ?: ini_get(
'variables_order');
562 $requestOrder = preg_replace(
'#[^cgp]#',
'', strtolower($requestOrder)) ?:
'gp';
566 foreach (str_split($requestOrder) as $order) {
570 $_REQUEST = array_merge(...$_REQUEST);
585 self::$trustedProxies = array_reduce($proxies,
function ($proxies, $proxy) {
586 if (
'REMOTE_ADDR' !== $proxy) {
588 } elseif (isset($_SERVER[
'REMOTE_ADDR'])) {
589 $proxies[] = $_SERVER[
'REMOTE_ADDR'];
594 self::$trustedHeaderSet = $trustedHeaderSet;
614 return self::$trustedHeaderSet;
626 self::$trustedHostPatterns = array_map(
function ($hostPattern) {
627 return sprintf(
'{%s}i', $hostPattern);
630 self::$trustedHosts = [];
655 if (
'' === ($qs ??
'')) {
662 return http_build_query($qs,
'',
'&', PHP_QUERY_RFC3986);
678 self::$httpMethodParameterOverride =
true;
705 public function get($key, $default =
null)
707 if ($this !== $result = $this->attributes->get($key, $this)) {
711 if ($this !== $result = $this->query->get($key, $this)) {
715 if ($this !== $result = $this->request->get($key, $this)) {
735 @trigger_error(sprintf(
'Calling "%s()" when no session has been set is deprecated since Symfony 4.1 and will throw an exception in 5.0. Use "hasSession()" instead.', __METHOD__), E_USER_DEPRECATED);
778 $this->session = $factory;
796 $ip = $this->server->get(
'REMOTE_ADDR');
802 return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip];
827 return $ipAddresses[0];
837 return $this->server->get(
'SCRIPT_NAME', $this->server->get(
'ORIG_SCRIPT_NAME',
''));
856 if (
null === $this->pathInfo) {
877 if (
null === $this->basePath) {
896 if (
null === $this->baseUrl) {
910 return $this->
isSecure() ?
'https' :
'http';
925 if ($this->
isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) {
927 } elseif ($this->
isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
929 } elseif (!$host = $this->headers->get(
'HOST')) {
930 return $this->server->get(
'SERVER_PORT');
933 if (
'[' === $host[0]) {
934 $pos = strpos($host,
':', strrpos($host,
']'));
936 $pos = strrpos($host,
':');
939 if (
false !== $pos && $port = substr($host, $pos + 1)) {
943 return 'https' === $this->
getScheme() ? 443 : 80;
953 return $this->headers->get(
'PHP_AUTH_USER');
963 return $this->headers->get(
'PHP_AUTH_PW');
977 $userinfo .=
":$pass";
995 if ((
'http' == $scheme && 80 == $port) || (
'https' == $scheme && 443 == $port)) {
999 return $this->
getHost().
':'.$port;
1009 if (
null === $this->requestUri) {
1079 if (!isset($path[0]) ||
'/' !== $path[0]) {
1088 $targetDirs = explode(
'/', substr($path, 1));
1089 array_pop($sourceDirs);
1090 $targetFile = array_pop($targetDirs);
1092 foreach ($sourceDirs as $i => $dir) {
1093 if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
1094 unset($sourceDirs[$i], $targetDirs[$i]);
1100 $targetDirs[] = $targetFile;
1101 $path = str_repeat(
'../', \count($sourceDirs)).implode(
'/', $targetDirs);
1107 return !isset($path[0]) ||
'/' === $path[0]
1108 ||
false !== ($colonPos = strpos($path,
':')) && ($colonPos < ($slashPos = strpos($path,
'/')) ||
false === $slashPos)
1109 ?
"./$path" : $path;
1122 $qs = static::normalizeQueryString($this->server->get(
'QUERY_STRING'));
1124 return '' === $qs ? null : $qs;
1139 if ($this->
isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) {
1140 return \in_array(strtolower($proto[0]), [
'https',
'on',
'ssl',
'1'],
true);
1143 $https = $this->server->get(
'HTTPS');
1145 return !empty($https) &&
'off' !== strtolower($https);
1162 if ($this->
isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
1164 } elseif (!$host = $this->headers->get(
'HOST')) {
1165 if (!$host = $this->server->get(
'SERVER_NAME')) {
1166 $host = $this->server->get(
'SERVER_ADDR',
'');
1172 $host = strtolower(preg_replace(
'/:\d+$/',
'', trim($host)));
1177 if ($host &&
'' !== preg_replace(
'/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/',
'', $host)) {
1178 if (!$this->isHostValid) {
1181 $this->isHostValid =
false;
1183 throw new SuspiciousOperationException(sprintf(
'Invalid Host "%s".', $host));
1186 if (\count(self::$trustedHostPatterns) > 0) {
1189 if (\in_array($host, self::$trustedHosts)) {
1193 foreach (self::$trustedHostPatterns as $pattern) {
1194 if (preg_match($pattern, $host)) {
1195 self::$trustedHosts[] = $host;
1201 if (!$this->isHostValid) {
1204 $this->isHostValid =
false;
1219 $this->method =
null;
1220 $this->server->set(
'REQUEST_METHOD',
$method);
1240 if (
null !== $this->method) {
1244 $this->method = strtoupper($this->server->get(
'REQUEST_METHOD',
'GET'));
1246 if (
'POST' !== $this->method) {
1250 $method = $this->headers->get(
'X-HTTP-METHOD-OVERRIDE');
1252 if (!
$method && self::$httpMethodParameterOverride) {
1253 $method = $this->request->get(
'_method', $this->query->get(
'_method',
'POST'));
1262 if (\in_array(
$method, [
'GET',
'HEAD',
'POST',
'PUT',
'DELETE',
'CONNECT',
'OPTIONS',
'PATCH',
'PURGE',
'TRACE'],
true)) {
1263 return $this->method =
$method;
1266 if (!preg_match(
'/^[A-Z]++$/D',
$method)) {
1267 throw new SuspiciousOperationException(sprintf(
'Invalid method override "%s".',
$method));
1270 return $this->method =
$method;
1282 return strtoupper($this->server->get(
'REQUEST_METHOD',
'GET'));
1294 if (
null === static::$formats) {
1295 static::initializeFormats();
1298 return isset(static::$formats[
$format]) ? static::$formats[
$format][0] :
null;
1310 if (
null === static::$formats) {
1311 static::initializeFormats();
1314 return isset(static::$formats[
$format]) ? static::$formats[
$format] : [];
1326 $canonicalMimeType =
null;
1327 if (
false !== $pos = strpos($mimeType,
';')) {
1328 $canonicalMimeType = trim(substr($mimeType, 0, $pos));
1331 if (
null === static::$formats) {
1332 static::initializeFormats();
1335 foreach (static::$formats as
$format => $mimeTypes) {
1336 if (\in_array($mimeType, (array) $mimeTypes)) {
1339 if (
null !== $canonicalMimeType && \in_array($canonicalMimeType, (array) $mimeTypes)) {
1355 if (
null === static::$formats) {
1356 static::initializeFormats();
1359 static::$formats[
$format] = \is_array($mimeTypes) ? $mimeTypes : [$mimeTypes];
1379 if (
null === $this->format) {
1380 $this->format = $this->attributes->get(
'_format');
1403 return $this->
getFormat($this->headers->get(
'CONTENT_TYPE'));
1413 $this->defaultLocale =
$locale;
1415 if (
null === $this->locale) {
1416 $this->setPhpDefaultLocale(
$locale);
1437 $this->setPhpDefaultLocale($this->locale =
$locale);
1447 return null === $this->locale ? $this->defaultLocale :
$this->locale;
1471 if (\func_num_args() > 0) {
1472 @trigger_error(sprintf(
'Passing arguments to "%s()" has been deprecated since Symfony 4.4; use "%s::isMethodCacheable()" to check if the method is cacheable instead.', __METHOD__, __CLASS__), E_USER_DEPRECATED);
1475 return \in_array($this->
getMethod(), [
'GET',
'HEAD',
'OPTIONS',
'TRACE']);
1485 return \in_array($this->
getMethod(), [
'HEAD',
'GET',
'PUT',
'DELETE',
'TRACE',
'OPTIONS',
'PURGE']);
1497 return \in_array($this->
getMethod(), [
'GET',
'HEAD']);
1514 preg_match(
'~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get(
'Via'), $matches);
1517 return 'HTTP/'.$matches[2];
1521 return $this->server->get(
'SERVER_PROTOCOL');
1533 public function getContent($asResource =
false)
1535 $currentContentIsResource = \is_resource($this->content);
1537 if (
true === $asResource) {
1538 if ($currentContentIsResource) {
1539 rewind($this->content);
1545 if (\is_string($this->content)) {
1546 $resource = fopen(
'php://temp',
'r+');
1547 fwrite($resource, $this->content);
1553 $this->content =
false;
1555 return fopen(
'php://input',
'rb');
1558 if ($currentContentIsResource) {
1559 rewind($this->content);
1561 return stream_get_contents($this->content);
1564 if (
null === $this->content ||
false === $this->content) {
1565 $this->content = file_get_contents(
'php://input');
1578 return preg_split(
'/\s*,\s*/', $this->headers->get(
'if_none_match'),
null, PREG_SPLIT_NO_EMPTY);
1586 return $this->headers->hasCacheControlDirective(
'no-cache') ||
'no-cache' == $this->headers->get(
'Pragma');
1599 if (
null !== $this->preferredFormat ||
null !== $this->preferredFormat = $this->
getRequestFormat(
null)) {
1600 return $this->preferredFormat;
1604 if ($this->preferredFormat = $this->
getFormat($mimeType)) {
1605 return $this->preferredFormat;
1623 if (empty($locales)) {
1624 return isset($preferredLanguages[0]) ? $preferredLanguages[0] :
null;
1627 if (!$preferredLanguages) {
1631 $extendedPreferredLanguages = [];
1632 foreach ($preferredLanguages as $language) {
1633 $extendedPreferredLanguages[] = $language;
1634 if (
false !== $position = strpos($language,
'_')) {
1635 $superLanguage = substr($language, 0, $position);
1636 if (!\in_array($superLanguage, $preferredLanguages)) {
1637 $extendedPreferredLanguages[] = $superLanguage;
1642 $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
1644 return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
1654 if (
null !== $this->languages) {
1659 $this->languages = [];
1660 foreach (
$languages as $lang => $acceptHeaderItem) {
1661 if (
false !== strpos($lang,
'-')) {
1662 $codes = explode(
'-', $lang);
1663 if (
'i' === $codes[0]) {
1667 if (\count($codes) > 1) {
1671 for ($i = 0, $max = \count($codes); $i < $max; ++$i) {
1673 $lang = strtolower($codes[0]);
1675 $lang .=
'_'.strtoupper($codes[$i]);
1681 $this->languages[] = $lang;
1694 if (
null !== $this->charsets) {
1708 if (
null !== $this->encodings) {
1722 if (
null !== $this->acceptableContentTypes) {
1741 return 'XMLHttpRequest' == $this->headers->get(
'X-Requested-With');
1756 if (
'1' == $this->server->get(
'IIS_WasUrlRewritten') &&
'' != $this->server->get(
'UNENCODED_URL')) {
1759 $this->server->remove(
'UNENCODED_URL');
1760 $this->server->remove(
'IIS_WasUrlRewritten');
1761 } elseif ($this->server->has(
'REQUEST_URI')) {
1774 if (isset($uriComponents[
'path'])) {
1778 if (isset($uriComponents[
'query'])) {
1782 } elseif ($this->server->has(
'ORIG_PATH_INFO')) {
1784 $requestUri = $this->server->get(
'ORIG_PATH_INFO');
1785 if (
'' != $this->server->get(
'QUERY_STRING')) {
1788 $this->server->remove(
'ORIG_PATH_INFO');
1804 $filename = basename($this->server->get(
'SCRIPT_FILENAME'));
1806 if (basename($this->server->get(
'SCRIPT_NAME')) === $filename) {
1807 $baseUrl = $this->server->get(
'SCRIPT_NAME');
1808 } elseif (basename($this->server->get(
'PHP_SELF')) === $filename) {
1809 $baseUrl = $this->server->get(
'PHP_SELF');
1810 } elseif (basename($this->server->get(
'ORIG_SCRIPT_NAME')) === $filename) {
1811 $baseUrl = $this->server->get(
'ORIG_SCRIPT_NAME');
1815 $path = $this->server->get(
'PHP_SELF',
'');
1816 $file = $this->server->get(
'SCRIPT_FILENAME',
'');
1817 $segs = explode(
'/', trim($file,
'/'));
1818 $segs = array_reverse($segs);
1820 $last = \count($segs);
1823 $seg = $segs[$index];
1826 }
while ($last > $index && (
false !== $pos = strpos($path,
$baseUrl)) && 0 != $pos);
1840 if (
$baseUrl &&
null !== $prefix = $this->getUrlencodedPrefix(
$requestUri, rtrim(\dirname(
$baseUrl),
'/'.\DIRECTORY_SEPARATOR).
'/')) {
1842 return rtrim($prefix,
'/'.\DIRECTORY_SEPARATOR);
1847 $truncatedRequestUri = substr(
$requestUri, 0, $pos);
1851 if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
1863 return rtrim(
$baseUrl,
'/'.\DIRECTORY_SEPARATOR);
1878 $filename = basename($this->server->get(
'SCRIPT_FILENAME'));
1879 if (basename(
$baseUrl) === $filename) {
1885 if (
'\\' === \DIRECTORY_SEPARATOR) {
1929 static::$formats = [
1930 'html' => [
'text/html',
'application/xhtml+xml'],
1931 'txt' => [
'text/plain'],
1932 'js' => [
'application/javascript',
'application/x-javascript',
'text/javascript'],
1933 'css' => [
'text/css'],
1934 'json' => [
'application/json',
'application/x-json'],
1935 'jsonld' => [
'application/ld+json'],
1936 'xml' => [
'text/xml',
'application/xml',
'application/x-xml'],
1937 'rdf' => [
'application/rdf+xml'],
1938 'atom' => [
'application/atom+xml'],
1939 'rss' => [
'application/rss+xml'],
1940 'form' => [
'application/x-www-form-urlencoded'],
1944 private function setPhpDefaultLocale(
string $locale): void
1950 if (class_exists(
'Locale',
false)) {
1953 }
catch (\Exception $e) {
1961 private function getUrlencodedPrefix(
string $string,
string $prefix): ?string
1963 if (0 !== strpos(rawurldecode($string), $prefix)) {
1967 $len = \strlen($prefix);
1969 if (preg_match(sprintf(
'#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
1978 if (self::$requestFactory) {
1982 throw new \LogicException(
'The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
2001 return self::$trustedProxies &&
IpUtils::checkIp($this->server->get(
'REMOTE_ADDR'), self::$trustedProxies);
2004 private function getTrustedValues(
int $type,
string $ip =
null): array
2007 $forwardedValues = [];
2009 if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::$trustedHeaders[$type])) {
2010 foreach (explode(
',', $this->headers->get(self::$trustedHeaders[$type])) as $v) {
2011 $clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ?
'0.0.0.0:' :
'').trim($v);
2015 if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
2016 $forwarded = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
2018 $forwardedValues = [];
2019 $param = self::$forwardedParams[$type];
2020 foreach ($parts as $subParts) {
2024 if (self::HEADER_X_FORWARDED_PORT === $type) {
2025 if (
']' === substr($v, -1) ||
false === $v = strrchr($v,
':')) {
2026 $v = $this->
isSecure() ?
':443' :
':80';
2030 $forwardedValues[] = $v;
2035 $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
2036 $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
2039 if ($forwardedValues === $clientValues || !$clientValues) {
2040 return $forwardedValues;
2043 if (!$forwardedValues) {
2044 return $clientValues;
2047 if (!$this->isForwardedValid) {
2048 return null !== $ip ? [
'0.0.0.0', $ip] : [];
2050 $this->isForwardedValid =
false;
2052 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]));
2055 private function normalizeAndFilterClientIps(array $clientIps,
string $ip): array
2061 $firstTrustedIp =
null;
2063 foreach ($clientIps as $key => $clientIp) {
2064 if (strpos($clientIp,
'.')) {
2067 $i = strpos($clientIp,
':');
2069 $clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
2071 } elseif (0 === strpos($clientIp,
'[')) {
2073 $i = strpos($clientIp,
']', 1);
2074 $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
2077 if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
2078 unset($clientIps[$key]);
2084 unset($clientIps[$key]);
2087 if (
null === $firstTrustedIp) {
2088 $firstTrustedIp = $clientIp;
2094 return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];