Skip to content

Commit ab4d8fe

Browse files
committed
Add populate_post_data() function
This function allows populating the $_POST and $_FILES globals for non-post requests. This avoids manual parsing of RFC1867 requests. Fixes #55815
1 parent 3a4091c commit ab4d8fe

File tree

7 files changed

+121
-5
lines changed

7 files changed

+121
-5
lines changed

ext/standard/basic_functions.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2263,6 +2263,8 @@ function htmlentities(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE |
22632263
*/
22642264
function get_html_translation_table(int $table = HTML_SPECIALCHARS, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, string $encoding = "UTF-8"): array {}
22652265

2266+
function populate_post_data(): void {}
2267+
22662268
/* }}} */
22672269

22682270
/* assert.c */

ext/standard/basic_functions_arginfo.h

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/html.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,3 +1559,23 @@ PHP_FUNCTION(get_html_translation_table)
15591559
}
15601560
}
15611561
/* }}} */
1562+
1563+
PHP_FUNCTION(populate_post_data)
1564+
{
1565+
ZEND_PARSE_PARAMETERS_NONE();
1566+
1567+
if (!SG(server_context) || !SG(request_info).content_type) {
1568+
return;
1569+
}
1570+
1571+
zval_ptr_dtor_nogc(&PG(http_globals)[TRACK_VARS_POST]);
1572+
zval_ptr_dtor_nogc(&PG(http_globals)[TRACK_VARS_FILES]);
1573+
array_init(&PG(http_globals)[TRACK_VARS_POST]);
1574+
array_init(&PG(http_globals)[TRACK_VARS_FILES]);
1575+
sapi_read_post_data();
1576+
sapi_handle_post(&PG(http_globals)[TRACK_VARS_POST]);
1577+
zend_hash_update(&EG(symbol_table), zend_string_init_interned(ZEND_STRL("_POST"), 1), &PG(http_globals)[TRACK_VARS_POST]);
1578+
zend_hash_update(&EG(symbol_table), zend_string_init_interned(ZEND_STRL("_FILES"), 1), &PG(http_globals)[TRACK_VARS_FILES]);
1579+
Z_ADDREF(PG(http_globals)[TRACK_VARS_POST]);
1580+
Z_ADDREF(PG(http_globals)[TRACK_VARS_FILES]);
1581+
}

main/SAPI.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ SAPI_API void sapi_handle_post(void *arg)
169169
}
170170
}
171171

172-
static void sapi_read_post_data(void)
172+
SAPI_API void sapi_read_post_data(void)
173173
{
174174
sapi_post_entry *post_entry;
175175
uint32_t content_type_length = (uint32_t)strlen(SG(request_info).content_type);

main/SAPI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ SAPI_API int sapi_add_header_ex(const char *header_line, size_t header_line_len,
186186
SAPI_API int sapi_send_headers(void);
187187
SAPI_API void sapi_free_header(sapi_header_struct *sapi_header);
188188
SAPI_API void sapi_handle_post(void *arg);
189+
SAPI_API void sapi_read_post_data(void);
189190
SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen);
190191
SAPI_API int sapi_register_post_entries(const sapi_post_entry *post_entry);
191192
SAPI_API int sapi_register_post_entry(const sapi_post_entry *post_entry);

sapi/fpm/tests/put_multipart.phpt

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
--TEST--
2+
PUT multipart
3+
--EXTENSIONS--
4+
zend_test
5+
--SKIPIF--
6+
<?php include "skipif.inc"; ?>
7+
--FILE--
8+
<?php
9+
10+
require_once "tester.inc";
11+
12+
$cfg = <<<EOT
13+
[global]
14+
error_log = {{FILE:LOG}}
15+
[unconfined]
16+
listen = {{ADDR}}
17+
pm = dynamic
18+
pm.max_children = 5
19+
pm.start_servers = 1
20+
pm.min_spare_servers = 1
21+
pm.max_spare_servers = 3
22+
EOT;
23+
24+
$code = <<<'EOT'
25+
<?php
26+
populate_post_data();
27+
$file_path = __DIR__ . '/put_multipart_uploaded_file.txt';
28+
move_uploaded_file($_FILES[0]['tmp_name'], $file_path);
29+
$file_content = file_get_contents($file_path);
30+
unlink($file_path);
31+
echo json_encode([
32+
'post' => $_POST,
33+
'files' => $_FILES,
34+
'file_content' => $file_content,
35+
], JSON_PRETTY_PRINT);
36+
EOT;
37+
38+
$tester = new FPM\Tester($cfg, $code);
39+
$tester->start();
40+
$tester->expectLogStartNotices();
41+
echo $tester
42+
->request(method: 'PUT', stdin: [
43+
'parts' => [
44+
[
45+
"disposition" => "form-data",
46+
"param" => "name",
47+
"name" => "get_parameter",
48+
"value" => "foo",
49+
],
50+
[
51+
"disposition" => "form-data",
52+
"param" => "filename",
53+
"name" => "uploaded_file",
54+
"value" => "bar",
55+
],
56+
],
57+
])
58+
->getBody();
59+
$tester->terminate();
60+
$tester->expectLogTerminatingNotices();
61+
$tester->close();
62+
63+
?>
64+
--EXPECTF--
65+
{
66+
"post": {
67+
"get_parameter": "foo"
68+
},
69+
"files": [
70+
{
71+
"name": "uploaded_file",
72+
"full_path": "uploaded_file",
73+
"type": "",
74+
"tmp_name": "%s",
75+
"error": 0,
76+
"size": 3
77+
}
78+
],
79+
"file_content": "bar"
80+
}
81+
--CLEAN--
82+
<?php
83+
require_once "tester.inc";
84+
FPM\Tester::clean();
85+
$file_path = __DIR__ . '/put_multipart_uploaded_file.txt';
86+
@unlink($file_path);
87+
?>

sapi/fpm/tests/tester.inc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,8 @@ class Tester
687687
string $uri = null,
688688
string $scriptFilename = null,
689689
string $scriptName = null,
690-
?string $stdin = null
690+
?string $stdin = null,
691+
?string $method = null,
691692
): array {
692693
if (is_null($scriptFilename)) {
693694
$scriptFilename = $this->makeSourceFile();
@@ -702,7 +703,7 @@ class Tester
702703
$params = array_merge(
703704
[
704705
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
705-
'REQUEST_METHOD' => is_null($stdin) ? 'GET' : 'POST',
706+
'REQUEST_METHOD' => $method ?? (is_null($stdin) ? 'GET' : 'POST'),
706707
'SCRIPT_FILENAME' => $scriptFilename === '' ? null : $scriptFilename,
707708
'SCRIPT_NAME' => $scriptName,
708709
'QUERY_STRING' => $query,
@@ -824,6 +825,7 @@ class Tester
824825
bool $expectError = false,
825826
int $readLimit = -1,
826827
int $writeDelay = 0,
828+
?string $method = null,
827829
): Response {
828830
if ($this->hasError()) {
829831
return new Response(null, true);
@@ -833,7 +835,7 @@ class Tester
833835
$stdin = $this->parseStdin($stdin, $headers);
834836
}
835837

836-
$params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin);
838+
$params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin, $method);
837839
$this->trace('Request params', $params);
838840

839841
try {

0 commit comments

Comments
 (0)