mirror of
https://github.com/itflow-org/itflow
synced 2026-06-18 07:41:05 +00:00
Allow PHP-8.2 and up Compatibility instead of just PHP-8.4
This commit is contained in:
205
plugins/vendor/symfony/http-foundation/Request.php
vendored
205
plugins/vendor/symfony/http-foundation/Request.php
vendored
@@ -62,6 +62,7 @@ class Request
|
||||
public const METHOD_OPTIONS = 'OPTIONS';
|
||||
public const METHOD_TRACE = 'TRACE';
|
||||
public const METHOD_CONNECT = 'CONNECT';
|
||||
public const METHOD_QUERY = 'QUERY';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
@@ -80,6 +81,13 @@ class Request
|
||||
|
||||
protected static bool $httpMethodParameterOverride = false;
|
||||
|
||||
/**
|
||||
* The HTTP methods that can be overridden.
|
||||
*
|
||||
* @var uppercase-string[]|null
|
||||
*/
|
||||
protected static ?array $allowedHttpMethodOverride = null;
|
||||
|
||||
/**
|
||||
* Custom parameters.
|
||||
*/
|
||||
@@ -94,6 +102,8 @@ class Request
|
||||
|
||||
/**
|
||||
* Query string parameters ($_GET).
|
||||
*
|
||||
* @var InputBag<string>
|
||||
*/
|
||||
public InputBag $query;
|
||||
|
||||
@@ -109,6 +119,8 @@ class Request
|
||||
|
||||
/**
|
||||
* Cookies ($_COOKIE).
|
||||
*
|
||||
* @var InputBag<string>
|
||||
*/
|
||||
public InputBag $cookies;
|
||||
|
||||
@@ -194,6 +206,28 @@ class Request
|
||||
self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
|
||||
];
|
||||
|
||||
/**
|
||||
* This mapping is used when no exact MIME match is found in $formats.
|
||||
*
|
||||
* It enables mappings like application/soap+xml -> xml.
|
||||
*
|
||||
* @see https://datatracker.ietf.org/doc/html/rfc6839
|
||||
* @see https://datatracker.ietf.org/doc/html/rfc7303
|
||||
* @see https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||
*/
|
||||
private const STRUCTURED_SUFFIX_FORMATS = [
|
||||
'json' => 'json',
|
||||
'xml' => 'xml',
|
||||
'xhtml' => 'html',
|
||||
'cbor' => 'cbor',
|
||||
'zip' => 'zip',
|
||||
'ber' => 'asn1',
|
||||
'der' => 'asn1',
|
||||
'tlv' => 'tlv',
|
||||
'wbxml' => 'xml',
|
||||
'yaml' => 'yaml',
|
||||
];
|
||||
|
||||
private bool $isIisRewrite = false;
|
||||
|
||||
/**
|
||||
@@ -251,16 +285,30 @@ class Request
|
||||
*/
|
||||
public static function createFromGlobals(): static
|
||||
{
|
||||
$request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
|
||||
|
||||
if (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded')
|
||||
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'], true)
|
||||
) {
|
||||
parse_str($request->getContent(), $data);
|
||||
$request->request = new InputBag($data);
|
||||
if (!\in_array($_SERVER['REQUEST_METHOD'] ?? null, ['PUT', 'DELETE', 'PATCH', 'QUERY'], true)) {
|
||||
return self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
|
||||
}
|
||||
|
||||
return $request;
|
||||
if (\PHP_VERSION_ID < 80400) {
|
||||
if (!isset($_SERVER['CONTENT_TYPE']) || str_starts_with($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded')) {
|
||||
$content = file_get_contents('php://input');
|
||||
parse_str($content, $post);
|
||||
} else {
|
||||
$content = null;
|
||||
$post = $_POST;
|
||||
}
|
||||
|
||||
return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $_FILES, $_SERVER, $content);
|
||||
}
|
||||
|
||||
try {
|
||||
[$post, $files] = request_parse_body();
|
||||
} catch (\RequestParseBodyException) {
|
||||
$post = $_POST;
|
||||
$files = $_FILES;
|
||||
}
|
||||
|
||||
return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $files, $_SERVER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,14 +401,23 @@ class Request
|
||||
$server['PHP_AUTH_PW'] = $components['pass'];
|
||||
}
|
||||
|
||||
if (!isset($components['path'])) {
|
||||
if ('' === $path = $components['path'] ?? '') {
|
||||
$components['path'] = '/';
|
||||
} elseif (!isset($components['scheme']) && !isset($components['host']) && '/' !== $path[0]) {
|
||||
if (false !== $pos = strpos($path, '/')) {
|
||||
$path = substr($path, 0, $pos);
|
||||
}
|
||||
|
||||
if (str_contains($path, ':')) {
|
||||
throw new BadRequestException('Invalid URI: Path is malformed.');
|
||||
}
|
||||
}
|
||||
|
||||
switch (strtoupper($method)) {
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
case 'DELETE':
|
||||
case 'QUERY':
|
||||
if (!isset($server['CONTENT_TYPE'])) {
|
||||
$server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
@@ -451,8 +508,8 @@ class Request
|
||||
$dup->method = null;
|
||||
$dup->format = null;
|
||||
|
||||
if (!$dup->get('_format') && $this->get('_format')) {
|
||||
$dup->attributes->set('_format', $this->get('_format'));
|
||||
if (!$dup->attributes->has('_format') && $this->attributes->has('_format')) {
|
||||
$dup->attributes->set('_format', $this->attributes->get('_format'));
|
||||
}
|
||||
|
||||
if (!$dup->getRequestFormat(null)) {
|
||||
@@ -596,7 +653,7 @@ class Request
|
||||
*/
|
||||
public static function setTrustedHosts(array $hostPatterns): void
|
||||
{
|
||||
self::$trustedHostPatterns = array_map(fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), $hostPatterns);
|
||||
self::$trustedHostPatterns = array_map(static fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), $hostPatterns);
|
||||
// we need to reset trusted hosts on trusted host patterns change
|
||||
self::$trustedHosts = [];
|
||||
}
|
||||
@@ -653,6 +710,34 @@ class Request
|
||||
return self::$httpMethodParameterOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of HTTP methods that can be overridden.
|
||||
*
|
||||
* Set to null to allow all methods to be overridden (default). Set to an
|
||||
* empty array to disallow overrides entirely. Otherwise, provide the list
|
||||
* of uppercased method names that are allowed.
|
||||
*
|
||||
* @param uppercase-string[]|null $methods
|
||||
*/
|
||||
public static function setAllowedHttpMethodOverride(?array $methods): void
|
||||
{
|
||||
if (array_intersect($methods ?? [], ['GET', 'HEAD', 'CONNECT', 'TRACE'])) {
|
||||
throw new \InvalidArgumentException('The HTTP methods "GET", "HEAD", "CONNECT", and "TRACE" cannot be overridden.');
|
||||
}
|
||||
|
||||
self::$allowedHttpMethodOverride = $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of HTTP methods that can be overridden.
|
||||
*
|
||||
* @return uppercase-string[]|null
|
||||
*/
|
||||
public static function getAllowedHttpMethodOverride(): ?array
|
||||
{
|
||||
return self::$allowedHttpMethodOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a "parameter" value from any bag.
|
||||
*
|
||||
@@ -662,10 +747,12 @@ class Request
|
||||
*
|
||||
* Order of precedence: PATH (routing placeholders or custom attributes), GET, POST
|
||||
*
|
||||
* @internal use explicit input sources instead
|
||||
* @deprecated since Symfony 7.4, use properties `->attributes`, `query` or `request` directly instead
|
||||
*/
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
trigger_deprecation('symfony/http-foundation', '7.4', 'Request::get() is deprecated, use properties ->attributes, query or request directly instead.');
|
||||
|
||||
if ($this !== $result = $this->attributes->get($key, $this)) {
|
||||
return $result;
|
||||
}
|
||||
@@ -770,10 +857,6 @@ class Request
|
||||
* being the original client, and each successive proxy that passed the 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 the $trustedHeaderSet
|
||||
* argument of the Request::setTrustedProxies() method instead.
|
||||
*
|
||||
* @see getClientIps()
|
||||
* @see https://wikipedia.org/wiki/X-Forwarded-For
|
||||
*/
|
||||
@@ -797,7 +880,7 @@ class Request
|
||||
*
|
||||
* Suppose this request is instantiated from /mysite on localhost:
|
||||
*
|
||||
* * http://localhost/mysite returns an empty string
|
||||
* * http://localhost/mysite returns '/'
|
||||
* * http://localhost/mysite/about returns '/about'
|
||||
* * http://localhost/mysite/enco%20ded returns '/enco%20ded'
|
||||
* * http://localhost/mysite/about?var=1 returns '/about'
|
||||
@@ -1075,7 +1158,7 @@ class Request
|
||||
|
||||
$https = $this->server->get('HTTPS');
|
||||
|
||||
return $https && 'off' !== strtolower($https);
|
||||
return $https && (!\is_string($https) || 'off' !== strtolower($https));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1092,10 +1175,8 @@ class Request
|
||||
{
|
||||
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
|
||||
$host = $host[0];
|
||||
} elseif (!$host = $this->headers->get('HOST')) {
|
||||
if (!$host = $this->server->get('SERVER_NAME')) {
|
||||
$host = $this->server->get('SERVER_ADDR', '');
|
||||
}
|
||||
} else {
|
||||
$host = $this->headers->get('HOST') ?: $this->server->get('SERVER_NAME') ?: $this->server->get('SERVER_ADDR', '');
|
||||
}
|
||||
|
||||
// trim and remove port number from host
|
||||
@@ -1168,7 +1249,7 @@ class Request
|
||||
|
||||
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
|
||||
|
||||
if ('POST' !== $this->method) {
|
||||
if ('POST' !== $this->method || !(self::$allowedHttpMethodOverride ?? true)) {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
@@ -1184,11 +1265,15 @@ class Request
|
||||
|
||||
$method = strtoupper($method);
|
||||
|
||||
if (\in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'PATCH', 'PURGE', 'TRACE'], true)) {
|
||||
return $this->method = $method;
|
||||
if (\in_array($method, ['GET', 'HEAD', 'CONNECT', 'TRACE'], true)) {
|
||||
trigger_deprecation('symfony/http-foundation', '7.4', 'HTTP method override is deprecated for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0.', $method);
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Z]++$/D', $method)) {
|
||||
if (self::$allowedHttpMethodOverride && !\in_array($method, self::$allowedHttpMethodOverride, true)) {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
if (\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) {
|
||||
throw new SuspiciousOperationException('Invalid HTTP method override.');
|
||||
}
|
||||
|
||||
@@ -1233,9 +1318,22 @@ class Request
|
||||
|
||||
/**
|
||||
* Gets the format associated with the mime type.
|
||||
*
|
||||
* Resolution order:
|
||||
* 1) Exact match on the full MIME type (e.g. "application/json").
|
||||
* 2) Match on the canonical MIME type (i.e. before the first ";" parameter).
|
||||
* 3) If the type is "application/*+suffix", use the structured syntax suffix
|
||||
* mapping (e.g. "application/foo+json" → "json"), when available.
|
||||
* 4) If $subtypeFallback is true and no match was found:
|
||||
* - return the MIME subtype (without "x-" prefix), provided it does not
|
||||
* contain a "+" (e.g. "application/x-yaml" → "yaml", "text/csv" → "csv").
|
||||
*
|
||||
* @param string|null $mimeType The mime type to check
|
||||
* @param bool $subtypeFallback Whether to fall back to the subtype if no exact match is found
|
||||
*/
|
||||
public function getFormat(?string $mimeType): ?string
|
||||
public function getFormat(?string $mimeType/* , bool $subtypeFallback = false */): ?string
|
||||
{
|
||||
$subtypeFallback = 2 <= \func_num_args() ? func_get_arg(1) : false;
|
||||
$canonicalMimeType = null;
|
||||
if ($mimeType && false !== $pos = strpos($mimeType, ';')) {
|
||||
$canonicalMimeType = trim(substr($mimeType, 0, $pos));
|
||||
@@ -1261,21 +1359,48 @@ class Request
|
||||
return $format;
|
||||
}
|
||||
|
||||
if (!$canonicalMimeType ??= $mimeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str_starts_with($canonicalMimeType, 'application/') && str_contains($canonicalMimeType, '+')) {
|
||||
$suffix = substr(strrchr($canonicalMimeType, '+'), 1);
|
||||
if (isset(self::STRUCTURED_SUFFIX_FORMATS[$suffix])) {
|
||||
return self::STRUCTURED_SUFFIX_FORMATS[$suffix];
|
||||
}
|
||||
}
|
||||
|
||||
if ($subtypeFallback && str_contains($canonicalMimeType, '/')) {
|
||||
[, $subtype] = explode('/', $canonicalMimeType, 2);
|
||||
if (str_starts_with($subtype, 'x-')) {
|
||||
$subtype = substr($subtype, 2);
|
||||
}
|
||||
if (!str_contains($subtype, '+')) {
|
||||
return $subtype;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a format with mime types.
|
||||
*
|
||||
* @param string $format The format to set
|
||||
* @param string|string[] $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
|
||||
*/
|
||||
public function setFormat(?string $format, string|array $mimeTypes): void
|
||||
{
|
||||
if (null === $format) {
|
||||
trigger_deprecation('symfony/http-foundation', '7.4', 'Passing "null" as the first argument of "%s()" is deprecated. The argument will be non-nullable in Symfony 8.0.', __METHOD__);
|
||||
$format = '';
|
||||
}
|
||||
|
||||
if (null === static::$formats) {
|
||||
static::initializeFormats();
|
||||
}
|
||||
|
||||
static::$formats[$format ?? ''] = (array) $mimeTypes;
|
||||
static::$formats[$format] = (array) $mimeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1367,7 +1492,7 @@ class Request
|
||||
*/
|
||||
public function isMethodSafe(): bool
|
||||
{
|
||||
return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']);
|
||||
return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE', 'QUERY'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1375,7 +1500,7 @@ class Request
|
||||
*/
|
||||
public function isMethodIdempotent(): bool
|
||||
{
|
||||
return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE']);
|
||||
return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE', 'QUERY'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1385,7 +1510,7 @@ class Request
|
||||
*/
|
||||
public function isMethodCacheable(): bool
|
||||
{
|
||||
return \in_array($this->getMethod(), ['GET', 'HEAD']);
|
||||
return \in_array($this->getMethod(), ['GET', 'HEAD', 'QUERY'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1421,10 +1546,8 @@ class Request
|
||||
*/
|
||||
public function getContent(bool $asResource = false)
|
||||
{
|
||||
$currentContentIsResource = \is_resource($this->content);
|
||||
|
||||
if (true === $asResource) {
|
||||
if ($currentContentIsResource) {
|
||||
if ($asResource) {
|
||||
if (\is_resource($this->content)) {
|
||||
rewind($this->content);
|
||||
|
||||
return $this->content;
|
||||
@@ -1444,7 +1567,7 @@ class Request
|
||||
return fopen('php://input', 'r');
|
||||
}
|
||||
|
||||
if ($currentContentIsResource) {
|
||||
if (\is_resource($this->content)) {
|
||||
rewind($this->content);
|
||||
|
||||
return stream_get_contents($this->content);
|
||||
@@ -1932,6 +2055,14 @@ class Request
|
||||
'atom' => ['application/atom+xml'],
|
||||
'rss' => ['application/rss+xml'],
|
||||
'form' => ['application/x-www-form-urlencoded', 'multipart/form-data'],
|
||||
'soap' => ['application/soap+xml'],
|
||||
'problem' => ['application/problem+json'],
|
||||
'hal' => ['application/hal+json', 'application/hal+xml'],
|
||||
'jsonapi' => ['application/vnd.api+json'],
|
||||
'yaml' => ['text/yaml', 'application/x-yaml'],
|
||||
'wbxml' => ['application/vnd.wap.wbxml'],
|
||||
'pdf' => ['application/pdf'],
|
||||
'csv' => ['text/csv'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user