Skip to content

Commit bd1af1e

Browse files
[HttpFoundation] Improve logic in Request::createFromGlobals()
1 parent 1f76f44 commit bd1af1e

File tree

2 files changed

+80
-25
lines changed

2 files changed

+80
-25
lines changed

Request.php

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -285,26 +285,30 @@ public function initialize(array $query = [], array $request = [], array $attrib
285285
*/
286286
public static function createFromGlobals(): static
287287
{
288-
$request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
289-
290-
if (!\in_array($request->server->get('REQUEST_METHOD', 'GET'), ['PUT', 'DELETE', 'PATCH', 'QUERY'], true)) {
291-
return $request;
288+
if (!\in_array($_SERVER['REQUEST_METHOD'] ?? null, ['PUT', 'DELETE', 'PATCH', 'QUERY'], true)) {
289+
return self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
292290
}
293291

294-
if (\PHP_VERSION_ID >= 80400) {
295-
try {
296-
[$post, $files] = request_parse_body();
297-
298-
$request->request->add($post);
299-
$request->files->add($files);
300-
} catch (\RequestParseBodyException) {
292+
if (\PHP_VERSION_ID < 80400) {
293+
if (!isset($_SERVER['CONTENT_TYPE']) || str_starts_with($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded')) {
294+
$content = file_get_contents('php://input');
295+
parse_str($content, $post);
296+
} else {
297+
$content = null;
298+
$post = $_POST;
301299
}
302-
} elseif (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded')) {
303-
parse_str($request->getContent(), $data);
304-
$request->request = new InputBag($data);
300+
301+
return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $_FILES, $_SERVER, $content);
305302
}
306303

307-
return $request;
304+
try {
305+
[$post, $files] = request_parse_body();
306+
} catch (\RequestParseBodyException) {
307+
$post = $_POST;
308+
$files = $_FILES;
309+
}
310+
311+
return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $files, $_SERVER);
308312
}
309313

310314
/**
@@ -1538,10 +1542,8 @@ public function getProtocolVersion(): ?string
15381542
*/
15391543
public function getContent(bool $asResource = false)
15401544
{
1541-
$currentContentIsResource = \is_resource($this->content);
1542-
1543-
if (true === $asResource) {
1544-
if ($currentContentIsResource) {
1545+
if ($asResource) {
1546+
if (\is_resource($this->content)) {
15451547
rewind($this->content);
15461548

15471549
return $this->content;
@@ -1561,7 +1563,7 @@ public function getContent(bool $asResource = false)
15611563
return fopen('php://input', 'r');
15621564
}
15631565

1564-
if ($currentContentIsResource) {
1566+
if (\is_resource($this->content)) {
15651567
rewind($this->content);
15661568

15671569
return stream_get_contents($this->content);

Tests/RequestTest.php

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,9 +1431,17 @@ public function testFormUrlEncodedBodyParsing(string $method)
14311431
$_SERVER['REQUEST_METHOD'] = $method;
14321432
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
14331433

1434-
$request = RequestContentProxy::createFromGlobals();
1434+
MockPhpStreamWrapper::setInputContent('content=mycontent');
1435+
stream_wrapper_unregister('php');
1436+
stream_wrapper_register('php', MockPhpStreamWrapper::class);
14351437

1436-
$this->assertEquals('mycontent', $request->request->get('content'));
1438+
try {
1439+
$request = Request::createFromGlobals();
1440+
1441+
$this->assertSame('mycontent', $request->request->get('content'));
1442+
} finally {
1443+
stream_wrapper_restore('php');
1444+
}
14371445
}
14381446

14391447
public function testOverrideGlobals()
@@ -3050,11 +3058,56 @@ public static function providePreferredFormatRfc9110(): iterable
30503058
}
30513059
}
30523060

3053-
class RequestContentProxy extends Request
3061+
class MockPhpStreamWrapper
30543062
{
3055-
public function getContent($asResource = false)
3063+
/** @var resource|null */
3064+
public $context;
3065+
3066+
private static string $inputContent = '';
3067+
private string $content = '';
3068+
private int $position = 0;
3069+
3070+
public static function setInputContent(string $content): void
3071+
{
3072+
self::$inputContent = $content;
3073+
}
3074+
3075+
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
3076+
{
3077+
if ('php://input' === $path) {
3078+
$this->content = self::$inputContent;
3079+
$this->position = 0;
3080+
3081+
return true;
3082+
}
3083+
3084+
return false;
3085+
}
3086+
3087+
public function stream_read(int $count): string
3088+
{
3089+
$result = substr($this->content, $this->position, $count);
3090+
$this->position += \strlen($result);
3091+
3092+
return $result;
3093+
}
3094+
3095+
public function stream_eof(): bool
3096+
{
3097+
return $this->position >= \strlen($this->content);
3098+
}
3099+
3100+
public function stream_stat(): array
30563101
{
3057-
return http_build_query(['content' => 'mycontent'], '', '&');
3102+
return [
3103+
'size' => \strlen($this->content),
3104+
'mode' => 0,
3105+
'uid' => 0,
3106+
'gid' => 0,
3107+
'atime' => 0,
3108+
'mtime' => 0,
3109+
'ctime' => 0,
3110+
];
30583111
}
30593112
}
30603113

0 commit comments

Comments
 (0)