Augmentation vers version 3.3.0

This commit is contained in:
Gauvain Boiché
2020-03-31 15:31:03 +02:00
parent d926806907
commit a1864c0414
2618 changed files with 406015 additions and 31377 deletions

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
/**
@@ -29,11 +30,22 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
*/
class Request
{
const HEADER_FORWARDED = 'forwarded';
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_PROTO = 'client_proto';
const HEADER_CLIENT_PORT = 'client_port';
const HEADER_FORWARDED = 0b00001; // When using RFC 7239
const HEADER_X_FORWARDED_FOR = 0b00010;
const HEADER_X_FORWARDED_HOST = 0b00100;
const HEADER_X_FORWARDED_PROTO = 0b01000;
const HEADER_X_FORWARDED_PORT = 0b10000;
const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers
const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT;
const METHOD_HEAD = 'HEAD';
const METHOD_GET = 'GET';
@@ -49,17 +61,17 @@ class Request
/**
* @var string[]
*/
protected static $trustedProxies = array();
protected static $trustedProxies = [];
/**
* @var string[]
*/
protected static $trustedHostPatterns = array();
protected static $trustedHostPatterns = [];
/**
* @var string[]
*/
protected static $trustedHosts = array();
protected static $trustedHosts = [];
/**
* Names for headers that can be trusted when
@@ -69,63 +81,65 @@ class Request
*
* The other headers are non-standard, but widely used
* by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
*
* @deprecated since version 3.3, to be removed in 4.0
*/
protected static $trustedHeaders = array(
protected static $trustedHeaders = [
self::HEADER_FORWARDED => 'FORWARDED',
self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);
];
protected static $httpMethodParameterOverride = false;
/**
* Custom parameters.
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
* @var ParameterBag
*/
public $attributes;
/**
* Request body parameters ($_POST).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
* @var ParameterBag
*/
public $request;
/**
* Query string parameters ($_GET).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
* @var ParameterBag
*/
public $query;
/**
* Server and execution environment parameters ($_SERVER).
*
* @var \Symfony\Component\HttpFoundation\ServerBag
* @var ServerBag
*/
public $server;
/**
* Uploaded files ($_FILES).
*
* @var \Symfony\Component\HttpFoundation\FileBag
* @var FileBag
*/
public $files;
/**
* Cookies ($_COOKIE).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
* @var ParameterBag
*/
public $cookies;
/**
* Headers (taken from the $_SERVER).
*
* @var \Symfony\Component\HttpFoundation\HeaderBag
* @var HeaderBag
*/
public $headers;
@@ -185,7 +199,7 @@ class Request
protected $format;
/**
* @var \Symfony\Component\HttpFoundation\Session\SessionInterface
* @var SessionInterface
*/
protected $session;
@@ -206,14 +220,26 @@ class Request
protected static $requestFactory;
private $isHostValid = true;
private $isForwardedValid = true;
private static $forwardedParams = array(
self::HEADER_CLIENT_IP => 'for',
self::HEADER_CLIENT_HOST => 'host',
self::HEADER_CLIENT_PROTO => 'proto',
self::HEADER_CLIENT_PORT => 'host',
);
private static $trustedHeaderSet = -1;
/** @deprecated since version 3.3, to be removed in 4.0 */
private static $trustedHeaderNames = [
self::HEADER_FORWARDED => 'FORWARDED',
self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
];
private static $forwardedParams = [
self::HEADER_X_FORWARDED_FOR => 'for',
self::HEADER_X_FORWARDED_HOST => 'host',
self::HEADER_X_FORWARDED_PROTO => 'proto',
self::HEADER_X_FORWARDED_PORT => 'host',
];
/**
* @param array $query The GET parameters
@@ -224,7 +250,7 @@ class Request
* @param array $server The SERVER parameters
* @param string|resource|null $content The raw body data
*/
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
public function __construct(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
}
@@ -242,7 +268,7 @@ class Request
* @param array $server The SERVER parameters
* @param string|resource|null $content The raw body data
*/
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
$this->request = new ParameterBag($request);
$this->query = new ParameterBag($query);
@@ -277,18 +303,18 @@ class Request
// HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields.
$server = $_SERVER;
if ('cli-server' === \PHP_SAPI) {
if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
if (\array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
$server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
}
if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
if (\array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
$server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
}
}
$request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server);
$request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $server);
if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])
) {
parse_str($request->getContent(), $data);
$request->request = new ParameterBag($data);
@@ -313,13 +339,13 @@ class Request
*
* @return static
*/
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
public static function create($uri, $method = 'GET', $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
{
$server = array_replace(array(
$server = array_replace([
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'HTTP_HOST' => 'localhost',
'HTTP_USER_AGENT' => 'Symfony/2.X',
'HTTP_USER_AGENT' => 'Symfony/3.X',
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
@@ -328,7 +354,7 @@ class Request
'SCRIPT_FILENAME' => '',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_TIME' => time(),
), $server);
], $server);
$server['PATH_INFO'] = '';
$server['REQUEST_METHOD'] = strtoupper($method);
@@ -376,10 +402,10 @@ class Request
// no break
case 'PATCH':
$request = $parameters;
$query = array();
$query = [];
break;
default:
$request = array();
$request = [];
$query = $parameters;
break;
}
@@ -402,7 +428,7 @@ class Request
$server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
$server['QUERY_STRING'] = $queryString;
return self::createRequestFromFactory($query, $request, array(), $cookies, $files, $server, $content);
return self::createRequestFromFactory($query, $request, [], $cookies, $files, $server, $content);
}
/**
@@ -502,11 +528,15 @@ class Request
try {
$content = $this->getContent();
} catch (\LogicException $e) {
if (\PHP_VERSION_ID >= 70400) {
throw $e;
}
return trigger_error($e, E_USER_ERROR);
}
$cookieHeader = '';
$cookies = array();
$cookies = [];
foreach ($this->cookies as $k => $v) {
$cookies[] = $k.'='.$v;
@@ -540,19 +570,19 @@ class Request
foreach ($this->headers->all() as $key => $value) {
$key = strtoupper(str_replace('-', '_', $key));
if (\in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) {
$_SERVER[$key] = implode(', ', $value);
} else {
$_SERVER['HTTP_'.$key] = implode(', ', $value);
}
}
$request = array('g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE);
$request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE];
$requestOrder = ini_get('request_order') ?: ini_get('variables_order');
$requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
$_REQUEST = array();
$_REQUEST = [];
foreach (str_split($requestOrder) as $order) {
$_REQUEST = array_merge($_REQUEST, $request[$order]);
}
@@ -563,11 +593,26 @@ class Request
*
* You should only list the reverse proxies that you manage directly.
*
* @param array $proxies A list of trusted proxies
* @param array $proxies A list of trusted proxies
* @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies
*
* @throws \InvalidArgumentException When $trustedHeaderSet is invalid
*/
public static function setTrustedProxies(array $proxies)
public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/)
{
self::$trustedProxies = $proxies;
if (2 > \func_num_args()) {
@trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED);
return;
}
$trustedHeaderSet = (int) func_get_arg(1);
foreach (self::$trustedHeaderNames as $header => $name) {
self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null;
}
self::$trustedHeaderSet = $trustedHeaderSet;
}
/**
@@ -580,6 +625,16 @@ class Request
return self::$trustedProxies;
}
/**
* Gets the set of trusted headers from trusted proxies.
*
* @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies
*/
public static function getTrustedHeaderSet()
{
return self::$trustedHeaderSet;
}
/**
* Sets a list of trusted host patterns.
*
@@ -593,7 +648,7 @@ class Request
return sprintf('{%s}i', $hostPattern);
}, $hostPatterns);
// we need to reset trusted hosts on trusted host patterns change
self::$trustedHosts = array();
self::$trustedHosts = [];
}
/**
@@ -623,14 +678,35 @@ class Request
* @param string $value The header name
*
* @throws \InvalidArgumentException
*
* @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public static function setTrustedHeaderName($key, $value)
{
if (!array_key_exists($key, self::$trustedHeaders)) {
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
if ('forwarded' === $key) {
$key = self::HEADER_FORWARDED;
} elseif ('client_ip' === $key) {
$key = self::HEADER_CLIENT_IP;
} elseif ('client_host' === $key) {
$key = self::HEADER_CLIENT_HOST;
} elseif ('client_proto' === $key) {
$key = self::HEADER_CLIENT_PROTO;
} elseif ('client_port' === $key) {
$key = self::HEADER_CLIENT_PORT;
} elseif (!\array_key_exists($key, self::$trustedHeaders)) {
throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
}
self::$trustedHeaders[$key] = $value;
if (null !== $value) {
self::$trustedHeaderNames[$key] = $value;
self::$trustedHeaderSet |= $key;
} else {
self::$trustedHeaderSet &= ~$key;
}
}
/**
@@ -641,10 +717,16 @@ class Request
* @return string The header name
*
* @throws \InvalidArgumentException
*
* @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.
*/
public static function getTrustedHeaderName($key)
{
if (!array_key_exists($key, self::$trustedHeaders)) {
if (2 > \func_num_args() || func_get_arg(1)) {
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), E_USER_DEPRECATED);
}
if (!\array_key_exists($key, self::$trustedHeaders)) {
throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key));
}
@@ -667,8 +749,8 @@ class Request
return '';
}
$parts = array();
$order = array();
$parts = [];
$order = [];
foreach (explode('&', $qs) as $param) {
if ('' === $param || '=' === $param[0]) {
@@ -721,43 +803,30 @@ class Request
}
/**
* Gets a "parameter" value.
* Gets a "parameter" value from any bag.
*
* This method is mainly useful for libraries that want to provide some flexibility.
* This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
* flexibility in controllers, it is better to explicitly get request parameters from the appropriate
* public property instead (attributes, query, request).
*
* Order of precedence: GET, PATH, POST
*
* Avoid using this method in controllers:
*
* * slow
* * prefer to get from a "named" source
*
* It is better to explicitly get request parameters from the appropriate
* public property instead (query, attributes, request).
*
* Note: Finding deep items is deprecated since version 2.8, to be removed in 3.0.
* Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY
*
* @param string $key The key
* @param mixed $default The default value if the parameter key does not exist
* @param bool $deep Is parameter deep in multidimensional array
*
* @return mixed
*/
public function get($key, $default = null, $deep = false)
public function get($key, $default = null)
{
if ($deep) {
@trigger_error('Using paths to find deeper items in '.__METHOD__.' is deprecated since Symfony 2.8 and will be removed in 3.0. Filter the returned value in your own code instead.', E_USER_DEPRECATED);
}
if ($this !== $result = $this->query->get($key, $this, $deep)) {
if ($this !== $result = $this->attributes->get($key, $this)) {
return $result;
}
if ($this !== $result = $this->attributes->get($key, $this, $deep)) {
if ($this !== $result = $this->query->get($key, $this)) {
return $result;
}
if ($this !== $result = $this->request->get($key, $this, $deep)) {
if ($this !== $result = $this->request->get($key, $this)) {
return $result;
}
@@ -828,10 +897,10 @@ class Request
$ip = $this->server->get('REMOTE_ADDR');
if (!$this->isFromTrustedProxy()) {
return array($ip);
return [$ip];
}
return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: array($ip);
return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: [$ip];
}
/**
@@ -844,13 +913,13 @@ class Request
* adding the IP address where it received the request from.
*
* If your reverse proxy uses a different header name than "X-Forwarded-For",
* ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
* the "client-ip" key.
* ("Client-Ip" for instance), configure it via the $trustedHeaderSet
* argument of the Request::setTrustedProxies() method instead.
*
* @return string|null The client IP address
*
* @see getClientIps()
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
* @see https://wikipedia.org/wiki/X-Forwarded-For
*/
public function getClientIp()
{
@@ -951,7 +1020,8 @@ class Request
* The "X-Forwarded-Port" header must contain the client port.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
* configure it via "setTrustedHeaderName()" with the "client-port" key.
* configure it via via the $trustedHeaderSet argument of the
* Request::setTrustedProxies() method instead.
*
* @return int|string can be a string if fetched from the server bag
*/
@@ -971,8 +1041,8 @@ class Request
$pos = strrpos($host, ':');
}
if (false !== $pos) {
return (int) substr($host, $pos + 1);
if (false !== $pos && $port = substr($host, $pos + 1)) {
return (int) $port;
}
return 'https' === $this->getScheme() ? 443 : 80;
@@ -1138,7 +1208,7 @@ class Request
// A reference to the same base directory or an empty subdirectory must be prefixed with "./".
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
// as the first segment of a relative-path reference, as it would be mistaken for a scheme name
// (see http://tools.ietf.org/html/rfc3986#section-4.2).
// (see https://tools.ietf.org/html/rfc3986#section-4.2).
return !isset($path[0]) || '/' === $path[0]
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
? "./$path" : $path;
@@ -1168,15 +1238,15 @@ class Request
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
*
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
* ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
* the "client-proto" key.
* ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet
* argument of the Request::setTrustedProxies() method instead.
*
* @return bool
*/
public function isSecure()
{
if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) {
return \in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true);
return \in_array(strtolower($proto[0]), ['https', 'on', 'ssl', '1'], true);
}
$https = $this->server->get('HTTPS');
@@ -1193,11 +1263,12 @@ class Request
* The "X-Forwarded-Host" header must contain the client host name.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
* configure it via "setTrustedHeaderName()" with the "client-host" key.
* configure it via the $trustedHeaderSet argument of the
* Request::setTrustedProxies() method instead.
*
* @return string
*
* @throws \UnexpectedValueException when the host name is invalid
* @throws SuspiciousOperationException when the host name is invalid or not trusted
*/
public function getHost()
{
@@ -1217,7 +1288,12 @@ class Request
// check that it does not contain forbidden characters (see RFC 952 and RFC 2181)
// use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) {
throw new \UnexpectedValueException(sprintf('Invalid Host "%s"', $host));
if (!$this->isHostValid) {
return '';
}
$this->isHostValid = false;
throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host));
}
if (\count(self::$trustedHostPatterns) > 0) {
@@ -1235,7 +1311,12 @@ class Request
}
}
throw new \UnexpectedValueException(sprintf('Untrusted Host "%s"', $host));
if (!$this->isHostValid) {
return '';
}
$this->isHostValid = false;
throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host));
}
return $host;
@@ -1269,22 +1350,37 @@ class Request
*/
public function getMethod()
{
if (null === $this->method) {
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' === $this->method) {
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$method = $this->request->get('_method', $this->query->get('_method', 'POST'));
if (\is_string($method)) {
$this->method = strtoupper($method);
}
}
}
if (null !== $this->method) {
return $this->method;
}
return $this->method;
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' !== $this->method) {
return $this->method;
}
$method = $this->headers->get('X-HTTP-METHOD-OVERRIDE');
if (!$method && self::$httpMethodParameterOverride) {
$method = $this->request->get('_method', $this->query->get('_method', 'POST'));
}
if (!\is_string($method)) {
return $this->method;
}
$method = strtoupper($method);
if (\in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'PATCH', 'PURGE', 'TRACE'], true)) {
return $this->method = $method;
}
if (!preg_match('/^[A-Z]++$/D', $method)) {
throw new SuspiciousOperationException(sprintf('Invalid method override "%s".', $method));
}
return $this->method = $method;
}
/**
@@ -1315,6 +1411,22 @@ class Request
return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
}
/**
* Gets the mime types associated with the format.
*
* @param string $format The format
*
* @return array The associated mime types
*/
public static function getMimeTypes($format)
{
if (null === static::$formats) {
static::initializeFormats();
}
return isset(static::$formats[$format]) ? static::$formats[$format] : [];
}
/**
* Gets the format associated with the mime type.
*
@@ -1341,6 +1453,8 @@ class Request
return $format;
}
}
return null;
}
/**
@@ -1355,7 +1469,7 @@ class Request
static::initializeFormats();
}
static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : [$mimeTypes];
}
/**
@@ -1364,17 +1478,17 @@ class Request
* Here is the process to determine the format:
*
* * format defined by the user (with setRequestFormat())
* * _format request parameter
* * _format request attribute
* * $default
*
* @param string|null $default The default format
*
* @return string The request format
* @return string|null The request format
*/
public function getRequestFormat($default = 'html')
{
if (null === $this->format) {
$this->format = $this->get('_format');
$this->format = $this->attributes->get('_format');
}
return null === $this->format ? $default : $this->format;
@@ -1457,7 +1571,7 @@ class Request
}
/**
* Checks whether the method is safe or not.
* Checks whether or not the method is safe.
*
* @see https://tools.ietf.org/html/rfc7231#section-4.2.1
*
@@ -1467,7 +1581,25 @@ class Request
*/
public function isMethodSafe(/* $andCacheable = true */)
{
return \in_array($this->getMethod(), 0 < \func_num_args() && !func_get_arg(0) ? array('GET', 'HEAD', 'OPTIONS', 'TRACE') : array('GET', 'HEAD'));
if (!\func_num_args() || func_get_arg(0)) {
// This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature)
// then setting $andCacheable to false should be deprecated in 4.1
@trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', E_USER_DEPRECATED);
return \in_array($this->getMethod(), ['GET', 'HEAD']);
}
return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']);
}
/**
* Checks whether or not the method is idempotent.
*
* @return bool
*/
public function isMethodIdempotent()
{
return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE']);
}
/**
@@ -1479,7 +1611,31 @@ class Request
*/
public function isMethodCacheable()
{
return \in_array($this->getMethod(), array('GET', 'HEAD'));
return \in_array($this->getMethod(), ['GET', 'HEAD']);
}
/**
* Returns the protocol version.
*
* If the application is behind a proxy, the protocol version used in the
* requests between the client and the proxy and between the proxy and the
* server might be different. This returns the former (from the "Via" header)
* if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns
* the latter (from the "SERVER_PROTOCOL" server parameter).
*
* @return string
*/
public function getProtocolVersion()
{
if ($this->isFromTrustedProxy()) {
preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches);
if ($matches) {
return 'HTTP/'.$matches[2];
}
}
return $this->server->get('SERVER_PROTOCOL');
}
/**
@@ -1569,7 +1725,7 @@ class Request
return $locales[0];
}
$extendedPreferredLanguages = array();
$extendedPreferredLanguages = [];
foreach ($preferredLanguages as $language) {
$extendedPreferredLanguages[] = $language;
if (false !== $position = strpos($language, '_')) {
@@ -1597,7 +1753,7 @@ class Request
}
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
$this->languages = array();
$this->languages = [];
foreach ($languages as $lang => $acceptHeaderItem) {
if (false !== strpos($lang, '-')) {
$codes = explode('-', $lang);
@@ -1673,7 +1829,7 @@ class Request
* It works if your JavaScript library sets an X-Requested-With HTTP header.
* It is known to work with common JavaScript frameworks:
*
* @see http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
* @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
*
* @return bool true if the request is an XMLHttpRequest, false otherwise
*/
@@ -1685,9 +1841,9 @@ class Request
/*
* The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
*
* Code subject to the new BSD license (http://framework.zend.com/license/new-bsd).
* Code subject to the new BSD license (https://framework.zend.com/license).
*
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (https://www.zend.com/)
*/
protected function prepareRequestUri()
@@ -1701,10 +1857,24 @@ class Request
$this->server->remove('IIS_WasUrlRewritten');
} elseif ($this->server->has('REQUEST_URI')) {
$requestUri = $this->server->get('REQUEST_URI');
// HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, only use URL path
$schemeAndHttpHost = $this->getSchemeAndHttpHost();
if (0 === strpos($requestUri, $schemeAndHttpHost)) {
$requestUri = substr($requestUri, \strlen($schemeAndHttpHost));
if ('' !== $requestUri && '/' === $requestUri[0]) {
// To only use path and query remove the fragment.
if (false !== $pos = strpos($requestUri, '#')) {
$requestUri = substr($requestUri, 0, $pos);
}
} else {
// HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path,
// only use URL path.
$uriComponents = parse_url($requestUri);
if (isset($uriComponents['path'])) {
$requestUri = $uriComponents['path'];
}
if (isset($uriComponents['query'])) {
$requestUri .= '?'.$uriComponents['query'];
}
}
} elseif ($this->server->has('ORIG_PATH_INFO')) {
// IIS 5.0, PHP as CGI
@@ -1797,12 +1967,12 @@ class Request
*/
protected function prepareBasePath()
{
$filename = basename($this->server->get('SCRIPT_FILENAME'));
$baseUrl = $this->getBaseUrl();
if (empty($baseUrl)) {
return '';
}
$filename = basename($this->server->get('SCRIPT_FILENAME'));
if (basename($baseUrl) === $filename) {
$basePath = \dirname($baseUrl);
} else {
@@ -1823,8 +1993,6 @@ class Request
*/
protected function preparePathInfo()
{
$baseUrl = $this->getBaseUrl();
if (null === ($requestUri = $this->getRequestUri())) {
return '/';
}
@@ -1837,12 +2005,14 @@ class Request
$requestUri = '/'.$requestUri;
}
if (null === ($baseUrl = $this->getBaseUrl())) {
return $requestUri;
}
$pathInfo = substr($requestUri, \strlen($baseUrl));
if (null !== $baseUrl && (false === $pathInfo || '' === $pathInfo)) {
if (false === $pathInfo || '' === $pathInfo) {
// If substr() returns false then PATH_INFO is set to an empty string
return '/';
} elseif (null === $baseUrl) {
return $requestUri;
}
return (string) $pathInfo;
@@ -1853,19 +2023,19 @@ class Request
*/
protected static function initializeFormats()
{
static::$formats = array(
'html' => array('text/html', 'application/xhtml+xml'),
'txt' => array('text/plain'),
'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
'css' => array('text/css'),
'json' => array('application/json', 'application/x-json'),
'jsonld' => array('application/ld+json'),
'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
'rdf' => array('application/rdf+xml'),
'atom' => array('application/atom+xml'),
'rss' => array('application/rss+xml'),
'form' => array('application/x-www-form-urlencoded'),
);
static::$formats = [
'html' => ['text/html', 'application/xhtml+xml'],
'txt' => ['text/plain'],
'js' => ['application/javascript', 'application/x-javascript', 'text/javascript'],
'css' => ['text/css'],
'json' => ['application/json', 'application/x-json'],
'jsonld' => ['application/ld+json'],
'xml' => ['text/xml', 'application/xml', 'application/x-xml'],
'rdf' => ['application/rdf+xml'],
'atom' => ['application/atom+xml'],
'rss' => ['application/rss+xml'],
'form' => ['application/x-www-form-urlencoded'],
];
}
/**
@@ -1886,7 +2056,7 @@ class Request
}
}
/*
/**
* Returns the prefix as encoded in the string when the string starts with
* the given prefix, false otherwise.
*
@@ -1910,7 +2080,7 @@ class Request
return false;
}
private static function createRequestFromFactory(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
if (self::$requestFactory) {
$request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
@@ -1925,15 +2095,23 @@ class Request
return new static($query, $request, $attributes, $cookies, $files, $server, $content);
}
private function isFromTrustedProxy()
/**
* Indicates whether this request originated from a trusted proxy.
*
* This can be useful to determine whether or not to trust the
* contents of a proxy-specific header.
*
* @return bool true if the request came from a trusted proxy, false otherwise
*/
public function isFromTrustedProxy()
{
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies);
}
private function getTrustedValues($type, $ip = null)
{
$clientValues = array();
$forwardedValues = array();
$clientValues = [];
$forwardedValues = [];
if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) {
foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) {
@@ -1943,7 +2121,7 @@ class Request
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
$forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
$forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : [];
if (self::HEADER_CLIENT_PORT === $type) {
foreach ($forwardedValues as $k => $v) {
if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) {
@@ -1968,7 +2146,7 @@ class Request
}
if (!$this->isForwardedValid) {
return null !== $ip ? array('0.0.0.0', $ip) : array();
return null !== $ip ? ['0.0.0.0', $ip] : [];
}
$this->isForwardedValid = false;
@@ -1978,7 +2156,7 @@ class Request
private function normalizeAndFilterClientIps(array $clientIps, $ip)
{
if (!$clientIps) {
return array();
return [];
}
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
$firstTrustedIp = null;
@@ -2014,6 +2192,6 @@ class Request
}
// Now the IP chain contains only untrusted proxies and the client IP
return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
}
}