[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/ -> Request.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\HttpFoundation;
  13  
  14  use Symfony\Component\HttpFoundation\Session\SessionInterface;
  15  
  16  /**
  17   * Request represents an HTTP request.
  18   *
  19   * The methods dealing with URL accept / return a raw path (% encoded):
  20   *   * getBasePath
  21   *   * getBaseUrl
  22   *   * getPathInfo
  23   *   * getRequestUri
  24   *   * getUri
  25   *   * getUriForPath
  26   *
  27   * @author Fabien Potencier <fabien@symfony.com>
  28   */
  29  class Request
  30  {
  31      const HEADER_CLIENT_IP = 'client_ip';
  32      const HEADER_CLIENT_HOST = 'client_host';
  33      const HEADER_CLIENT_PROTO = 'client_proto';
  34      const HEADER_CLIENT_PORT = 'client_port';
  35  
  36      protected static $trustedProxies = array();
  37  
  38      /**
  39       * @var string[]
  40       */
  41      protected static $trustedHostPatterns = array();
  42  
  43      /**
  44       * @var string[]
  45       */
  46      protected static $trustedHosts = array();
  47  
  48      /**
  49       * Names for headers that can be trusted when
  50       * using trusted proxies.
  51       *
  52       * The default names are non-standard, but widely used
  53       * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
  54       */
  55      protected static $trustedHeaders = array(
  56          self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
  57          self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
  58          self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
  59          self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
  60      );
  61  
  62      protected static $httpMethodParameterOverride = false;
  63  
  64      /**
  65       * Custom parameters.
  66       *
  67       * @var \Symfony\Component\HttpFoundation\ParameterBag
  68       */
  69      public $attributes;
  70  
  71      /**
  72       * Request body parameters ($_POST).
  73       *
  74       * @var \Symfony\Component\HttpFoundation\ParameterBag
  75       */
  76      public $request;
  77  
  78      /**
  79       * Query string parameters ($_GET).
  80       *
  81       * @var \Symfony\Component\HttpFoundation\ParameterBag
  82       */
  83      public $query;
  84  
  85      /**
  86       * Server and execution environment parameters ($_SERVER).
  87       *
  88       * @var \Symfony\Component\HttpFoundation\ServerBag
  89       */
  90      public $server;
  91  
  92      /**
  93       * Uploaded files ($_FILES).
  94       *
  95       * @var \Symfony\Component\HttpFoundation\FileBag
  96       */
  97      public $files;
  98  
  99      /**
 100       * Cookies ($_COOKIE).
 101       *
 102       * @var \Symfony\Component\HttpFoundation\ParameterBag
 103       */
 104      public $cookies;
 105  
 106      /**
 107       * Headers (taken from the $_SERVER).
 108       *
 109       * @var \Symfony\Component\HttpFoundation\HeaderBag
 110       */
 111      public $headers;
 112  
 113      /**
 114       * @var string
 115       */
 116      protected $content;
 117  
 118      /**
 119       * @var array
 120       */
 121      protected $languages;
 122  
 123      /**
 124       * @var array
 125       */
 126      protected $charsets;
 127  
 128      /**
 129       * @var array
 130       */
 131      protected $acceptableContentTypes;
 132  
 133      /**
 134       * @var string
 135       */
 136      protected $pathInfo;
 137  
 138      /**
 139       * @var string
 140       */
 141      protected $requestUri;
 142  
 143      /**
 144       * @var string
 145       */
 146      protected $baseUrl;
 147  
 148      /**
 149       * @var string
 150       */
 151      protected $basePath;
 152  
 153      /**
 154       * @var string
 155       */
 156      protected $method;
 157  
 158      /**
 159       * @var string
 160       */
 161      protected $format;
 162  
 163      /**
 164       * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
 165       */
 166      protected $session;
 167  
 168      /**
 169       * @var string
 170       */
 171      protected $locale;
 172  
 173      /**
 174       * @var string
 175       */
 176      protected $defaultLocale = 'en';
 177  
 178      /**
 179       * @var array
 180       */
 181      protected static $formats;
 182  
 183      /**
 184       * Constructor.
 185       *
 186       * @param array           $query      The GET parameters
 187       * @param array           $request    The POST parameters
 188       * @param array           $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 189       * @param array           $cookies    The COOKIE parameters
 190       * @param array           $files      The FILES parameters
 191       * @param array           $server     The SERVER parameters
 192       * @param string|resource $content    The raw body data
 193       */
 194      public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
 195      {
 196          $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
 197      }
 198  
 199      /**
 200       * Sets the parameters for this request.
 201       *
 202       * This method also re-initializes all properties.
 203       *
 204       * @param array           $query      The GET parameters
 205       * @param array           $request    The POST parameters
 206       * @param array           $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 207       * @param array           $cookies    The COOKIE parameters
 208       * @param array           $files      The FILES parameters
 209       * @param array           $server     The SERVER parameters
 210       * @param string|resource $content    The raw body data
 211       */
 212      public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
 213      {
 214          $this->request = new ParameterBag($request);
 215          $this->query = new ParameterBag($query);
 216          $this->attributes = new ParameterBag($attributes);
 217          $this->cookies = new ParameterBag($cookies);
 218          $this->files = new FileBag($files);
 219          $this->server = new ServerBag($server);
 220          $this->headers = new HeaderBag($this->server->getHeaders());
 221  
 222          $this->content = $content;
 223          $this->languages = null;
 224          $this->charsets = null;
 225          $this->acceptableContentTypes = null;
 226          $this->pathInfo = null;
 227          $this->requestUri = null;
 228          $this->baseUrl = null;
 229          $this->basePath = null;
 230          $this->method = null;
 231          $this->format = null;
 232      }
 233  
 234      /**
 235       * Creates a new request with values from PHP's super globals.
 236       *
 237       * @return Request A new request
 238       */
 239      public static function createFromGlobals()
 240      {
 241          // With the php's bug #66606, the php's built-in web server
 242          // stores the Content-Type and Content-Length header values in
 243          // HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields.
 244          $server = $_SERVER;
 245          if ('cli-server' === PHP_SAPI) {
 246              if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
 247                  $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
 248              }
 249              if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
 250                  $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
 251              }
 252          }
 253  
 254          $request = new static($_GET, $_POST, array(), $_COOKIE, $_FILES, $server);
 255  
 256          if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
 257              && in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
 258          ) {
 259              parse_str($request->getContent(), $data);
 260              $request->request = new ParameterBag($data);
 261          }
 262  
 263          return $request;
 264      }
 265  
 266      /**
 267       * Creates a Request based on a given URI and configuration.
 268       *
 269       * The information contained in the URI always take precedence
 270       * over the other information (server and parameters).
 271       *
 272       * @param string $uri        The URI
 273       * @param string $method     The HTTP method
 274       * @param array  $parameters The query (GET) or request (POST) parameters
 275       * @param array  $cookies    The request cookies ($_COOKIE)
 276       * @param array  $files      The request files ($_FILES)
 277       * @param array  $server     The server parameters ($_SERVER)
 278       * @param string $content    The raw body data
 279       *
 280       * @return Request A Request instance
 281       */
 282      public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
 283      {
 284          $server = array_replace(array(
 285              'SERVER_NAME' => 'localhost',
 286              'SERVER_PORT' => 80,
 287              'HTTP_HOST' => 'localhost',
 288              'HTTP_USER_AGENT' => 'Symfony/2.X',
 289              'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 290              'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
 291              'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
 292              'REMOTE_ADDR' => '127.0.0.1',
 293              'SCRIPT_NAME' => '',
 294              'SCRIPT_FILENAME' => '',
 295              'SERVER_PROTOCOL' => 'HTTP/1.1',
 296              'REQUEST_TIME' => time(),
 297          ), $server);
 298  
 299          $server['PATH_INFO'] = '';
 300          $server['REQUEST_METHOD'] = strtoupper($method);
 301  
 302          $components = parse_url($uri);
 303          if (isset($components['host'])) {
 304              $server['SERVER_NAME'] = $components['host'];
 305              $server['HTTP_HOST'] = $components['host'];
 306          }
 307  
 308          if (isset($components['scheme'])) {
 309              if ('https' === $components['scheme']) {
 310                  $server['HTTPS'] = 'on';
 311                  $server['SERVER_PORT'] = 443;
 312              } else {
 313                  unset($server['HTTPS']);
 314                  $server['SERVER_PORT'] = 80;
 315              }
 316          }
 317  
 318          if (isset($components['port'])) {
 319              $server['SERVER_PORT'] = $components['port'];
 320              $server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$components['port'];
 321          }
 322  
 323          if (isset($components['user'])) {
 324              $server['PHP_AUTH_USER'] = $components['user'];
 325          }
 326  
 327          if (isset($components['pass'])) {
 328              $server['PHP_AUTH_PW'] = $components['pass'];
 329          }
 330  
 331          if (!isset($components['path'])) {
 332              $components['path'] = '/';
 333          }
 334  
 335          switch (strtoupper($method)) {
 336              case 'POST':
 337              case 'PUT':
 338              case 'DELETE':
 339                  if (!isset($server['CONTENT_TYPE'])) {
 340                      $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
 341                  }
 342                  // no break
 343              case 'PATCH':
 344                  $request = $parameters;
 345                  $query = array();
 346                  break;
 347              default:
 348                  $request = array();
 349                  $query = $parameters;
 350                  break;
 351          }
 352  
 353          $queryString = '';
 354          if (isset($components['query'])) {
 355              parse_str(html_entity_decode($components['query']), $qs);
 356  
 357              if ($query) {
 358                  $query = array_replace($qs, $query);
 359                  $queryString = http_build_query($query, '', '&');
 360              } else {
 361                  $query = $qs;
 362                  $queryString = $components['query'];
 363              }
 364          } elseif ($query) {
 365              $queryString = http_build_query($query, '', '&');
 366          }
 367  
 368          $server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
 369          $server['QUERY_STRING'] = $queryString;
 370  
 371          return new static($query, $request, array(), $cookies, $files, $server, $content);
 372      }
 373  
 374      /**
 375       * Clones a request and overrides some of its parameters.
 376       *
 377       * @param array $query      The GET parameters
 378       * @param array $request    The POST parameters
 379       * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
 380       * @param array $cookies    The COOKIE parameters
 381       * @param array $files      The FILES parameters
 382       * @param array $server     The SERVER parameters
 383       *
 384       * @return Request The duplicated request
 385       */
 386      public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
 387      {
 388          $dup = clone $this;
 389          if ($query !== null) {
 390              $dup->query = new ParameterBag($query);
 391          }
 392          if ($request !== null) {
 393              $dup->request = new ParameterBag($request);
 394          }
 395          if ($attributes !== null) {
 396              $dup->attributes = new ParameterBag($attributes);
 397          }
 398          if ($cookies !== null) {
 399              $dup->cookies = new ParameterBag($cookies);
 400          }
 401          if ($files !== null) {
 402              $dup->files = new FileBag($files);
 403          }
 404          if ($server !== null) {
 405              $dup->server = new ServerBag($server);
 406              $dup->headers = new HeaderBag($dup->server->getHeaders());
 407          }
 408          $dup->languages = null;
 409          $dup->charsets = null;
 410          $dup->acceptableContentTypes = null;
 411          $dup->pathInfo = null;
 412          $dup->requestUri = null;
 413          $dup->baseUrl = null;
 414          $dup->basePath = null;
 415          $dup->method = null;
 416          $dup->format = null;
 417  
 418          if (!$dup->get('_format') && $this->get('_format')) {
 419              $dup->attributes->set('_format', $this->get('_format'));
 420          }
 421  
 422          if (!$dup->getRequestFormat(null)) {
 423              $dup->setRequestFormat($this->getRequestFormat(null));
 424          }
 425  
 426          return $dup;
 427      }
 428  
 429      /**
 430       * Clones the current request.
 431       *
 432       * Note that the session is not cloned as duplicated requests
 433       * are most of the time sub-requests of the main one.
 434       */
 435      public function __clone()
 436      {
 437          $this->query = clone $this->query;
 438          $this->request = clone $this->request;
 439          $this->attributes = clone $this->attributes;
 440          $this->cookies = clone $this->cookies;
 441          $this->files = clone $this->files;
 442          $this->server = clone $this->server;
 443          $this->headers = clone $this->headers;
 444      }
 445  
 446      /**
 447       * Returns the request as a string.
 448       *
 449       * @return string The request
 450       */
 451      public function __toString()
 452      {
 453          try {
 454              $content = $this->getContent();
 455          } catch (\LogicException $e) {
 456              return trigger_error($e, E_USER_ERROR);
 457          }
 458  
 459          return
 460              sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
 461              $this->headers."\r\n".
 462              $content;
 463      }
 464  
 465      /**
 466       * Overrides the PHP global variables according to this request instance.
 467       *
 468       * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE.
 469       * $_FILES is never overridden, see rfc1867
 470       */
 471      public function overrideGlobals()
 472      {
 473          $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), null, '&')));
 474  
 475          $_GET = $this->query->all();
 476          $_POST = $this->request->all();
 477          $_SERVER = $this->server->all();
 478          $_COOKIE = $this->cookies->all();
 479  
 480          foreach ($this->headers->all() as $key => $value) {
 481              $key = strtoupper(str_replace('-', '_', $key));
 482              if (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
 483                  $_SERVER[$key] = implode(', ', $value);
 484              } else {
 485                  $_SERVER['HTTP_'.$key] = implode(', ', $value);
 486              }
 487          }
 488  
 489          $request = array('g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE);
 490  
 491          $requestOrder = ini_get('request_order') ?: ini_get('variables_order');
 492          $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
 493  
 494          $_REQUEST = array();
 495          foreach (str_split($requestOrder) as $order) {
 496              $_REQUEST = array_merge($_REQUEST, $request[$order]);
 497          }
 498      }
 499  
 500      /**
 501       * Sets a list of trusted proxies.
 502       *
 503       * You should only list the reverse proxies that you manage directly.
 504       *
 505       * @param array $proxies A list of trusted proxies
 506       */
 507      public static function setTrustedProxies(array $proxies)
 508      {
 509          self::$trustedProxies = $proxies;
 510      }
 511  
 512      /**
 513       * Gets the list of trusted proxies.
 514       *
 515       * @return array An array of trusted proxies.
 516       */
 517      public static function getTrustedProxies()
 518      {
 519          return self::$trustedProxies;
 520      }
 521  
 522      /**
 523       * Sets a list of trusted host patterns.
 524       *
 525       * You should only list the hosts you manage using regexs.
 526       *
 527       * @param array $hostPatterns A list of trusted host patterns
 528       */
 529      public static function setTrustedHosts(array $hostPatterns)
 530      {
 531          self::$trustedHostPatterns = array_map(function ($hostPattern) {
 532              return sprintf('#%s#i', $hostPattern);
 533          }, $hostPatterns);
 534          // we need to reset trusted hosts on trusted host patterns change
 535          self::$trustedHosts = array();
 536      }
 537  
 538      /**
 539       * Gets the list of trusted host patterns.
 540       *
 541       * @return array An array of trusted host patterns.
 542       */
 543      public static function getTrustedHosts()
 544      {
 545          return self::$trustedHostPatterns;
 546      }
 547  
 548      /**
 549       * Sets the name for trusted headers.
 550       *
 551       * The following header keys are supported:
 552       *
 553       *  * Request::HEADER_CLIENT_IP:    defaults to X-Forwarded-For   (see getClientIp())
 554       *  * Request::HEADER_CLIENT_HOST:  defaults to X-Forwarded-Host  (see getHost())
 555       *  * Request::HEADER_CLIENT_PORT:  defaults to X-Forwarded-Port  (see getPort())
 556       *  * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure())
 557       *
 558       * Setting an empty value allows to disable the trusted header for the given key.
 559       *
 560       * @param string $key   The header key
 561       * @param string $value The header name
 562       *
 563       * @throws \InvalidArgumentException
 564       */
 565      public static function setTrustedHeaderName($key, $value)
 566      {
 567          if (!array_key_exists($key, self::$trustedHeaders)) {
 568              throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
 569          }
 570  
 571          self::$trustedHeaders[$key] = $value;
 572      }
 573  
 574      /**
 575       * Gets the trusted proxy header name.
 576       *
 577       * @param string $key The header key
 578       *
 579       * @return string The header name
 580       *
 581       * @throws \InvalidArgumentException
 582       */
 583      public static function getTrustedHeaderName($key)
 584      {
 585          if (!array_key_exists($key, self::$trustedHeaders)) {
 586              throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key));
 587          }
 588  
 589          return self::$trustedHeaders[$key];
 590      }
 591  
 592      /**
 593       * Normalizes a query string.
 594       *
 595       * It builds a normalized query string, where keys/value pairs are alphabetized,
 596       * have consistent escaping and unneeded delimiters are removed.
 597       *
 598       * @param string $qs Query string
 599       *
 600       * @return string A normalized query string for the Request
 601       */
 602      public static function normalizeQueryString($qs)
 603      {
 604          if ('' == $qs) {
 605              return '';
 606          }
 607  
 608          $parts = array();
 609          $order = array();
 610  
 611          foreach (explode('&', $qs) as $param) {
 612              if ('' === $param || '=' === $param[0]) {
 613                  // Ignore useless delimiters, e.g. "x=y&".
 614                  // Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
 615                  // PHP also does not include them when building _GET.
 616                  continue;
 617              }
 618  
 619              $keyValuePair = explode('=', $param, 2);
 620  
 621              // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
 622              // 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
 623              // RFC 3986 with rawurlencode.
 624              $parts[] = isset($keyValuePair[1]) ?
 625                  rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) :
 626                  rawurlencode(urldecode($keyValuePair[0]));
 627              $order[] = urldecode($keyValuePair[0]);
 628          }
 629  
 630          array_multisort($order, SORT_ASC, $parts);
 631  
 632          return implode('&', $parts);
 633      }
 634  
 635      /**
 636       * Enables support for the _method request parameter to determine the intended HTTP method.
 637       *
 638       * Be warned that enabling this feature might lead to CSRF issues in your code.
 639       * Check that you are using CSRF tokens when required.
 640       * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered
 641       * and used to send a "PUT" or "DELETE" request via the _method request parameter.
 642       * If these methods are not protected against CSRF, this presents a possible vulnerability.
 643       *
 644       * The HTTP method can only be overridden when the real HTTP method is POST.
 645       */
 646      public static function enableHttpMethodParameterOverride()
 647      {
 648          self::$httpMethodParameterOverride = true;
 649      }
 650  
 651      /**
 652       * Checks whether support for the _method request parameter is enabled.
 653       *
 654       * @return bool True when the _method request parameter is enabled, false otherwise
 655       */
 656      public static function getHttpMethodParameterOverride()
 657      {
 658          return self::$httpMethodParameterOverride;
 659      }
 660  
 661      /**
 662       * Gets a "parameter" value.
 663       *
 664       * This method is mainly useful for libraries that want to provide some flexibility.
 665       *
 666       * Order of precedence: GET, PATH, POST
 667       *
 668       * Avoid using this method in controllers:
 669       *
 670       *  * slow
 671       *  * prefer to get from a "named" source
 672       *
 673       * It is better to explicitly get request parameters from the appropriate
 674       * public property instead (query, attributes, request).
 675       *
 676       * @param string $key     the key
 677       * @param mixed  $default the default value if the parameter key does not exist
 678       * @param bool   $deep    is parameter deep in multidimensional array
 679       *
 680       * @return mixed
 681       */
 682      public function get($key, $default = null, $deep = false)
 683      {
 684          if ($this !== $result = $this->query->get($key, $this, $deep)) {
 685              return $result;
 686          }
 687  
 688          if ($this !== $result = $this->attributes->get($key, $this, $deep)) {
 689              return $result;
 690          }
 691  
 692          if ($this !== $result = $this->request->get($key, $this, $deep)) {
 693              return $result;
 694          }
 695  
 696          return $default;
 697      }
 698  
 699      /**
 700       * Gets the Session.
 701       *
 702       * @return SessionInterface|null The session
 703       */
 704      public function getSession()
 705      {
 706          return $this->session;
 707      }
 708  
 709      /**
 710       * Whether the request contains a Session which was started in one of the
 711       * previous requests.
 712       *
 713       * @return bool
 714       */
 715      public function hasPreviousSession()
 716      {
 717          // the check for $this->session avoids malicious users trying to fake a session cookie with proper name
 718          return $this->hasSession() && $this->cookies->has($this->session->getName());
 719      }
 720  
 721      /**
 722       * Whether the request contains a Session object.
 723       *
 724       * This method does not give any information about the state of the session object,
 725       * like whether the session is started or not. It is just a way to check if this Request
 726       * is associated with a Session instance.
 727       *
 728       * @return bool true when the Request contains a Session object, false otherwise
 729       */
 730      public function hasSession()
 731      {
 732          return null !== $this->session;
 733      }
 734  
 735      /**
 736       * Sets the Session.
 737       *
 738       * @param SessionInterface $session The Session
 739       */
 740      public function setSession(SessionInterface $session)
 741      {
 742          $this->session = $session;
 743      }
 744  
 745      /**
 746       * Returns the client IP addresses.
 747       *
 748       * In the returned array the most trusted IP address is first, and the
 749       * least trusted one last. The "real" client IP address is the last one,
 750       * but this is also the least trusted one. Trusted proxies are stripped.
 751       *
 752       * Use this method carefully; you should use getClientIp() instead.
 753       *
 754       * @return array The client IP addresses
 755       *
 756       * @see getClientIp()
 757       */
 758      public function getClientIps()
 759      {
 760          $ip = $this->server->get('REMOTE_ADDR');
 761  
 762          if (!$this->isFromTrustedProxy()) {
 763              return array($ip);
 764          }
 765  
 766          if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
 767              return array($ip);
 768          }
 769  
 770          $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
 771          $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
 772          $firstTrustedIp = null;
 773  
 774          // Eliminate all IPs from the forwarded IP chain which are trusted proxies
 775          foreach ($clientIps as $key => $clientIp) {
 776              // Remove port on IPv4 address (unfortunately, it does happen)
 777              if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
 778                  $clientIps[$key] = $clientIp = $match[1];
 779              }
 780  
 781              if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
 782                  unset($clientIps[$key]);
 783  
 784                  continue;
 785              }
 786  
 787              if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
 788                  unset($clientIps[$key]);
 789  
 790                  // Fallback to this when the client IP falls into the range of trusted proxies
 791                  if (null ===  $firstTrustedIp) {
 792                      $firstTrustedIp = $clientIp;
 793                  }
 794              }
 795          }
 796  
 797          // Now the IP chain contains only untrusted proxies and the client IP
 798          return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
 799      }
 800  
 801      /**
 802       * Returns the client IP address.
 803       *
 804       * This method can read the client IP address from the "X-Forwarded-For" header
 805       * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
 806       * header value is a comma+space separated list of IP addresses, the left-most
 807       * being the original client, and each successive proxy that passed the request
 808       * adding the IP address where it received the request from.
 809       *
 810       * If your reverse proxy uses a different header name than "X-Forwarded-For",
 811       * ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
 812       * the "client-ip" key.
 813       *
 814       * @return string The client IP address
 815       *
 816       * @see getClientIps()
 817       * @see http://en.wikipedia.org/wiki/X-Forwarded-For
 818       */
 819      public function getClientIp()
 820      {
 821          $ipAddresses = $this->getClientIps();
 822  
 823          return $ipAddresses[0];
 824      }
 825  
 826      /**
 827       * Returns current script name.
 828       *
 829       * @return string
 830       */
 831      public function getScriptName()
 832      {
 833          return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', ''));
 834      }
 835  
 836      /**
 837       * Returns the path being requested relative to the executed script.
 838       *
 839       * The path info always starts with a /.
 840       *
 841       * Suppose this request is instantiated from /mysite on localhost:
 842       *
 843       *  * http://localhost/mysite              returns an empty string
 844       *  * http://localhost/mysite/about        returns '/about'
 845       *  * http://localhost/mysite/enco%20ded   returns '/enco%20ded'
 846       *  * http://localhost/mysite/about?var=1  returns '/about'
 847       *
 848       * @return string The raw path (i.e. not urldecoded)
 849       */
 850      public function getPathInfo()
 851      {
 852          if (null === $this->pathInfo) {
 853              $this->pathInfo = $this->preparePathInfo();
 854          }
 855  
 856          return $this->pathInfo;
 857      }
 858  
 859      /**
 860       * Returns the root path from which this request is executed.
 861       *
 862       * Suppose that an index.php file instantiates this request object:
 863       *
 864       *  * http://localhost/index.php         returns an empty string
 865       *  * http://localhost/index.php/page    returns an empty string
 866       *  * http://localhost/web/index.php     returns '/web'
 867       *  * http://localhost/we%20b/index.php  returns '/we%20b'
 868       *
 869       * @return string The raw path (i.e. not urldecoded)
 870       */
 871      public function getBasePath()
 872      {
 873          if (null === $this->basePath) {
 874              $this->basePath = $this->prepareBasePath();
 875          }
 876  
 877          return $this->basePath;
 878      }
 879  
 880      /**
 881       * Returns the root URL from which this request is executed.
 882       *
 883       * The base URL never ends with a /.
 884       *
 885       * This is similar to getBasePath(), except that it also includes the
 886       * script filename (e.g. index.php) if one exists.
 887       *
 888       * @return string The raw URL (i.e. not urldecoded)
 889       */
 890      public function getBaseUrl()
 891      {
 892          if (null === $this->baseUrl) {
 893              $this->baseUrl = $this->prepareBaseUrl();
 894          }
 895  
 896          return $this->baseUrl;
 897      }
 898  
 899      /**
 900       * Gets the request's scheme.
 901       *
 902       * @return string
 903       */
 904      public function getScheme()
 905      {
 906          return $this->isSecure() ? 'https' : 'http';
 907      }
 908  
 909      /**
 910       * Returns the port on which the request is made.
 911       *
 912       * This method can read the client port from the "X-Forwarded-Port" header
 913       * when trusted proxies were set via "setTrustedProxies()".
 914       *
 915       * The "X-Forwarded-Port" header must contain the client port.
 916       *
 917       * If your reverse proxy uses a different header name than "X-Forwarded-Port",
 918       * configure it via "setTrustedHeaderName()" with the "client-port" key.
 919       *
 920       * @return string
 921       */
 922      public function getPort()
 923      {
 924          if ($this->isFromTrustedProxy()) {
 925              if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) {
 926                  return $port;
 927              }
 928  
 929              if (self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && 'https' === $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO], 'http')) {
 930                  return 443;
 931              }
 932          }
 933  
 934          if ($host = $this->headers->get('HOST')) {
 935              if ($host[0] === '[') {
 936                  $pos = strpos($host, ':', strrpos($host, ']'));
 937              } else {
 938                  $pos = strrpos($host, ':');
 939              }
 940  
 941              if (false !== $pos) {
 942                  return (int) substr($host, $pos + 1);
 943              }
 944  
 945              return 'https' === $this->getScheme() ? 443 : 80;
 946          }
 947  
 948          return $this->server->get('SERVER_PORT');
 949      }
 950  
 951      /**
 952       * Returns the user.
 953       *
 954       * @return string|null
 955       */
 956      public function getUser()
 957      {
 958          return $this->headers->get('PHP_AUTH_USER');
 959      }
 960  
 961      /**
 962       * Returns the password.
 963       *
 964       * @return string|null
 965       */
 966      public function getPassword()
 967      {
 968          return $this->headers->get('PHP_AUTH_PW');
 969      }
 970  
 971      /**
 972       * Gets the user info.
 973       *
 974       * @return string A user name and, optionally, scheme-specific information about how to gain authorization to access the server
 975       */
 976      public function getUserInfo()
 977      {
 978          $userinfo = $this->getUser();
 979  
 980          $pass = $this->getPassword();
 981          if ('' != $pass) {
 982              $userinfo .= ":$pass";
 983          }
 984  
 985          return $userinfo;
 986      }
 987  
 988      /**
 989       * Returns the HTTP host being requested.
 990       *
 991       * The port name will be appended to the host if it's non-standard.
 992       *
 993       * @return string
 994       */
 995      public function getHttpHost()
 996      {
 997          $scheme = $this->getScheme();
 998          $port = $this->getPort();
 999  
1000          if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) {
1001              return $this->getHost();
1002          }
1003  
1004          return $this->getHost().':'.$port;
1005      }
1006  
1007      /**
1008       * Returns the requested URI (path and query string).
1009       *
1010       * @return string The raw URI (i.e. not URI decoded)
1011       */
1012      public function getRequestUri()
1013      {
1014          if (null === $this->requestUri) {
1015              $this->requestUri = $this->prepareRequestUri();
1016          }
1017  
1018          return $this->requestUri;
1019      }
1020  
1021      /**
1022       * Gets the scheme and HTTP host.
1023       *
1024       * If the URL was called with basic authentication, the user
1025       * and the password are not added to the generated string.
1026       *
1027       * @return string The scheme and HTTP host
1028       */
1029      public function getSchemeAndHttpHost()
1030      {
1031          return $this->getScheme().'://'.$this->getHttpHost();
1032      }
1033  
1034      /**
1035       * Generates a normalized URI (URL) for the Request.
1036       *
1037       * @return string A normalized URI (URL) for the Request
1038       *
1039       * @see getQueryString()
1040       */
1041      public function getUri()
1042      {
1043          if (null !== $qs = $this->getQueryString()) {
1044              $qs = '?'.$qs;
1045          }
1046  
1047          return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
1048      }
1049  
1050      /**
1051       * Generates a normalized URI for the given path.
1052       *
1053       * @param string $path A path to use instead of the current one
1054       *
1055       * @return string The normalized URI for the path
1056       */
1057      public function getUriForPath($path)
1058      {
1059          return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
1060      }
1061  
1062      /**
1063       * Generates the normalized query string for the Request.
1064       *
1065       * It builds a normalized query string, where keys/value pairs are alphabetized
1066       * and have consistent escaping.
1067       *
1068       * @return string|null A normalized query string for the Request
1069       */
1070      public function getQueryString()
1071      {
1072          $qs = static::normalizeQueryString($this->server->get('QUERY_STRING'));
1073  
1074          return '' === $qs ? null : $qs;
1075      }
1076  
1077      /**
1078       * Checks whether the request is secure or not.
1079       *
1080       * This method can read the client protocol from the "X-Forwarded-Proto" header
1081       * when trusted proxies were set via "setTrustedProxies()".
1082       *
1083       * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
1084       *
1085       * If your reverse proxy uses a different header name than "X-Forwarded-Proto"
1086       * ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
1087       * the "client-proto" key.
1088       *
1089       * @return bool
1090       */
1091      public function isSecure()
1092      {
1093          if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
1094              return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));
1095          }
1096  
1097          $https = $this->server->get('HTTPS');
1098  
1099          return !empty($https) && 'off' !== strtolower($https);
1100      }
1101  
1102      /**
1103       * Returns the host name.
1104       *
1105       * This method can read the client host name from the "X-Forwarded-Host" header
1106       * when trusted proxies were set via "setTrustedProxies()".
1107       *
1108       * The "X-Forwarded-Host" header must contain the client host name.
1109       *
1110       * If your reverse proxy uses a different header name than "X-Forwarded-Host",
1111       * configure it via "setTrustedHeaderName()" with the "client-host" key.
1112       *
1113       * @return string
1114       *
1115       * @throws \UnexpectedValueException when the host name is invalid
1116       */
1117      public function getHost()
1118      {
1119          if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) {
1120              $elements = explode(',', $host);
1121  
1122              $host = $elements[count($elements) - 1];
1123          } elseif (!$host = $this->headers->get('HOST')) {
1124              if (!$host = $this->server->get('SERVER_NAME')) {
1125                  $host = $this->server->get('SERVER_ADDR', '');
1126              }
1127          }
1128  
1129          // trim and remove port number from host
1130          // host is lowercase as per RFC 952/2181
1131          $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
1132  
1133          // as the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user)
1134          // check that it does not contain forbidden characters (see RFC 952 and RFC 2181)
1135          // use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
1136          if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) {
1137              throw new \UnexpectedValueException('Invalid Host "'.$host.'"');
1138          }
1139  
1140          if (count(self::$trustedHostPatterns) > 0) {
1141              // to avoid host header injection attacks, you should provide a list of trusted host patterns
1142  
1143              if (in_array($host, self::$trustedHosts)) {
1144                  return $host;
1145              }
1146  
1147              foreach (self::$trustedHostPatterns as $pattern) {
1148                  if (preg_match($pattern, $host)) {
1149                      self::$trustedHosts[] = $host;
1150  
1151                      return $host;
1152                  }
1153              }
1154  
1155              throw new \UnexpectedValueException('Untrusted Host "'.$host.'"');
1156          }
1157  
1158          return $host;
1159      }
1160  
1161      /**
1162       * Sets the request method.
1163       *
1164       * @param string $method
1165       */
1166      public function setMethod($method)
1167      {
1168          $this->method = null;
1169          $this->server->set('REQUEST_METHOD', $method);
1170      }
1171  
1172      /**
1173       * Gets the request "intended" method.
1174       *
1175       * If the X-HTTP-Method-Override header is set, and if the method is a POST,
1176       * then it is used to determine the "real" intended HTTP method.
1177       *
1178       * The _method request parameter can also be used to determine the HTTP method,
1179       * but only if enableHttpMethodParameterOverride() has been called.
1180       *
1181       * The method is always an uppercased string.
1182       *
1183       * @return string The request method
1184       *
1185       * @see getRealMethod()
1186       */
1187      public function getMethod()
1188      {
1189          if (null === $this->method) {
1190              $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
1191  
1192              if ('POST' === $this->method) {
1193                  if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
1194                      $this->method = strtoupper($method);
1195                  } elseif (self::$httpMethodParameterOverride) {
1196                      $this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
1197                  }
1198              }
1199          }
1200  
1201          return $this->method;
1202      }
1203  
1204      /**
1205       * Gets the "real" request method.
1206       *
1207       * @return string The request method
1208       *
1209       * @see getMethod()
1210       */
1211      public function getRealMethod()
1212      {
1213          return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
1214      }
1215  
1216      /**
1217       * Gets the mime type associated with the format.
1218       *
1219       * @param string $format The format
1220       *
1221       * @return string The associated mime type (null if not found)
1222       */
1223      public function getMimeType($format)
1224      {
1225          if (null === static::$formats) {
1226              static::initializeFormats();
1227          }
1228  
1229          return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
1230      }
1231  
1232      /**
1233       * Gets the format associated with the mime type.
1234       *
1235       * @param string $mimeType The associated mime type
1236       *
1237       * @return string|null The format (null if not found)
1238       */
1239      public function getFormat($mimeType)
1240      {
1241          $canonicalMimeType = null;
1242          if (false !== $pos = strpos($mimeType, ';')) {
1243              $canonicalMimeType = substr($mimeType, 0, $pos);
1244          }
1245  
1246          if (null === static::$formats) {
1247              static::initializeFormats();
1248          }
1249  
1250          foreach (static::$formats as $format => $mimeTypes) {
1251              if (in_array($mimeType, (array) $mimeTypes)) {
1252                  return $format;
1253              }
1254              if (null !== $canonicalMimeType && in_array($canonicalMimeType, (array) $mimeTypes)) {
1255                  return $format;
1256              }
1257          }
1258      }
1259  
1260      /**
1261       * Associates a format with mime types.
1262       *
1263       * @param string       $format    The format
1264       * @param string|array $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
1265       */
1266      public function setFormat($format, $mimeTypes)
1267      {
1268          if (null === static::$formats) {
1269              static::initializeFormats();
1270          }
1271  
1272          static::$formats[$format] = is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
1273      }
1274  
1275      /**
1276       * Gets the request format.
1277       *
1278       * Here is the process to determine the format:
1279       *
1280       *  * format defined by the user (with setRequestFormat())
1281       *  * _format request parameter
1282       *  * $default
1283       *
1284       * @param string $default The default format
1285       *
1286       * @return string The request format
1287       */
1288      public function getRequestFormat($default = 'html')
1289      {
1290          if (null === $this->format) {
1291              $this->format = $this->get('_format', $default);
1292          }
1293  
1294          return $this->format;
1295      }
1296  
1297      /**
1298       * Sets the request format.
1299       *
1300       * @param string $format The request format.
1301       */
1302      public function setRequestFormat($format)
1303      {
1304          $this->format = $format;
1305      }
1306  
1307      /**
1308       * Gets the format associated with the request.
1309       *
1310       * @return string|null The format (null if no content type is present)
1311       */
1312      public function getContentType()
1313      {
1314          return $this->getFormat($this->headers->get('CONTENT_TYPE'));
1315      }
1316  
1317      /**
1318       * Sets the default locale.
1319       *
1320       * @param string $locale
1321       */
1322      public function setDefaultLocale($locale)
1323      {
1324          $this->defaultLocale = $locale;
1325  
1326          if (null === $this->locale) {
1327              $this->setPhpDefaultLocale($locale);
1328          }
1329      }
1330  
1331      /**
1332       * Get the default locale.
1333       *
1334       * @return string
1335       */
1336      public function getDefaultLocale()
1337      {
1338          return $this->defaultLocale;
1339      }
1340  
1341      /**
1342       * Sets the locale.
1343       *
1344       * @param string $locale
1345       */
1346      public function setLocale($locale)
1347      {
1348          $this->setPhpDefaultLocale($this->locale = $locale);
1349      }
1350  
1351      /**
1352       * Get the locale.
1353       *
1354       * @return string
1355       */
1356      public function getLocale()
1357      {
1358          return null === $this->locale ? $this->defaultLocale : $this->locale;
1359      }
1360  
1361      /**
1362       * Checks if the request method is of specified type.
1363       *
1364       * @param string $method Uppercase request method (GET, POST etc).
1365       *
1366       * @return bool
1367       */
1368      public function isMethod($method)
1369      {
1370          return $this->getMethod() === strtoupper($method);
1371      }
1372  
1373      /**
1374       * Checks whether the method is safe or not.
1375       *
1376       * @return bool
1377       */
1378      public function isMethodSafe()
1379      {
1380          return in_array($this->getMethod(), array('GET', 'HEAD'));
1381      }
1382  
1383      /**
1384       * Returns the request body content.
1385       *
1386       * @param bool $asResource If true, a resource will be returned
1387       *
1388       * @return string|resource The request body content or a resource to read the body stream.
1389       *
1390       * @throws \LogicException
1391       */
1392      public function getContent($asResource = false)
1393      {
1394          $currentContentIsResource = is_resource($this->content);
1395          if (PHP_VERSION_ID < 50600 && false === $this->content) {
1396              throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.');
1397          }
1398  
1399          if (true === $asResource) {
1400              if ($currentContentIsResource) {
1401                  rewind($this->content);
1402  
1403                  return $this->content;
1404              }
1405  
1406              // Content passed in parameter (test)
1407              if (is_string($this->content)) {
1408                  $resource = fopen('php://temp', 'r+');
1409                  fwrite($resource, $this->content);
1410                  rewind($resource);
1411  
1412                  return $resource;
1413              }
1414  
1415              $this->content = false;
1416  
1417              return fopen('php://input', 'rb');
1418          }
1419  
1420          if ($currentContentIsResource) {
1421              rewind($this->content);
1422  
1423              return stream_get_contents($this->content);
1424          }
1425  
1426          if (null === $this->content) {
1427              $this->content = file_get_contents('php://input');
1428          }
1429  
1430          return $this->content;
1431      }
1432  
1433      /**
1434       * Gets the Etags.
1435       *
1436       * @return array The entity tags
1437       */
1438      public function getETags()
1439      {
1440          return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, PREG_SPLIT_NO_EMPTY);
1441      }
1442  
1443      /**
1444       * @return bool
1445       */
1446      public function isNoCache()
1447      {
1448          return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma');
1449      }
1450  
1451      /**
1452       * Returns the preferred language.
1453       *
1454       * @param array $locales An array of ordered available locales
1455       *
1456       * @return string|null The preferred locale
1457       */
1458      public function getPreferredLanguage(array $locales = null)
1459      {
1460          $preferredLanguages = $this->getLanguages();
1461  
1462          if (empty($locales)) {
1463              return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null;
1464          }
1465  
1466          if (!$preferredLanguages) {
1467              return $locales[0];
1468          }
1469  
1470          $extendedPreferredLanguages = array();
1471          foreach ($preferredLanguages as $language) {
1472              $extendedPreferredLanguages[] = $language;
1473              if (false !== $position = strpos($language, '_')) {
1474                  $superLanguage = substr($language, 0, $position);
1475                  if (!in_array($superLanguage, $preferredLanguages)) {
1476                      $extendedPreferredLanguages[] = $superLanguage;
1477                  }
1478              }
1479          }
1480  
1481          $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
1482  
1483          return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
1484      }
1485  
1486      /**
1487       * Gets a list of languages acceptable by the client browser.
1488       *
1489       * @return array Languages ordered in the user browser preferences
1490       */
1491      public function getLanguages()
1492      {
1493          if (null !== $this->languages) {
1494              return $this->languages;
1495          }
1496  
1497          $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
1498          $this->languages = array();
1499          foreach ($languages as $lang => $acceptHeaderItem) {
1500              if (false !== strpos($lang, '-')) {
1501                  $codes = explode('-', $lang);
1502                  if ('i' === $codes[0]) {
1503                      // Language not listed in ISO 639 that are not variants
1504                      // of any listed language, which can be registered with the
1505                      // i-prefix, such as i-cherokee
1506                      if (count($codes) > 1) {
1507                          $lang = $codes[1];
1508                      }
1509                  } else {
1510                      for ($i = 0, $max = count($codes); $i < $max; ++$i) {
1511                          if ($i === 0) {
1512                              $lang = strtolower($codes[0]);
1513                          } else {
1514                              $lang .= '_'.strtoupper($codes[$i]);
1515                          }
1516                      }
1517                  }
1518              }
1519  
1520              $this->languages[] = $lang;
1521          }
1522  
1523          return $this->languages;
1524      }
1525  
1526      /**
1527       * Gets a list of charsets acceptable by the client browser.
1528       *
1529       * @return array List of charsets in preferable order
1530       */
1531      public function getCharsets()
1532      {
1533          if (null !== $this->charsets) {
1534              return $this->charsets;
1535          }
1536  
1537          return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
1538      }
1539  
1540      /**
1541       * Gets a list of content types acceptable by the client browser.
1542       *
1543       * @return array List of content types in preferable order
1544       */
1545      public function getAcceptableContentTypes()
1546      {
1547          if (null !== $this->acceptableContentTypes) {
1548              return $this->acceptableContentTypes;
1549          }
1550  
1551          return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
1552      }
1553  
1554      /**
1555       * Returns true if the request is a XMLHttpRequest.
1556       *
1557       * It works if your JavaScript library sets an X-Requested-With HTTP header.
1558       * It is known to work with common JavaScript frameworks:
1559       *
1560       * @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
1561       *
1562       * @return bool true if the request is an XMLHttpRequest, false otherwise
1563       */
1564      public function isXmlHttpRequest()
1565      {
1566          return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
1567      }
1568  
1569      /*
1570       * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
1571       *
1572       * Code subject to the new BSD license (http://framework.zend.com/license/new-bsd).
1573       *
1574       * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
1575       */
1576  
1577      protected function prepareRequestUri()
1578      {
1579          $requestUri = '';
1580  
1581          if ($this->headers->has('X_ORIGINAL_URL')) {
1582              // IIS with Microsoft Rewrite Module
1583              $requestUri = $this->headers->get('X_ORIGINAL_URL');
1584              $this->headers->remove('X_ORIGINAL_URL');
1585              $this->server->remove('HTTP_X_ORIGINAL_URL');
1586              $this->server->remove('UNENCODED_URL');
1587              $this->server->remove('IIS_WasUrlRewritten');
1588          } elseif ($this->headers->has('X_REWRITE_URL')) {
1589              // IIS with ISAPI_Rewrite
1590              $requestUri = $this->headers->get('X_REWRITE_URL');
1591              $this->headers->remove('X_REWRITE_URL');
1592          } elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
1593              // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
1594              $requestUri = $this->server->get('UNENCODED_URL');
1595              $this->server->remove('UNENCODED_URL');
1596              $this->server->remove('IIS_WasUrlRewritten');
1597          } elseif ($this->server->has('REQUEST_URI')) {
1598              $requestUri = $this->server->get('REQUEST_URI');
1599              // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, only use URL path
1600              $schemeAndHttpHost = $this->getSchemeAndHttpHost();
1601              if (strpos($requestUri, $schemeAndHttpHost) === 0) {
1602                  $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
1603              }
1604          } elseif ($this->server->has('ORIG_PATH_INFO')) {
1605              // IIS 5.0, PHP as CGI
1606              $requestUri = $this->server->get('ORIG_PATH_INFO');
1607              if ('' != $this->server->get('QUERY_STRING')) {
1608                  $requestUri .= '?'.$this->server->get('QUERY_STRING');
1609              }
1610              $this->server->remove('ORIG_PATH_INFO');
1611          }
1612  
1613          // normalize the request URI to ease creating sub-requests from this request
1614          $this->server->set('REQUEST_URI', $requestUri);
1615  
1616          return $requestUri;
1617      }
1618  
1619      /**
1620       * Prepares the base URL.
1621       *
1622       * @return string
1623       */
1624      protected function prepareBaseUrl()
1625      {
1626          $filename = basename($this->server->get('SCRIPT_FILENAME'));
1627  
1628          if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
1629              $baseUrl = $this->server->get('SCRIPT_NAME');
1630          } elseif (basename($this->server->get('PHP_SELF')) === $filename) {
1631              $baseUrl = $this->server->get('PHP_SELF');
1632          } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
1633              $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility
1634          } else {
1635              // Backtrack up the script_filename to find the portion matching
1636              // php_self
1637              $path = $this->server->get('PHP_SELF', '');
1638              $file = $this->server->get('SCRIPT_FILENAME', '');
1639              $segs = explode('/', trim($file, '/'));
1640              $segs = array_reverse($segs);
1641              $index = 0;
1642              $last = count($segs);
1643              $baseUrl = '';
1644              do {
1645                  $seg = $segs[$index];
1646                  $baseUrl = '/'.$seg.$baseUrl;
1647                  ++$index;
1648              } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos);
1649          }
1650  
1651          // Does the baseUrl have anything in common with the request_uri?
1652          $requestUri = $this->getRequestUri();
1653  
1654          if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
1655              // full $baseUrl matches
1656              return $prefix;
1657          }
1658  
1659          if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/'.DIRECTORY_SEPARATOR).'/')) {
1660              // directory portion of $baseUrl matches
1661              return rtrim($prefix, '/'.DIRECTORY_SEPARATOR);
1662          }
1663  
1664          $truncatedRequestUri = $requestUri;
1665          if (false !== $pos = strpos($requestUri, '?')) {
1666              $truncatedRequestUri = substr($requestUri, 0, $pos);
1667          }
1668  
1669          $basename = basename($baseUrl);
1670          if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
1671              // no match whatsoever; set it blank
1672              return '';
1673          }
1674  
1675          // If using mod_rewrite or ISAPI_Rewrite strip the script filename
1676          // out of baseUrl. $pos !== 0 makes sure it is not matching a value
1677          // from PATH_INFO or QUERY_STRING
1678          if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && $pos !== 0) {
1679              $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
1680          }
1681  
1682          return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR);
1683      }
1684  
1685      /**
1686       * Prepares the base path.
1687       *
1688       * @return string base path
1689       */
1690      protected function prepareBasePath()
1691      {
1692          $filename = basename($this->server->get('SCRIPT_FILENAME'));
1693          $baseUrl = $this->getBaseUrl();
1694          if (empty($baseUrl)) {
1695              return '';
1696          }
1697  
1698          if (basename($baseUrl) === $filename) {
1699              $basePath = dirname($baseUrl);
1700          } else {
1701              $basePath = $baseUrl;
1702          }
1703  
1704          if ('\\' === DIRECTORY_SEPARATOR) {
1705              $basePath = str_replace('\\', '/', $basePath);
1706          }
1707  
1708          return rtrim($basePath, '/');
1709      }
1710  
1711      /**
1712       * Prepares the path info.
1713       *
1714       * @return string path info
1715       */
1716      protected function preparePathInfo()
1717      {
1718          $baseUrl = $this->getBaseUrl();
1719  
1720          if (null === ($requestUri = $this->getRequestUri())) {
1721              return '/';
1722          }
1723  
1724          // Remove the query string from REQUEST_URI
1725          if ($pos = strpos($requestUri, '?')) {
1726              $requestUri = substr($requestUri, 0, $pos);
1727          }
1728  
1729          $pathInfo = substr($requestUri, strlen($baseUrl));
1730          if (null !== $baseUrl && (false === $pathInfo || '' === $pathInfo)) {
1731              // If substr() returns false then PATH_INFO is set to an empty string
1732              return '/';
1733          } elseif (null === $baseUrl) {
1734              return $requestUri;
1735          }
1736  
1737          return (string) $pathInfo;
1738      }
1739  
1740      /**
1741       * Initializes HTTP request formats.
1742       */
1743      protected static function initializeFormats()
1744      {
1745          static::$formats = array(
1746              'html' => array('text/html', 'application/xhtml+xml'),
1747              'txt' => array('text/plain'),
1748              'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
1749              'css' => array('text/css'),
1750              'json' => array('application/json', 'application/x-json'),
1751              'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
1752              'rdf' => array('application/rdf+xml'),
1753              'atom' => array('application/atom+xml'),
1754              'rss' => array('application/rss+xml'),
1755          );
1756      }
1757  
1758      /**
1759       * Sets the default PHP locale.
1760       *
1761       * @param string $locale
1762       */
1763      private function setPhpDefaultLocale($locale)
1764      {
1765          // if either the class Locale doesn't exist, or an exception is thrown when
1766          // setting the default locale, the intl module is not installed, and
1767          // the call can be ignored:
1768          try {
1769              if (class_exists('Locale', false)) {
1770                  \Locale::setDefault($locale);
1771              }
1772          } catch (\Exception $e) {
1773          }
1774      }
1775  
1776      /*
1777       * Returns the prefix as encoded in the string when the string starts with
1778       * the given prefix, false otherwise.
1779       *
1780       * @param string $string The urlencoded string
1781       * @param string $prefix The prefix not encoded
1782       *
1783       * @return string|false The prefix as it is encoded in $string, or false
1784       */
1785      private function getUrlencodedPrefix($string, $prefix)
1786      {
1787          if (0 !== strpos(rawurldecode($string), $prefix)) {
1788              return false;
1789          }
1790  
1791          $len = strlen($prefix);
1792  
1793          if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
1794              return $match[0];
1795          }
1796  
1797          return false;
1798      }
1799  
1800      private function isFromTrustedProxy()
1801      {
1802          return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies);
1803      }
1804  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1