Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Request.php

Zuletzt modifiziert: 01.05.2026, 11:26 - Dateigröße: 69.82 KiB


 0001  <?php
 0002   
 0003  /*
 0004   * This file is part of the Symfony package.
 0005   *
 0006   * (c) Fabien Potencier <fabien@symfony.com>
 0007   *
 0008   * For the full copyright and license information, please view the LICENSE
 0009   * file that was distributed with this source code.
 0010   */
 0011   
 0012  namespace Symfony\Component\HttpFoundation;
 0013   
 0014  use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
 0015  use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
 0016  use Symfony\Component\HttpFoundation\Session\SessionInterface;
 0017   
 0018  /**
 0019   * Request represents an HTTP request.
 0020   *
 0021   * The methods dealing with URL accept / return a raw path (% encoded):
 0022   *   * getBasePath
 0023   *   * getBaseUrl
 0024   *   * getPathInfo
 0025   *   * getRequestUri
 0026   *   * getUri
 0027   *   * getUriForPath
 0028   *
 0029   * @author Fabien Potencier <fabien@symfony.com>
 0030   */
 0031  class Request
 0032  {
 0033      const HEADER_FORWARDED = 0b00001; // When using RFC 7239
 0034      const HEADER_X_FORWARDED_FOR = 0b00010;
 0035      const HEADER_X_FORWARDED_HOST = 0b00100;
 0036      const HEADER_X_FORWARDED_PROTO = 0b01000;
 0037      const HEADER_X_FORWARDED_PORT = 0b10000;
 0038      const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers
 0039      const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host
 0040   
 0041      /** @deprecated since version 3.3, to be removed in 4.0 */
 0042      const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR;
 0043      /** @deprecated since version 3.3, to be removed in 4.0 */
 0044      const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST;
 0045      /** @deprecated since version 3.3, to be removed in 4.0 */
 0046      const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO;
 0047      /** @deprecated since version 3.3, to be removed in 4.0 */
 0048      const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT;
 0049   
 0050      const METHOD_HEAD = 'HEAD';
 0051      const METHOD_GET = 'GET';
 0052      const METHOD_POST = 'POST';
 0053      const METHOD_PUT = 'PUT';
 0054      const METHOD_PATCH = 'PATCH';
 0055      const METHOD_DELETE = 'DELETE';
 0056      const METHOD_PURGE = 'PURGE';
 0057      const METHOD_OPTIONS = 'OPTIONS';
 0058      const METHOD_TRACE = 'TRACE';
 0059      const METHOD_CONNECT = 'CONNECT';
 0060   
 0061      /**
 0062       * @var string[]
 0063       */
 0064      protected static $trustedProxies = [];
 0065   
 0066      /**
 0067       * @var string[]
 0068       */
 0069      protected static $trustedHostPatterns = [];
 0070   
 0071      /**
 0072       * @var string[]
 0073       */
 0074      protected static $trustedHosts = [];
 0075   
 0076      /**
 0077       * Names for headers that can be trusted when
 0078       * using trusted proxies.
 0079       *
 0080       * The FORWARDED header is the standard as of rfc7239.
 0081       *
 0082       * The other headers are non-standard, but widely used
 0083       * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
 0084       *
 0085       * @deprecated since version 3.3, to be removed in 4.0
 0086       */
 0087      protected static $trustedHeaders = [
 0088          self::HEADER_FORWARDED => 'FORWARDED',
 0089          self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
 0090          self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
 0091          self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
 0092          self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
 0093      ];
 0094   
 0095      protected static $httpMethodParameterOverride = false;
 0096   
 0097      /**
 0098       * Custom parameters.
 0099       *
 0100       * @var ParameterBag
 0101       */
 0102      public $attributes;
 0103   
 0104      /**
 0105       * Request body parameters ($_POST).
 0106       *
 0107       * @var ParameterBag
 0108       */
 0109      public $request;
 0110   
 0111      /**
 0112       * Query string parameters ($_GET).
 0113       *
 0114       * @var ParameterBag
 0115       */
 0116      public $query;
 0117   
 0118      /**
 0119       * Server and execution environment parameters ($_SERVER).
 0120       *
 0121       * @var ServerBag
 0122       */
 0123      public $server;
 0124   
 0125      /**
 0126       * Uploaded files ($_FILES).
 0127       *
 0128       * @var FileBag
 0129       */
 0130      public $files;
 0131   
 0132      /**
 0133       * Cookies ($_COOKIE).
 0134       *
 0135       * @var ParameterBag
 0136       */
 0137      public $cookies;
 0138   
 0139      /**
 0140       * Headers (taken from the $_SERVER).
 0141       *
 0142       * @var HeaderBag
 0143       */
 0144      public $headers;
 0145   
 0146      /**
 0147       * @var string|resource|false|null
 0148       */
 0149      protected $content;
 0150   
 0151      /**
 0152       * @var array
 0153       */
 0154      protected $languages;
 0155   
 0156      /**
 0157       * @var array
 0158       */
 0159      protected $charsets;
 0160   
 0161      /**
 0162       * @var array
 0163       */
 0164      protected $encodings;
 0165   
 0166      /**
 0167       * @var array
 0168       */
 0169      protected $acceptableContentTypes;
 0170   
 0171      /**
 0172       * @var string
 0173       */
 0174      protected $pathInfo;
 0175   
 0176      /**
 0177       * @var string
 0178       */
 0179      protected $requestUri;
 0180   
 0181      /**
 0182       * @var string
 0183       */
 0184      protected $baseUrl;
 0185   
 0186      /**
 0187       * @var string
 0188       */
 0189      protected $basePath;
 0190   
 0191      /**
 0192       * @var string
 0193       */
 0194      protected $method;
 0195   
 0196      /**
 0197       * @var string
 0198       */
 0199      protected $format;
 0200   
 0201      /**
 0202       * @var SessionInterface
 0203       */
 0204      protected $session;
 0205   
 0206      /**
 0207       * @var string
 0208       */
 0209      protected $locale;
 0210   
 0211      /**
 0212       * @var string
 0213       */
 0214      protected $defaultLocale = 'en';
 0215   
 0216      /**
 0217       * @var array
 0218       */
 0219      protected static $formats;
 0220   
 0221      protected static $requestFactory;
 0222   
 0223      private $isHostValid = true;
 0224      private $isForwardedValid = true;
 0225   
 0226      private static $trustedHeaderSet = -1;
 0227   
 0228      /** @deprecated since version 3.3, to be removed in 4.0 */
 0229      private static $trustedHeaderNames = [
 0230          self::HEADER_FORWARDED => 'FORWARDED',
 0231          self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
 0232          self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
 0233          self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
 0234          self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
 0235      ];
 0236   
 0237      private static $forwardedParams = [
 0238          self::HEADER_X_FORWARDED_FOR => 'for',
 0239          self::HEADER_X_FORWARDED_HOST => 'host',
 0240          self::HEADER_X_FORWARDED_PROTO => 'proto',
 0241          self::HEADER_X_FORWARDED_PORT => 'host',
 0242      ];
 0243   
 0244      /**
 0245       * @param array                $query      The GET parameters
 0246       * @param array                $request    The POST parameters
 0247       * @param array                $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 0248       * @param array                $cookies    The COOKIE parameters
 0249       * @param array                $files      The FILES parameters
 0250       * @param array                $server     The SERVER parameters
 0251       * @param string|resource|null $content    The raw body data
 0252       */
 0253      public function __construct(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
 0254      {
 0255          $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
 0256      }
 0257   
 0258      /**
 0259       * Sets the parameters for this request.
 0260       *
 0261       * This method also re-initializes all properties.
 0262       *
 0263       * @param array                $query      The GET parameters
 0264       * @param array                $request    The POST parameters
 0265       * @param array                $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 0266       * @param array                $cookies    The COOKIE parameters
 0267       * @param array                $files      The FILES parameters
 0268       * @param array                $server     The SERVER parameters
 0269       * @param string|resource|null $content    The raw body data
 0270       */
 0271      public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
 0272      {
 0273          $this->request = new ParameterBag($request);
 0274          $this->query = new ParameterBag($query);
 0275          $this->attributes = new ParameterBag($attributes);
 0276          $this->cookies = new ParameterBag($cookies);
 0277          $this->files = new FileBag($files);
 0278          $this->server = new ServerBag($server);
 0279          $this->headers = new HeaderBag($this->server->getHeaders());
 0280   
 0281          $this->content = $content;
 0282          $this->languages = null;
 0283          $this->charsets = null;
 0284          $this->encodings = null;
 0285          $this->acceptableContentTypes = null;
 0286          $this->pathInfo = null;
 0287          $this->requestUri = null;
 0288          $this->baseUrl = null;
 0289          $this->basePath = null;
 0290          $this->method = null;
 0291          $this->format = null;
 0292      }
 0293   
 0294      /**
 0295       * Creates a new request with values from PHP's super globals.
 0296       *
 0297       * @return static
 0298       */
 0299      public static function createFromGlobals()
 0300      {
 0301          // With the php's bug #66606, the php's built-in web server
 0302          // stores the Content-Type and Content-Length header values in
 0303          // HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields.
 0304          $server = $_SERVER;
 0305          if ('cli-server' === \PHP_SAPI) {
 0306              if (\array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
 0307                  $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
 0308              }
 0309              if (\array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
 0310                  $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
 0311              }
 0312          }
 0313   
 0314          $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $server);
 0315   
 0316          if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
 0317              && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])
 0318          ) {
 0319              parse_str($request->getContent(), $data);
 0320              $request->request = new ParameterBag($data);
 0321          }
 0322   
 0323          return $request;
 0324      }
 0325   
 0326      /**
 0327       * Creates a Request based on a given URI and configuration.
 0328       *
 0329       * The information contained in the URI always take precedence
 0330       * over the other information (server and parameters).
 0331       *
 0332       * @param string               $uri        The URI
 0333       * @param string               $method     The HTTP method
 0334       * @param array                $parameters The query (GET) or request (POST) parameters
 0335       * @param array                $cookies    The request cookies ($_COOKIE)
 0336       * @param array                $files      The request files ($_FILES)
 0337       * @param array                $server     The server parameters ($_SERVER)
 0338       * @param string|resource|null $content    The raw body data
 0339       *
 0340       * @return static
 0341       */
 0342      public static function create($uri, $method = 'GET', $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
 0343      {
 0344          $server = array_replace([
 0345              'SERVER_NAME' => 'localhost',
 0346              'SERVER_PORT' => 80,
 0347              'HTTP_HOST' => 'localhost',
 0348              'HTTP_USER_AGENT' => 'Symfony/3.X',
 0349              'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 0350              'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
 0351              'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
 0352              'REMOTE_ADDR' => '127.0.0.1',
 0353              'SCRIPT_NAME' => '',
 0354              'SCRIPT_FILENAME' => '',
 0355              'SERVER_PROTOCOL' => 'HTTP/1.1',
 0356              'REQUEST_TIME' => time(),
 0357          ], $server);
 0358   
 0359          $server['PATH_INFO'] = '';
 0360          $server['REQUEST_METHOD'] = strtoupper($method);
 0361   
 0362          $components = parse_url($uri);
 0363          if (isset($components['host'])) {
 0364              $server['SERVER_NAME'] = $components['host'];
 0365              $server['HTTP_HOST'] = $components['host'];
 0366          }
 0367   
 0368          if (isset($components['scheme'])) {
 0369              if ('https' === $components['scheme']) {
 0370                  $server['HTTPS'] = 'on';
 0371                  $server['SERVER_PORT'] = 443;
 0372              } else {
 0373                  unset($server['HTTPS']);
 0374                  $server['SERVER_PORT'] = 80;
 0375              }
 0376          }
 0377   
 0378          if (isset($components['port'])) {
 0379              $server['SERVER_PORT'] = $components['port'];
 0380              $server['HTTP_HOST'] .= ':'.$components['port'];
 0381          }
 0382   
 0383          if (isset($components['user'])) {
 0384              $server['PHP_AUTH_USER'] = $components['user'];
 0385          }
 0386   
 0387          if (isset($components['pass'])) {
 0388              $server['PHP_AUTH_PW'] = $components['pass'];
 0389          }
 0390   
 0391          if (!isset($components['path'])) {
 0392              $components['path'] = '/';
 0393          }
 0394   
 0395          switch (strtoupper($method)) {
 0396              case 'POST':
 0397              case 'PUT':
 0398              case 'DELETE':
 0399                  if (!isset($server['CONTENT_TYPE'])) {
 0400                      $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
 0401                  }
 0402                  // no break
 0403              case 'PATCH':
 0404                  $request = $parameters;
 0405                  $query = [];
 0406                  break;
 0407              default:
 0408                  $request = [];
 0409                  $query = $parameters;
 0410                  break;
 0411          }
 0412   
 0413          $queryString = '';
 0414          if (isset($components['query'])) {
 0415              parse_str(html_entity_decode($components['query']), $qs);
 0416   
 0417              if ($query) {
 0418                  $query = array_replace($qs, $query);
 0419                  $queryString = http_build_query($query, '', '&');
 0420              } else {
 0421                  $query = $qs;
 0422                  $queryString = $components['query'];
 0423              }
 0424          } elseif ($query) {
 0425              $queryString = http_build_query($query, '', '&');
 0426          }
 0427   
 0428          $server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
 0429          $server['QUERY_STRING'] = $queryString;
 0430   
 0431          return self::createRequestFromFactory($query, $request, [], $cookies, $files, $server, $content);
 0432      }
 0433   
 0434      /**
 0435       * Sets a callable able to create a Request instance.
 0436       *
 0437       * This is mainly useful when you need to override the Request class
 0438       * to keep BC with an existing system. It should not be used for any
 0439       * other purpose.
 0440       *
 0441       * @param callable|null $callable A PHP callable
 0442       */
 0443      public static function setFactory($callable)
 0444      {
 0445          self::$requestFactory = $callable;
 0446      }
 0447   
 0448      /**
 0449       * Clones a request and overrides some of its parameters.
 0450       *
 0451       * @param array $query      The GET parameters
 0452       * @param array $request    The POST parameters
 0453       * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 0454       * @param array $cookies    The COOKIE parameters
 0455       * @param array $files      The FILES parameters
 0456       * @param array $server     The SERVER parameters
 0457       *
 0458       * @return static
 0459       */
 0460      public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
 0461      {
 0462          $dup = clone $this;
 0463          if (null !== $query) {
 0464              $dup->query = new ParameterBag($query);
 0465          }
 0466          if (null !== $request) {
 0467              $dup->request = new ParameterBag($request);
 0468          }
 0469          if (null !== $attributes) {
 0470              $dup->attributes = new ParameterBag($attributes);
 0471          }
 0472          if (null !== $cookies) {
 0473              $dup->cookies = new ParameterBag($cookies);
 0474          }
 0475          if (null !== $files) {
 0476              $dup->files = new FileBag($files);
 0477          }
 0478          if (null !== $server) {
 0479              $dup->server = new ServerBag($server);
 0480              $dup->headers = new HeaderBag($dup->server->getHeaders());
 0481          }
 0482          $dup->languages = null;
 0483          $dup->charsets = null;
 0484          $dup->encodings = null;
 0485          $dup->acceptableContentTypes = null;
 0486          $dup->pathInfo = null;
 0487          $dup->requestUri = null;
 0488          $dup->baseUrl = null;
 0489          $dup->basePath = null;
 0490          $dup->method = null;
 0491          $dup->format = null;
 0492   
 0493          if (!$dup->get('_format') && $this->get('_format')) {
 0494              $dup->attributes->set('_format', $this->get('_format'));
 0495          }
 0496   
 0497          if (!$dup->getRequestFormat(null)) {
 0498              $dup->setRequestFormat($this->getRequestFormat(null));
 0499          }
 0500   
 0501          return $dup;
 0502      }
 0503   
 0504      /**
 0505       * Clones the current request.
 0506       *
 0507       * Note that the session is not cloned as duplicated requests
 0508       * are most of the time sub-requests of the main one.
 0509       */
 0510      public function __clone()
 0511      {
 0512          $this->query = clone $this->query;
 0513          $this->request = clone $this->request;
 0514          $this->attributes = clone $this->attributes;
 0515          $this->cookies = clone $this->cookies;
 0516          $this->files = clone $this->files;
 0517          $this->server = clone $this->server;
 0518          $this->headers = clone $this->headers;
 0519      }
 0520   
 0521      /**
 0522       * Returns the request as a string.
 0523       *
 0524       * @return string The request
 0525       */
 0526      public function __toString()
 0527      {
 0528          try {
 0529              $content = $this->getContent();
 0530          } catch (\LogicException $e) {
 0531              if (\PHP_VERSION_ID >= 70400) {
 0532                  throw $e;
 0533              }
 0534   
 0535              return trigger_error($e, \E_USER_ERROR);
 0536          }
 0537   
 0538          $cookieHeader = '';
 0539          $cookies = [];
 0540   
 0541          foreach ($this->cookies as $k => $v) {
 0542              $cookies[] = $k.'='.$v;
 0543          }
 0544   
 0545          if (!empty($cookies)) {
 0546              $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n";
 0547          }
 0548   
 0549          return
 0550              sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
 0551              $this->headers.
 0552              $cookieHeader."\r\n".
 0553              $content;
 0554      }
 0555   
 0556      /**
 0557       * Overrides the PHP global variables according to this request instance.
 0558       *
 0559       * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE.
 0560       * $_FILES is never overridden, see rfc1867
 0561       */
 0562      public function overrideGlobals()
 0563      {
 0564          $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), '', '&')));
 0565   
 0566          $_GET = $this->query->all();
 0567          $_POST = $this->request->all();
 0568          $_SERVER = $this->server->all();
 0569          $_COOKIE = $this->cookies->all();
 0570   
 0571          foreach ($this->headers->all() as $key => $value) {
 0572              $key = strtoupper(str_replace('-', '_', $key));
 0573              if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) {
 0574                  $_SERVER[$key] = implode(', ', $value);
 0575              } else {
 0576                  $_SERVER['HTTP_'.$key] = implode(', ', $value);
 0577              }
 0578          }
 0579   
 0580          $request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE];
 0581   
 0582          $requestOrder = ini_get('request_order') ?: ini_get('variables_order');
 0583          $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
 0584   
 0585          $_REQUEST = [];
 0586          foreach (str_split($requestOrder) as $order) {
 0587              $_REQUEST = array_merge($_REQUEST, $request[$order]);
 0588          }
 0589      }
 0590   
 0591      /**
 0592       * Sets a list of trusted proxies.
 0593       *
 0594       * You should only list the reverse proxies that you manage directly.
 0595       *
 0596       * @param array $proxies          A list of trusted proxies
 0597       * @param int   $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies
 0598       *
 0599       * @throws \InvalidArgumentException When $trustedHeaderSet is invalid
 0600       */
 0601      public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/)
 0602      {
 0603          self::$trustedProxies = $proxies;
 0604   
 0605          if (2 > \func_num_args()) {
 0606              @trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), \E_USER_DEPRECATED);
 0607   
 0608              return;
 0609          }
 0610          $trustedHeaderSet = (int) func_get_arg(1);
 0611   
 0612          foreach (self::$trustedHeaderNames as $header => $name) {
 0613              self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null;
 0614          }
 0615          self::$trustedHeaderSet = $trustedHeaderSet;
 0616      }
 0617   
 0618      /**
 0619       * Gets the list of trusted proxies.
 0620       *
 0621       * @return array An array of trusted proxies
 0622       */
 0623      public static function getTrustedProxies()
 0624      {
 0625          return self::$trustedProxies;
 0626      }
 0627   
 0628      /**
 0629       * Gets the set of trusted headers from trusted proxies.
 0630       *
 0631       * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies
 0632       */
 0633      public static function getTrustedHeaderSet()
 0634      {
 0635          return self::$trustedHeaderSet;
 0636      }
 0637   
 0638      /**
 0639       * Sets a list of trusted host patterns.
 0640       *
 0641       * You should only list the hosts you manage using regexs.
 0642       *
 0643       * @param array $hostPatterns A list of trusted host patterns
 0644       */
 0645      public static function setTrustedHosts(array $hostPatterns)
 0646      {
 0647          self::$trustedHostPatterns = array_map(function ($hostPattern) {
 0648              return sprintf('{%s}i', $hostPattern);
 0649          }, $hostPatterns);
 0650          // we need to reset trusted hosts on trusted host patterns change
 0651          self::$trustedHosts = [];
 0652      }
 0653   
 0654      /**
 0655       * Gets the list of trusted host patterns.
 0656       *
 0657       * @return array An array of trusted host patterns
 0658       */
 0659      public static function getTrustedHosts()
 0660      {
 0661          return self::$trustedHostPatterns;
 0662      }
 0663   
 0664      /**
 0665       * Sets the name for trusted headers.
 0666       *
 0667       * The following header keys are supported:
 0668       *
 0669       *  * Request::HEADER_CLIENT_IP:    defaults to X-Forwarded-For   (see getClientIp())
 0670       *  * Request::HEADER_CLIENT_HOST:  defaults to X-Forwarded-Host  (see getHost())
 0671       *  * Request::HEADER_CLIENT_PORT:  defaults to X-Forwarded-Port  (see getPort())
 0672       *  * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure())
 0673       *  * Request::HEADER_FORWARDED:    defaults to Forwarded         (see RFC 7239)
 0674       *
 0675       * Setting an empty value allows to disable the trusted header for the given key.
 0676       *
 0677       * @param string $key   The header key
 0678       * @param string $value The header name
 0679       *
 0680       * @throws \InvalidArgumentException
 0681       *
 0682       * @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
 0683       */
 0684      public static function setTrustedHeaderName($key, $value)
 0685      {
 0686          @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), \E_USER_DEPRECATED);
 0687   
 0688          if ('forwarded' === $key) {
 0689              $key = self::HEADER_FORWARDED;
 0690          } elseif ('client_ip' === $key) {
 0691              $key = self::HEADER_CLIENT_IP;
 0692          } elseif ('client_host' === $key) {
 0693              $key = self::HEADER_CLIENT_HOST;
 0694          } elseif ('client_proto' === $key) {
 0695              $key = self::HEADER_CLIENT_PROTO;
 0696          } elseif ('client_port' === $key) {
 0697              $key = self::HEADER_CLIENT_PORT;
 0698          } elseif (!\array_key_exists($key, self::$trustedHeaders)) {
 0699              throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
 0700          }
 0701   
 0702          self::$trustedHeaders[$key] = $value;
 0703   
 0704          if (null !== $value) {
 0705              self::$trustedHeaderNames[$key] = $value;
 0706              self::$trustedHeaderSet |= $key;
 0707          } else {
 0708              self::$trustedHeaderSet &= ~$key;
 0709          }
 0710      }
 0711   
 0712      /**
 0713       * Gets the trusted proxy header name.
 0714       *
 0715       * @param string $key The header key
 0716       *
 0717       * @return string The header name
 0718       *
 0719       * @throws \InvalidArgumentException
 0720       *
 0721       * @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.
 0722       */
 0723      public static function getTrustedHeaderName($key)
 0724      {
 0725          if (2 > \func_num_args() || func_get_arg(1)) {
 0726              @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), \E_USER_DEPRECATED);
 0727          }
 0728   
 0729          if (!\array_key_exists($key, self::$trustedHeaders)) {
 0730              throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key));
 0731          }
 0732   
 0733          return self::$trustedHeaders[$key];
 0734      }
 0735   
 0736      /**
 0737       * Normalizes a query string.
 0738       *
 0739       * It builds a normalized query string, where keys/value pairs are alphabetized,
 0740       * have consistent escaping and unneeded delimiters are removed.
 0741       *
 0742       * @param string $qs Query string
 0743       *
 0744       * @return string A normalized query string for the Request
 0745       */
 0746      public static function normalizeQueryString($qs)
 0747      {
 0748          if ('' == $qs) {
 0749              return '';
 0750          }
 0751   
 0752          $parts = [];
 0753          $order = [];
 0754   
 0755          foreach (explode('&', $qs) as $param) {
 0756              if ('' === $param || '=' === $param[0]) {
 0757                  // Ignore useless delimiters, e.g. "x=y&".
 0758                  // Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
 0759                  // PHP also does not include them when building _GET.
 0760                  continue;
 0761              }
 0762   
 0763              $keyValuePair = explode('=', $param, 2);
 0764   
 0765              // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
 0766              // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. This is why we use urldecode and then normalize to
 0767              // RFC 3986 with rawurlencode.
 0768              $parts[] = isset($keyValuePair[1]) ?
 0769                  rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) :
 0770                  rawurlencode(urldecode($keyValuePair[0]));
 0771              $order[] = urldecode($keyValuePair[0]);
 0772          }
 0773   
 0774          array_multisort($order, \SORT_ASC, $parts);
 0775   
 0776          return implode('&', $parts);
 0777      }
 0778   
 0779      /**
 0780       * Enables support for the _method request parameter to determine the intended HTTP method.
 0781       *
 0782       * Be warned that enabling this feature might lead to CSRF issues in your code.
 0783       * Check that you are using CSRF tokens when required.
 0784       * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered
 0785       * and used to send a "PUT" or "DELETE" request via the _method request parameter.
 0786       * If these methods are not protected against CSRF, this presents a possible vulnerability.
 0787       *
 0788       * The HTTP method can only be overridden when the real HTTP method is POST.
 0789       */
 0790      public static function enableHttpMethodParameterOverride()
 0791      {
 0792          self::$httpMethodParameterOverride = true;
 0793      }
 0794   
 0795      /**
 0796       * Checks whether support for the _method request parameter is enabled.
 0797       *
 0798       * @return bool True when the _method request parameter is enabled, false otherwise
 0799       */
 0800      public static function getHttpMethodParameterOverride()
 0801      {
 0802          return self::$httpMethodParameterOverride;
 0803      }
 0804   
 0805      /**
 0806       * Gets a "parameter" value from any bag.
 0807       *
 0808       * This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
 0809       * flexibility in controllers, it is better to explicitly get request parameters from the appropriate
 0810       * public property instead (attributes, query, request).
 0811       *
 0812       * Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY
 0813       *
 0814       * @param string $key     The key
 0815       * @param mixed  $default The default value if the parameter key does not exist
 0816       *
 0817       * @return mixed
 0818       */
 0819      public function get($key, $default = null)
 0820      {
 0821          if ($this !== $result = $this->attributes->get($key, $this)) {
 0822              return $result;
 0823          }
 0824   
 0825          if ($this !== $result = $this->query->get($key, $this)) {
 0826              return $result;
 0827          }
 0828   
 0829          if ($this !== $result = $this->request->get($key, $this)) {
 0830              return $result;
 0831          }
 0832   
 0833          return $default;
 0834      }
 0835   
 0836      /**
 0837       * Gets the Session.
 0838       *
 0839       * @return SessionInterface|null The session
 0840       */
 0841      public function getSession()
 0842      {
 0843          return $this->session;
 0844      }
 0845   
 0846      /**
 0847       * Whether the request contains a Session which was started in one of the
 0848       * previous requests.
 0849       *
 0850       * @return bool
 0851       */
 0852      public function hasPreviousSession()
 0853      {
 0854          // the check for $this->session avoids malicious users trying to fake a session cookie with proper name
 0855          return $this->hasSession() && $this->cookies->has($this->session->getName());
 0856      }
 0857   
 0858      /**
 0859       * Whether the request contains a Session object.
 0860       *
 0861       * This method does not give any information about the state of the session object,
 0862       * like whether the session is started or not. It is just a way to check if this Request
 0863       * is associated with a Session instance.
 0864       *
 0865       * @return bool true when the Request contains a Session object, false otherwise
 0866       */
 0867      public function hasSession()
 0868      {
 0869          return null !== $this->session;
 0870      }
 0871   
 0872      /**
 0873       * Sets the Session.
 0874       *
 0875       * @param SessionInterface $session The Session
 0876       */
 0877      public function setSession(SessionInterface $session)
 0878      {
 0879          $this->session = $session;
 0880      }
 0881   
 0882      /**
 0883       * Returns the client IP addresses.
 0884       *
 0885       * In the returned array the most trusted IP address is first, and the
 0886       * least trusted one last. The "real" client IP address is the last one,
 0887       * but this is also the least trusted one. Trusted proxies are stripped.
 0888       *
 0889       * Use this method carefully; you should use getClientIp() instead.
 0890       *
 0891       * @return array The client IP addresses
 0892       *
 0893       * @see getClientIp()
 0894       */
 0895      public function getClientIps()
 0896      {
 0897          $ip = $this->server->get('REMOTE_ADDR');
 0898   
 0899          if (!$this->isFromTrustedProxy()) {
 0900              return [$ip];
 0901          }
 0902   
 0903          return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: [$ip];
 0904      }
 0905   
 0906      /**
 0907       * Returns the client IP address.
 0908       *
 0909       * This method can read the client IP address from the "X-Forwarded-For" header
 0910       * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
 0911       * header value is a comma+space separated list of IP addresses, the left-most
 0912       * being the original client, and each successive proxy that passed the request
 0913       * adding the IP address where it received the request from.
 0914       *
 0915       * If your reverse proxy uses a different header name than "X-Forwarded-For",
 0916       * ("Client-Ip" for instance), configure it via the $trustedHeaderSet
 0917       * argument of the Request::setTrustedProxies() method instead.
 0918       *
 0919       * @return string|null The client IP address
 0920       *
 0921       * @see getClientIps()
 0922       * @see https://wikipedia.org/wiki/X-Forwarded-For
 0923       */
 0924      public function getClientIp()
 0925      {
 0926          $ipAddresses = $this->getClientIps();
 0927   
 0928          return $ipAddresses[0];
 0929      }
 0930   
 0931      /**
 0932       * Returns current script name.
 0933       *
 0934       * @return string
 0935       */
 0936      public function getScriptName()
 0937      {
 0938          return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', ''));
 0939      }
 0940   
 0941      /**
 0942       * Returns the path being requested relative to the executed script.
 0943       *
 0944       * The path info always starts with a /.
 0945       *
 0946       * Suppose this request is instantiated from /mysite on localhost:
 0947       *
 0948       *  * http://localhost/mysite              returns an empty string
 0949       *  * http://localhost/mysite/about        returns '/about'
 0950       *  * http://localhost/mysite/enco%20ded   returns '/enco%20ded'
 0951       *  * http://localhost/mysite/about?var=1  returns '/about'
 0952       *
 0953       * @return string The raw path (i.e. not urldecoded)
 0954       */
 0955      public function getPathInfo()
 0956      {
 0957          if (null === $this->pathInfo) {
 0958              $this->pathInfo = $this->preparePathInfo();
 0959          }
 0960   
 0961          return $this->pathInfo;
 0962      }
 0963   
 0964      /**
 0965       * Returns the root path from which this request is executed.
 0966       *
 0967       * Suppose that an index.php file instantiates this request object:
 0968       *
 0969       *  * http://localhost/index.php         returns an empty string
 0970       *  * http://localhost/index.php/page    returns an empty string
 0971       *  * http://localhost/web/index.php     returns '/web'
 0972       *  * http://localhost/we%20b/index.php  returns '/we%20b'
 0973       *
 0974       * @return string The raw path (i.e. not urldecoded)
 0975       */
 0976      public function getBasePath()
 0977      {
 0978          if (null === $this->basePath) {
 0979              $this->basePath = $this->prepareBasePath();
 0980          }
 0981   
 0982          return $this->basePath;
 0983      }
 0984   
 0985      /**
 0986       * Returns the root URL from which this request is executed.
 0987       *
 0988       * The base URL never ends with a /.
 0989       *
 0990       * This is similar to getBasePath(), except that it also includes the
 0991       * script filename (e.g. index.php) if one exists.
 0992       *
 0993       * @return string The raw URL (i.e. not urldecoded)
 0994       */
 0995      public function getBaseUrl()
 0996      {
 0997          if (null === $this->baseUrl) {
 0998              $this->baseUrl = $this->prepareBaseUrl();
 0999          }
 1000   
 1001          return $this->baseUrl;
 1002      }
 1003   
 1004      /**
 1005       * Gets the request's scheme.
 1006       *
 1007       * @return string
 1008       */
 1009      public function getScheme()
 1010      {
 1011          return $this->isSecure() ? 'https' : 'http';
 1012      }
 1013   
 1014      /**
 1015       * Returns the port on which the request is made.
 1016       *
 1017       * This method can read the client port from the "X-Forwarded-Port" header
 1018       * when trusted proxies were set via "setTrustedProxies()".
 1019       *
 1020       * The "X-Forwarded-Port" header must contain the client port.
 1021       *
 1022       * If your reverse proxy uses a different header name than "X-Forwarded-Port",
 1023       * configure it via via the $trustedHeaderSet argument of the
 1024       * Request::setTrustedProxies() method instead.
 1025       *
 1026       * @return int|string can be a string if fetched from the server bag
 1027       */
 1028      public function getPort()
 1029      {
 1030          if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) {
 1031              $host = $host[0];
 1032          } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
 1033              $host = $host[0];
 1034          } elseif (!$host = $this->headers->get('HOST')) {
 1035              return $this->server->get('SERVER_PORT');
 1036          }
 1037   
 1038          if ('[' === $host[0]) {
 1039              $pos = strpos($host, ':', strrpos($host, ']'));
 1040          } else {
 1041              $pos = strrpos($host, ':');
 1042          }
 1043   
 1044          if (false !== $pos && $port = substr($host, $pos + 1)) {
 1045              return (int) $port;
 1046          }
 1047   
 1048          return 'https' === $this->getScheme() ? 443 : 80;
 1049      }
 1050   
 1051      /**
 1052       * Returns the user.
 1053       *
 1054       * @return string|null
 1055       */
 1056      public function getUser()
 1057      {
 1058          return $this->headers->get('PHP_AUTH_USER');
 1059      }
 1060   
 1061      /**
 1062       * Returns the password.
 1063       *
 1064       * @return string|null
 1065       */
 1066      public function getPassword()
 1067      {
 1068          return $this->headers->get('PHP_AUTH_PW');
 1069      }
 1070   
 1071      /**
 1072       * Gets the user info.
 1073       *
 1074       * @return string A user name and, optionally, scheme-specific information about how to gain authorization to access the server
 1075       */
 1076      public function getUserInfo()
 1077      {
 1078          $userinfo = $this->getUser();
 1079   
 1080          $pass = $this->getPassword();
 1081          if ('' != $pass) {
 1082              $userinfo .= ":$pass";
 1083          }
 1084   
 1085          return $userinfo;
 1086      }
 1087   
 1088      /**
 1089       * Returns the HTTP host being requested.
 1090       *
 1091       * The port name will be appended to the host if it's non-standard.
 1092       *
 1093       * @return string
 1094       */
 1095      public function getHttpHost()
 1096      {
 1097          $scheme = $this->getScheme();
 1098          $port = $this->getPort();
 1099   
 1100          if (('http' == $scheme && 80 == $port) || ('https' == $scheme && 443 == $port)) {
 1101              return $this->getHost();
 1102          }
 1103   
 1104          return $this->getHost().':'.$port;
 1105      }
 1106   
 1107      /**
 1108       * Returns the requested URI (path and query string).
 1109       *
 1110       * @return string The raw URI (i.e. not URI decoded)
 1111       */
 1112      public function getRequestUri()
 1113      {
 1114          if (null === $this->requestUri) {
 1115              $this->requestUri = $this->prepareRequestUri();
 1116          }
 1117   
 1118          return $this->requestUri;
 1119      }
 1120   
 1121      /**
 1122       * Gets the scheme and HTTP host.
 1123       *
 1124       * If the URL was called with basic authentication, the user
 1125       * and the password are not added to the generated string.
 1126       *
 1127       * @return string The scheme and HTTP host
 1128       */
 1129      public function getSchemeAndHttpHost()
 1130      {
 1131          return $this->getScheme().'://'.$this->getHttpHost();
 1132      }
 1133   
 1134      /**
 1135       * Generates a normalized URI (URL) for the Request.
 1136       *
 1137       * @return string A normalized URI (URL) for the Request
 1138       *
 1139       * @see getQueryString()
 1140       */
 1141      public function getUri()
 1142      {
 1143          if (null !== $qs = $this->getQueryString()) {
 1144              $qs = '?'.$qs;
 1145          }
 1146   
 1147          return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
 1148      }
 1149   
 1150      /**
 1151       * Generates a normalized URI for the given path.
 1152       *
 1153       * @param string $path A path to use instead of the current one
 1154       *
 1155       * @return string The normalized URI for the path
 1156       */
 1157      public function getUriForPath($path)
 1158      {
 1159          return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
 1160      }
 1161   
 1162      /**
 1163       * Returns the path as relative reference from the current Request path.
 1164       *
 1165       * Only the URIs path component (no schema, host etc.) is relevant and must be given.
 1166       * Both paths must be absolute and not contain relative parts.
 1167       * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
 1168       * Furthermore, they can be used to reduce the link size in documents.
 1169       *
 1170       * Example target paths, given a base path of "/a/b/c/d":
 1171       * - "/a/b/c/d"     -> ""
 1172       * - "/a/b/c/"      -> "./"
 1173       * - "/a/b/"        -> "../"
 1174       * - "/a/b/c/other" -> "other"
 1175       * - "/a/x/y"       -> "../../x/y"
 1176       *
 1177       * @param string $path The target path
 1178       *
 1179       * @return string The relative target path
 1180       */
 1181      public function getRelativeUriForPath($path)
 1182      {
 1183          // be sure that we are dealing with an absolute path
 1184          if (!isset($path[0]) || '/' !== $path[0]) {
 1185              return $path;
 1186          }
 1187   
 1188          if ($path === $basePath = $this->getPathInfo()) {
 1189              return '';
 1190          }
 1191   
 1192          $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
 1193          $targetDirs = explode('/', substr($path, 1));
 1194          array_pop($sourceDirs);
 1195          $targetFile = array_pop($targetDirs);
 1196   
 1197          foreach ($sourceDirs as $i => $dir) {
 1198              if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
 1199                  unset($sourceDirs[$i], $targetDirs[$i]);
 1200              } else {
 1201                  break;
 1202              }
 1203          }
 1204   
 1205          $targetDirs[] = $targetFile;
 1206          $path = str_repeat('../', \count($sourceDirs)).implode('/', $targetDirs);
 1207   
 1208          // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
 1209          // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
 1210          // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
 1211          // (see https://tools.ietf.org/html/rfc3986#section-4.2).
 1212          return !isset($path[0]) || '/' === $path[0]
 1213              || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
 1214              ? "./$path" : $path;
 1215      }
 1216   
 1217      /**
 1218       * Generates the normalized query string for the Request.
 1219       *
 1220       * It builds a normalized query string, where keys/value pairs are alphabetized
 1221       * and have consistent escaping.
 1222       *
 1223       * @return string|null A normalized query string for the Request
 1224       */
 1225      public function getQueryString()
 1226      {
 1227          $qs = static::normalizeQueryString($this->server->get('QUERY_STRING'));
 1228   
 1229          return '' === $qs ? null : $qs;
 1230      }
 1231   
 1232      /**
 1233       * Checks whether the request is secure or not.
 1234       *
 1235       * This method can read the client protocol from the "X-Forwarded-Proto" header
 1236       * when trusted proxies were set via "setTrustedProxies()".
 1237       *
 1238       * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
 1239       *
 1240       * If your reverse proxy uses a different header name than "X-Forwarded-Proto"
 1241       * ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet
 1242       * argument of the Request::setTrustedProxies() method instead.
 1243       *
 1244       * @return bool
 1245       */
 1246      public function isSecure()
 1247      {
 1248          if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) {
 1249              return \in_array(strtolower($proto[0]), ['https', 'on', 'ssl', '1'], true);
 1250          }
 1251   
 1252          $https = $this->server->get('HTTPS');
 1253   
 1254          return !empty($https) && 'off' !== strtolower($https);
 1255      }
 1256   
 1257      /**
 1258       * Returns the host name.
 1259       *
 1260       * This method can read the client host name from the "X-Forwarded-Host" header
 1261       * when trusted proxies were set via "setTrustedProxies()".
 1262       *
 1263       * The "X-Forwarded-Host" header must contain the client host name.
 1264       *
 1265       * If your reverse proxy uses a different header name than "X-Forwarded-Host",
 1266       * configure it via the $trustedHeaderSet argument of the
 1267       * Request::setTrustedProxies() method instead.
 1268       *
 1269       * @return string
 1270       *
 1271       * @throws SuspiciousOperationException when the host name is invalid or not trusted
 1272       */
 1273      public function getHost()
 1274      {
 1275          if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
 1276              $host = $host[0];
 1277          } elseif (!$host = $this->headers->get('HOST')) {
 1278              if (!$host = $this->server->get('SERVER_NAME')) {
 1279                  $host = $this->server->get('SERVER_ADDR', '');
 1280              }
 1281          }
 1282   
 1283          // trim and remove port number from host
 1284          // host is lowercase as per RFC 952/2181
 1285          $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
 1286   
 1287          // as the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user)
 1288          // check that it does not contain forbidden characters (see RFC 952 and RFC 2181)
 1289          // use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
 1290          if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) {
 1291              if (!$this->isHostValid) {
 1292                  return '';
 1293              }
 1294              $this->isHostValid = false;
 1295   
 1296              throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host));
 1297          }
 1298   
 1299          if (\count(self::$trustedHostPatterns) > 0) {
 1300              // to avoid host header injection attacks, you should provide a list of trusted host patterns
 1301   
 1302              if (\in_array($host, self::$trustedHosts)) {
 1303                  return $host;
 1304              }
 1305   
 1306              foreach (self::$trustedHostPatterns as $pattern) {
 1307                  if (preg_match($pattern, $host)) {
 1308                      self::$trustedHosts[] = $host;
 1309   
 1310                      return $host;
 1311                  }
 1312              }
 1313   
 1314              if (!$this->isHostValid) {
 1315                  return '';
 1316              }
 1317              $this->isHostValid = false;
 1318   
 1319              throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host));
 1320          }
 1321   
 1322          return $host;
 1323      }
 1324   
 1325      /**
 1326       * Sets the request method.
 1327       *
 1328       * @param string $method
 1329       */
 1330      public function setMethod($method)
 1331      {
 1332          $this->method = null;
 1333          $this->server->set('REQUEST_METHOD', $method);
 1334      }
 1335   
 1336      /**
 1337       * Gets the request "intended" method.
 1338       *
 1339       * If the X-HTTP-Method-Override header is set, and if the method is a POST,
 1340       * then it is used to determine the "real" intended HTTP method.
 1341       *
 1342       * The _method request parameter can also be used to determine the HTTP method,
 1343       * but only if enableHttpMethodParameterOverride() has been called.
 1344       *
 1345       * The method is always an uppercased string.
 1346       *
 1347       * @return string The request method
 1348       *
 1349       * @see getRealMethod()
 1350       */
 1351      public function getMethod()
 1352      {
 1353          if (null !== $this->method) {
 1354              return $this->method;
 1355          }
 1356   
 1357          $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
 1358   
 1359          if ('POST' !== $this->method) {
 1360              return $this->method;
 1361          }
 1362   
 1363          $method = $this->headers->get('X-HTTP-METHOD-OVERRIDE');
 1364   
 1365          if (!$method && self::$httpMethodParameterOverride) {
 1366              $method = $this->request->get('_method', $this->query->get('_method', 'POST'));
 1367          }
 1368   
 1369          if (!\is_string($method)) {
 1370              return $this->method;
 1371          }
 1372   
 1373          $method = strtoupper($method);
 1374   
 1375          if (\in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'PATCH', 'PURGE', 'TRACE'], true)) {
 1376              return $this->method = $method;
 1377          }
 1378   
 1379          if (!preg_match('/^[A-Z]++$/D', $method)) {
 1380              throw new SuspiciousOperationException(sprintf('Invalid method override "%s".', $method));
 1381          }
 1382   
 1383          return $this->method = $method;
 1384      }
 1385   
 1386      /**
 1387       * Gets the "real" request method.
 1388       *
 1389       * @return string The request method
 1390       *
 1391       * @see getMethod()
 1392       */
 1393      public function getRealMethod()
 1394      {
 1395          return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
 1396      }
 1397   
 1398      /**
 1399       * Gets the mime type associated with the format.
 1400       *
 1401       * @param string $format The format
 1402       *
 1403       * @return string|null The associated mime type (null if not found)
 1404       */
 1405      public function getMimeType($format)
 1406      {
 1407          if (null === static::$formats) {
 1408              static::initializeFormats();
 1409          }
 1410   
 1411          return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
 1412      }
 1413   
 1414      /**
 1415       * Gets the mime types associated with the format.
 1416       *
 1417       * @param string $format The format
 1418       *
 1419       * @return array The associated mime types
 1420       */
 1421      public static function getMimeTypes($format)
 1422      {
 1423          if (null === static::$formats) {
 1424              static::initializeFormats();
 1425          }
 1426   
 1427          return isset(static::$formats[$format]) ? static::$formats[$format] : [];
 1428      }
 1429   
 1430      /**
 1431       * Gets the format associated with the mime type.
 1432       *
 1433       * @param string $mimeType The associated mime type
 1434       *
 1435       * @return string|null The format (null if not found)
 1436       */
 1437      public function getFormat($mimeType)
 1438      {
 1439          $canonicalMimeType = null;
 1440          if (false !== $pos = strpos($mimeType, ';')) {
 1441              $canonicalMimeType = trim(substr($mimeType, 0, $pos));
 1442          }
 1443   
 1444          if (null === static::$formats) {
 1445              static::initializeFormats();
 1446          }
 1447   
 1448          foreach (static::$formats as $format => $mimeTypes) {
 1449              if (\in_array($mimeType, (array) $mimeTypes)) {
 1450                  return $format;
 1451              }
 1452              if (null !== $canonicalMimeType && \in_array($canonicalMimeType, (array) $mimeTypes)) {
 1453                  return $format;
 1454              }
 1455          }
 1456   
 1457          return null;
 1458      }
 1459   
 1460      /**
 1461       * Associates a format with mime types.
 1462       *
 1463       * @param string       $format    The format
 1464       * @param string|array $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
 1465       */
 1466      public function setFormat($format, $mimeTypes)
 1467      {
 1468          if (null === static::$formats) {
 1469              static::initializeFormats();
 1470          }
 1471   
 1472          static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : [$mimeTypes];
 1473      }
 1474   
 1475      /**
 1476       * Gets the request format.
 1477       *
 1478       * Here is the process to determine the format:
 1479       *
 1480       *  * format defined by the user (with setRequestFormat())
 1481       *  * _format request attribute
 1482       *  * $default
 1483       *
 1484       * @param string|null $default The default format
 1485       *
 1486       * @return string|null The request format
 1487       */
 1488      public function getRequestFormat($default = 'html')
 1489      {
 1490          if (null === $this->format) {
 1491              $this->format = $this->attributes->get('_format');
 1492          }
 1493   
 1494          return null === $this->format ? $default : $this->format;
 1495      }
 1496   
 1497      /**
 1498       * Sets the request format.
 1499       *
 1500       * @param string $format The request format
 1501       */
 1502      public function setRequestFormat($format)
 1503      {
 1504          $this->format = $format;
 1505      }
 1506   
 1507      /**
 1508       * Gets the format associated with the request.
 1509       *
 1510       * @return string|null The format (null if no content type is present)
 1511       */
 1512      public function getContentType()
 1513      {
 1514          return $this->getFormat($this->headers->get('CONTENT_TYPE'));
 1515      }
 1516   
 1517      /**
 1518       * Sets the default locale.
 1519       *
 1520       * @param string $locale
 1521       */
 1522      public function setDefaultLocale($locale)
 1523      {
 1524          $this->defaultLocale = $locale;
 1525   
 1526          if (null === $this->locale) {
 1527              $this->setPhpDefaultLocale($locale);
 1528          }
 1529      }
 1530   
 1531      /**
 1532       * Get the default locale.
 1533       *
 1534       * @return string
 1535       */
 1536      public function getDefaultLocale()
 1537      {
 1538          return $this->defaultLocale;
 1539      }
 1540   
 1541      /**
 1542       * Sets the locale.
 1543       *
 1544       * @param string $locale
 1545       */
 1546      public function setLocale($locale)
 1547      {
 1548          $this->setPhpDefaultLocale($this->locale = $locale);
 1549      }
 1550   
 1551      /**
 1552       * Get the locale.
 1553       *
 1554       * @return string
 1555       */
 1556      public function getLocale()
 1557      {
 1558          return null === $this->locale ? $this->defaultLocale : $this->locale;
 1559      }
 1560   
 1561      /**
 1562       * Checks if the request method is of specified type.
 1563       *
 1564       * @param string $method Uppercase request method (GET, POST etc)
 1565       *
 1566       * @return bool
 1567       */
 1568      public function isMethod($method)
 1569      {
 1570          return $this->getMethod() === strtoupper($method);
 1571      }
 1572   
 1573      /**
 1574       * Checks whether or not the method is safe.
 1575       *
 1576       * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
 1577       *
 1578       * @param bool $andCacheable Adds the additional condition that the method should be cacheable. True by default.
 1579       *
 1580       * @return bool
 1581       */
 1582      public function isMethodSafe(/* $andCacheable = true */)
 1583      {
 1584          if (!\func_num_args() || func_get_arg(0)) {
 1585              // This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature)
 1586              // then setting $andCacheable to false should be deprecated in 4.1
 1587              @trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', \E_USER_DEPRECATED);
 1588   
 1589              return \in_array($this->getMethod(), ['GET', 'HEAD']);
 1590          }
 1591   
 1592          return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']);
 1593      }
 1594   
 1595      /**
 1596       * Checks whether or not the method is idempotent.
 1597       *
 1598       * @return bool
 1599       */
 1600      public function isMethodIdempotent()
 1601      {
 1602          return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE']);
 1603      }
 1604   
 1605      /**
 1606       * Checks whether the method is cacheable or not.
 1607       *
 1608       * @see https://tools.ietf.org/html/rfc7231#section-4.2.3
 1609       *
 1610       * @return bool True for GET and HEAD, false otherwise
 1611       */
 1612      public function isMethodCacheable()
 1613      {
 1614          return \in_array($this->getMethod(), ['GET', 'HEAD']);
 1615      }
 1616   
 1617      /**
 1618       * Returns the protocol version.
 1619       *
 1620       * If the application is behind a proxy, the protocol version used in the
 1621       * requests between the client and the proxy and between the proxy and the
 1622       * server might be different. This returns the former (from the "Via" header)
 1623       * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns
 1624       * the latter (from the "SERVER_PROTOCOL" server parameter).
 1625       *
 1626       * @return string
 1627       */
 1628      public function getProtocolVersion()
 1629      {
 1630          if ($this->isFromTrustedProxy()) {
 1631              preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches);
 1632   
 1633              if ($matches) {
 1634                  return 'HTTP/'.$matches[2];
 1635              }
 1636          }
 1637   
 1638          return $this->server->get('SERVER_PROTOCOL');
 1639      }
 1640   
 1641      /**
 1642       * Returns the request body content.
 1643       *
 1644       * @param bool $asResource If true, a resource will be returned
 1645       *
 1646       * @return string|resource The request body content or a resource to read the body stream
 1647       *
 1648       * @throws \LogicException
 1649       */
 1650      public function getContent($asResource = false)
 1651      {
 1652          $currentContentIsResource = \is_resource($this->content);
 1653          if (\PHP_VERSION_ID < 50600 && false === $this->content) {
 1654              throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.');
 1655          }
 1656   
 1657          if (true === $asResource) {
 1658              if ($currentContentIsResource) {
 1659                  rewind($this->content);
 1660   
 1661                  return $this->content;
 1662              }
 1663   
 1664              // Content passed in parameter (test)
 1665              if (\is_string($this->content)) {
 1666                  $resource = fopen('php://temp', 'r+');
 1667                  fwrite($resource, $this->content);
 1668                  rewind($resource);
 1669   
 1670                  return $resource;
 1671              }
 1672   
 1673              $this->content = false;
 1674   
 1675              return fopen('php://input', 'rb');
 1676          }
 1677   
 1678          if ($currentContentIsResource) {
 1679              rewind($this->content);
 1680   
 1681              return stream_get_contents($this->content);
 1682          }
 1683   
 1684          if (null === $this->content || false === $this->content) {
 1685              $this->content = file_get_contents('php://input');
 1686          }
 1687   
 1688          return $this->content;
 1689      }
 1690   
 1691      /**
 1692       * Gets the Etags.
 1693       *
 1694       * @return array The entity tags
 1695       */
 1696      public function getETags()
 1697      {
 1698          return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, \PREG_SPLIT_NO_EMPTY);
 1699      }
 1700   
 1701      /**
 1702       * @return bool
 1703       */
 1704      public function isNoCache()
 1705      {
 1706          return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma');
 1707      }
 1708   
 1709      /**
 1710       * Returns the preferred language.
 1711       *
 1712       * @param array $locales An array of ordered available locales
 1713       *
 1714       * @return string|null The preferred locale
 1715       */
 1716      public function getPreferredLanguage(array $locales = null)
 1717      {
 1718          $preferredLanguages = $this->getLanguages();
 1719   
 1720          if (empty($locales)) {
 1721              return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null;
 1722          }
 1723   
 1724          if (!$preferredLanguages) {
 1725              return $locales[0];
 1726          }
 1727   
 1728          $extendedPreferredLanguages = [];
 1729          foreach ($preferredLanguages as $language) {
 1730              $extendedPreferredLanguages[] = $language;
 1731              if (false !== $position = strpos($language, '_')) {
 1732                  $superLanguage = substr($language, 0, $position);
 1733                  if (!\in_array($superLanguage, $preferredLanguages)) {
 1734                      $extendedPreferredLanguages[] = $superLanguage;
 1735                  }
 1736              }
 1737          }
 1738   
 1739          $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
 1740   
 1741          return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
 1742      }
 1743   
 1744      /**
 1745       * Gets a list of languages acceptable by the client browser.
 1746       *
 1747       * @return array Languages ordered in the user browser preferences
 1748       */
 1749      public function getLanguages()
 1750      {
 1751          if (null !== $this->languages) {
 1752              return $this->languages;
 1753          }
 1754   
 1755          $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
 1756          $this->languages = [];
 1757          foreach ($languages as $lang => $acceptHeaderItem) {
 1758              if (false !== strpos($lang, '-')) {
 1759                  $codes = explode('-', $lang);
 1760                  if ('i' === $codes[0]) {
 1761                      // Language not listed in ISO 639 that are not variants
 1762                      // of any listed language, which can be registered with the
 1763                      // i-prefix, such as i-cherokee
 1764                      if (\count($codes) > 1) {
 1765                          $lang = $codes[1];
 1766                      }
 1767                  } else {
 1768                      for ($i = 0, $max = \count($codes); $i < $max; ++$i) {
 1769                          if (0 === $i) {
 1770                              $lang = strtolower($codes[0]);
 1771                          } else {
 1772                              $lang .= '_'.strtoupper($codes[$i]);
 1773                          }
 1774                      }
 1775                  }
 1776              }
 1777   
 1778              $this->languages[] = $lang;
 1779          }
 1780   
 1781          return $this->languages;
 1782      }
 1783   
 1784      /**
 1785       * Gets a list of charsets acceptable by the client browser.
 1786       *
 1787       * @return array List of charsets in preferable order
 1788       */
 1789      public function getCharsets()
 1790      {
 1791          if (null !== $this->charsets) {
 1792              return $this->charsets;
 1793          }
 1794   
 1795          return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
 1796      }
 1797   
 1798      /**
 1799       * Gets a list of encodings acceptable by the client browser.
 1800       *
 1801       * @return array List of encodings in preferable order
 1802       */
 1803      public function getEncodings()
 1804      {
 1805          if (null !== $this->encodings) {
 1806              return $this->encodings;
 1807          }
 1808   
 1809          return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all());
 1810      }
 1811   
 1812      /**
 1813       * Gets a list of content types acceptable by the client browser.
 1814       *
 1815       * @return array List of content types in preferable order
 1816       */
 1817      public function getAcceptableContentTypes()
 1818      {
 1819          if (null !== $this->acceptableContentTypes) {
 1820              return $this->acceptableContentTypes;
 1821          }
 1822   
 1823          return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
 1824      }
 1825   
 1826      /**
 1827       * Returns true if the request is a XMLHttpRequest.
 1828       *
 1829       * It works if your JavaScript library sets an X-Requested-With HTTP header.
 1830       * It is known to work with common JavaScript frameworks:
 1831       *
 1832       * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
 1833       *
 1834       * @return bool true if the request is an XMLHttpRequest, false otherwise
 1835       */
 1836      public function isXmlHttpRequest()
 1837      {
 1838          return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
 1839      }
 1840   
 1841      /*
 1842       * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
 1843       *
 1844       * Code subject to the new BSD license (https://framework.zend.com/license).
 1845       *
 1846       * Copyright (c) 2005-2010 Zend Technologies USA Inc. (https://www.zend.com/)
 1847       */
 1848   
 1849      protected function prepareRequestUri()
 1850      {
 1851          $requestUri = '';
 1852   
 1853          if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
 1854              // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
 1855              $requestUri = $this->server->get('UNENCODED_URL');
 1856              $this->server->remove('UNENCODED_URL');
 1857              $this->server->remove('IIS_WasUrlRewritten');
 1858          } elseif ($this->server->has('REQUEST_URI')) {
 1859              $requestUri = $this->server->get('REQUEST_URI');
 1860   
 1861              if ('' !== $requestUri && '/' === $requestUri[0]) {
 1862                  // To only use path and query remove the fragment.
 1863                  if (false !== $pos = strpos($requestUri, '#')) {
 1864                      $requestUri = substr($requestUri, 0, $pos);
 1865                  }
 1866              } else {
 1867                  // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path,
 1868                  // only use URL path.
 1869                  $uriComponents = parse_url($requestUri);
 1870   
 1871                  if (isset($uriComponents['path'])) {
 1872                      $requestUri = $uriComponents['path'];
 1873                  }
 1874   
 1875                  if (isset($uriComponents['query'])) {
 1876                      $requestUri .= '?'.$uriComponents['query'];
 1877                  }
 1878              }
 1879          } elseif ($this->server->has('ORIG_PATH_INFO')) {
 1880              // IIS 5.0, PHP as CGI
 1881              $requestUri = $this->server->get('ORIG_PATH_INFO');
 1882              if ('' != $this->server->get('QUERY_STRING')) {
 1883                  $requestUri .= '?'.$this->server->get('QUERY_STRING');
 1884              }
 1885              $this->server->remove('ORIG_PATH_INFO');
 1886          }
 1887   
 1888          // normalize the request URI to ease creating sub-requests from this request
 1889          $this->server->set('REQUEST_URI', $requestUri);
 1890   
 1891          return $requestUri;
 1892      }
 1893   
 1894      /**
 1895       * Prepares the base URL.
 1896       *
 1897       * @return string
 1898       */
 1899      protected function prepareBaseUrl()
 1900      {
 1901          $filename = basename($this->server->get('SCRIPT_FILENAME'));
 1902   
 1903          if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
 1904              $baseUrl = $this->server->get('SCRIPT_NAME');
 1905          } elseif (basename($this->server->get('PHP_SELF')) === $filename) {
 1906              $baseUrl = $this->server->get('PHP_SELF');
 1907          } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
 1908              $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility
 1909          } else {
 1910              // Backtrack up the script_filename to find the portion matching
 1911              // php_self
 1912              $path = $this->server->get('PHP_SELF', '');
 1913              $file = $this->server->get('SCRIPT_FILENAME', '');
 1914              $segs = explode('/', trim($file, '/'));
 1915              $segs = array_reverse($segs);
 1916              $index = 0;
 1917              $last = \count($segs);
 1918              $baseUrl = '';
 1919              do {
 1920                  $seg = $segs[$index];
 1921                  $baseUrl = '/'.$seg.$baseUrl;
 1922                  ++$index;
 1923              } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos);
 1924          }
 1925   
 1926          // Does the baseUrl have anything in common with the request_uri?
 1927          $requestUri = $this->getRequestUri();
 1928          if ('' !== $requestUri && '/' !== $requestUri[0]) {
 1929              $requestUri = '/'.$requestUri;
 1930          }
 1931   
 1932          if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
 1933              // full $baseUrl matches
 1934              return $prefix;
 1935          }
 1936   
 1937          if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) {
 1938              // directory portion of $baseUrl matches
 1939              return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR);
 1940          }
 1941   
 1942          $truncatedRequestUri = $requestUri;
 1943          if (false !== $pos = strpos($requestUri, '?')) {
 1944              $truncatedRequestUri = substr($requestUri, 0, $pos);
 1945          }
 1946   
 1947          $basename = basename($baseUrl);
 1948          if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
 1949              // no match whatsoever; set it blank
 1950              return '';
 1951          }
 1952   
 1953          // If using mod_rewrite or ISAPI_Rewrite strip the script filename
 1954          // out of baseUrl. $pos !== 0 makes sure it is not matching a value
 1955          // from PATH_INFO or QUERY_STRING
 1956          if (\strlen($requestUri) >= \strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) {
 1957              $baseUrl = substr($requestUri, 0, $pos + \strlen($baseUrl));
 1958          }
 1959   
 1960          return rtrim($baseUrl, '/'.\DIRECTORY_SEPARATOR);
 1961      }
 1962   
 1963      /**
 1964       * Prepares the base path.
 1965       *
 1966       * @return string base path
 1967       */
 1968      protected function prepareBasePath()
 1969      {
 1970          $baseUrl = $this->getBaseUrl();
 1971          if (empty($baseUrl)) {
 1972              return '';
 1973          }
 1974   
 1975          $filename = basename($this->server->get('SCRIPT_FILENAME'));
 1976          if (basename($baseUrl) === $filename) {
 1977              $basePath = \dirname($baseUrl);
 1978          } else {
 1979              $basePath = $baseUrl;
 1980          }
 1981   
 1982          if ('\\' === \DIRECTORY_SEPARATOR) {
 1983              $basePath = str_replace('\\', '/', $basePath);
 1984          }
 1985   
 1986          return rtrim($basePath, '/');
 1987      }
 1988   
 1989      /**
 1990       * Prepares the path info.
 1991       *
 1992       * @return string path info
 1993       */
 1994      protected function preparePathInfo()
 1995      {
 1996          if (null === ($requestUri = $this->getRequestUri())) {
 1997              return '/';
 1998          }
 1999   
 2000          // Remove the query string from REQUEST_URI
 2001          if (false !== $pos = strpos($requestUri, '?')) {
 2002              $requestUri = substr($requestUri, 0, $pos);
 2003          }
 2004          if ('' !== $requestUri && '/' !== $requestUri[0]) {
 2005              $requestUri = '/'.$requestUri;
 2006          }
 2007   
 2008          if (null === ($baseUrl = $this->getBaseUrl())) {
 2009              return $requestUri;
 2010          }
 2011   
 2012          $pathInfo = substr($requestUri, \strlen($baseUrl));
 2013          if (false === $pathInfo || '' === $pathInfo) {
 2014              // If substr() returns false then PATH_INFO is set to an empty string
 2015              return '/';
 2016          }
 2017   
 2018          return (string) $pathInfo;
 2019      }
 2020   
 2021      /**
 2022       * Initializes HTTP request formats.
 2023       */
 2024      protected static function initializeFormats()
 2025      {
 2026          static::$formats = [
 2027              'html' => ['text/html', 'application/xhtml+xml'],
 2028              'txt' => ['text/plain'],
 2029              'js' => ['application/javascript', 'application/x-javascript', 'text/javascript'],
 2030              'css' => ['text/css'],
 2031              'json' => ['application/json', 'application/x-json'],
 2032              'jsonld' => ['application/ld+json'],
 2033              'xml' => ['text/xml', 'application/xml', 'application/x-xml'],
 2034              'rdf' => ['application/rdf+xml'],
 2035              'atom' => ['application/atom+xml'],
 2036              'rss' => ['application/rss+xml'],
 2037              'form' => ['application/x-www-form-urlencoded'],
 2038          ];
 2039      }
 2040   
 2041      /**
 2042       * Sets the default PHP locale.
 2043       *
 2044       * @param string $locale
 2045       */
 2046      private function setPhpDefaultLocale($locale)
 2047      {
 2048          // if either the class Locale doesn't exist, or an exception is thrown when
 2049          // setting the default locale, the intl module is not installed, and
 2050          // the call can be ignored:
 2051          try {
 2052              if (class_exists('Locale', false)) {
 2053                  \Locale::setDefault($locale);
 2054              }
 2055          } catch (\Exception $e) {
 2056          }
 2057      }
 2058   
 2059      /**
 2060       * Returns the prefix as encoded in the string when the string starts with
 2061       * the given prefix, false otherwise.
 2062       *
 2063       * @param string $string The urlencoded string
 2064       * @param string $prefix The prefix not encoded
 2065       *
 2066       * @return string|false The prefix as it is encoded in $string, or false
 2067       */
 2068      private function getUrlencodedPrefix($string, $prefix)
 2069      {
 2070          if (0 !== strpos(rawurldecode($string), $prefix)) {
 2071              return false;
 2072          }
 2073   
 2074          $len = \strlen($prefix);
 2075   
 2076          if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
 2077              return $match[0];
 2078          }
 2079   
 2080          return false;
 2081      }
 2082   
 2083      private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
 2084      {
 2085          if (self::$requestFactory) {
 2086              $request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
 2087   
 2088              if (!$request instanceof self) {
 2089                  throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
 2090              }
 2091   
 2092              return $request;
 2093          }
 2094   
 2095          return new static($query, $request, $attributes, $cookies, $files, $server, $content);
 2096      }
 2097   
 2098      /**
 2099       * Indicates whether this request originated from a trusted proxy.
 2100       *
 2101       * This can be useful to determine whether or not to trust the
 2102       * contents of a proxy-specific header.
 2103       *
 2104       * @return bool true if the request came from a trusted proxy, false otherwise
 2105       */
 2106      public function isFromTrustedProxy()
 2107      {
 2108          return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies);
 2109      }
 2110   
 2111      private function getTrustedValues($type, $ip = null)
 2112      {
 2113          $clientValues = [];
 2114          $forwardedValues = [];
 2115   
 2116          if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) {
 2117              foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) {
 2118                  $clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v);
 2119              }
 2120          }
 2121   
 2122          if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
 2123              $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
 2124              $forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : [];
 2125              if (self::HEADER_CLIENT_PORT === $type) {
 2126                  foreach ($forwardedValues as $k => $v) {
 2127                      if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) {
 2128                          $v = $this->isSecure() ? ':443' : ':80';
 2129                      }
 2130                      $forwardedValues[$k] = '0.0.0.0'.$v;
 2131                  }
 2132              }
 2133          }
 2134   
 2135          if (null !== $ip) {
 2136              $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
 2137              $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
 2138          }
 2139   
 2140          if ($forwardedValues === $clientValues || !$clientValues) {
 2141              return $forwardedValues;
 2142          }
 2143   
 2144          if (!$forwardedValues) {
 2145              return $clientValues;
 2146          }
 2147   
 2148          if (!$this->isForwardedValid) {
 2149              return null !== $ip ? ['0.0.0.0', $ip] : [];
 2150          }
 2151          $this->isForwardedValid = false;
 2152   
 2153          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]));
 2154      }
 2155   
 2156      private function normalizeAndFilterClientIps(array $clientIps, $ip)
 2157      {
 2158          if (!$clientIps) {
 2159              return [];
 2160          }
 2161          $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
 2162          $firstTrustedIp = null;
 2163   
 2164          foreach ($clientIps as $key => $clientIp) {
 2165              if (strpos($clientIp, '.')) {
 2166                  // Strip :port from IPv4 addresses. This is allowed in Forwarded
 2167                  // and may occur in X-Forwarded-For.
 2168                  $i = strpos($clientIp, ':');
 2169                  if ($i) {
 2170                      $clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
 2171                  }
 2172              } elseif (0 === strpos($clientIp, '[')) {
 2173                  // Strip brackets and :port from IPv6 addresses.
 2174                  $i = strpos($clientIp, ']', 1);
 2175                  $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
 2176              }
 2177   
 2178              if (!filter_var($clientIp, \FILTER_VALIDATE_IP)) {
 2179                  unset($clientIps[$key]);
 2180   
 2181                  continue;
 2182              }
 2183   
 2184              if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
 2185                  unset($clientIps[$key]);
 2186   
 2187                  // Fallback to this when the client IP falls into the range of trusted proxies
 2188                  if (null === $firstTrustedIp) {
 2189                      $firstTrustedIp = $clientIp;
 2190                  }
 2191              }
 2192          }
 2193   
 2194          // Now the IP chain contains only untrusted proxies and the client IP
 2195          return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
 2196      }
 2197  }
 2198