Overview

Namespaces

  • Composer
    • Autoload
  • Guzzle
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
        • Header
      • QueryAggregator
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Mock
    • Stream
  • Mockery
    • Adapter
      • Phpunit
    • CountValidator
    • Exception
    • Generator
      • StringManipulation
        • Pass
    • Loader
    • Matcher
  • None
  • Omnipay
    • Common
      • Exception
      • Message
    • Dummy
      • Message
    • Fatzebra
      • Message
  • PHP
  • Symfony
    • Component
      • EventDispatcher
        • Debug
        • DependencyInjection
        • Tests
          • Debug
          • DependencyInjection
      • HttpFoundation
        • File
          • Exception
          • MimeType
        • Session
          • Attribute
          • Flash
          • Storage
            • Handler
            • Proxy
        • Tests
          • File
            • MimeType
          • Session
            • Attribute
            • Flash
            • Storage
              • Handler
              • Proxy
      • Yaml
        • Exception
        • Tests

Classes

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