Skip to content

Commit aaa0057

Browse files
committed
Make populate_post_data() accept streams
1 parent d2705c0 commit aaa0057

11 files changed

+161
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
populate_post_data() with multipart stream
3+
--FILE--
4+
<?php
5+
6+
$stream = fopen('php://memory','r+');
7+
fwrite($stream, <<<'BODY'
8+
-----------------------------84000087610663814162942123332
9+
Content-Disposition: form-data; name="post_field_name"
10+
11+
post field data
12+
-----------------------------84000087610663814162942123332
13+
Content-Disposition: form-data; name="file_name"; filename="original_file_name.txt"
14+
Content-Type: text/plain
15+
16+
file data
17+
-----------------------------84000087610663814162942123332--
18+
BODY);
19+
rewind($stream);
20+
21+
[$_POST, $_FILES] = populate_post_data($stream, 'multipart/form-data; boundary=---------------------------84000087610663814162942123332');
22+
23+
var_dump($_POST, $_FILES);
24+
25+
$file_path = __DIR__ . '/put_multipart_uploaded_file.txt';
26+
move_uploaded_file($_FILES['file_name']['tmp_name'], $file_path);
27+
var_dump(file_get_contents($file_path));
28+
29+
?>
30+
--CLEAN--
31+
<?php
32+
$file_path = __DIR__ . '/put_multipart_uploaded_file.txt';
33+
@unlink($file_path);
34+
?>
35+
--EXPECTF--
36+
array(1) {
37+
["post_field_name"]=>
38+
string(15) "post field data"
39+
}
40+
array(1) {
41+
["file_name"]=>
42+
array(6) {
43+
["name"]=>
44+
string(22) "original_file_name.txt"
45+
["full_path"]=>
46+
string(22) "original_file_name.txt"
47+
["type"]=>
48+
string(10) "text/plain"
49+
["tmp_name"]=>
50+
string(%d) "%s"
51+
["error"]=>
52+
int(0)
53+
["size"]=>
54+
int(9)
55+
}
56+
}
57+
string(9) "file data"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
populate_post_data() with urlencoded stream
3+
--FILE--
4+
<?php
5+
6+
$stream = fopen('php://memory','r+');
7+
fwrite($stream, 'foo=foo&bar[]=1&bar[]=2');
8+
rewind($stream);
9+
10+
[$_POST, $_FILES] = populate_post_data($stream, 'application/x-www-form-urlencoded');
11+
12+
var_dump($_POST, $_FILES);
13+
14+
?>
15+
--CLEAN--
16+
<?php
17+
$file_path = __DIR__ . '/put_multipart_uploaded_file.txt';
18+
@unlink($file_path);
19+
?>
20+
--EXPECT--
21+
array(2) {
22+
["foo"]=>
23+
string(3) "foo"
24+
["bar"]=>
25+
array(2) {
26+
[0]=>
27+
string(1) "1"
28+
[1]=>
29+
string(1) "2"
30+
}
31+
}
32+
array(0) {
33+
}

ext/standard/basic_functions.stub.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -2264,10 +2264,11 @@ function htmlentities(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE |
22642264
function get_html_translation_table(int $table = HTML_SPECIALCHARS, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, string $encoding = "UTF-8"): array {}
22652265

22662266
/**
2267+
* @param resource|null $input_stream
22672268
* @return array<int, array>
22682269
* @refcount 1
22692270
*/
2270-
function populate_post_data(): array {}
2271+
function populate_post_data($input_stream = null, string $content_type = null): array {}
22712272

22722273
/* }}} */
22732274

ext/standard/basic_functions_arginfo.h

+5-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/html.c

+19-4
Original file line numberDiff line numberDiff line change
@@ -1562,16 +1562,31 @@ PHP_FUNCTION(get_html_translation_table)
15621562

15631563
PHP_FUNCTION(populate_post_data)
15641564
{
1565-
ZEND_PARSE_PARAMETERS_NONE();
1565+
zval *input_stream_zv = NULL;
1566+
zend_string *content_type = NULL;
15661567

1567-
if (!SG(server_context) || !SG(request_info).content_type) {
1568-
return;
1568+
ZEND_PARSE_PARAMETERS_START(0, 2)
1569+
Z_PARAM_OPTIONAL
1570+
Z_PARAM_RESOURCE_OR_NULL(input_stream_zv)
1571+
Z_PARAM_STR_OR_NULL(content_type)
1572+
ZEND_PARSE_PARAMETERS_END();
1573+
1574+
if (!content_type && input_stream_zv) {
1575+
zend_throw_error(NULL, "$content_type must be set if $input_stream is passed");
1576+
} else if (content_type && !input_stream_zv) {
1577+
zend_throw_error(NULL, "$content_type must not be set if $input_stream is not passed");
1578+
}
1579+
1580+
php_stream *input_stream = NULL;
1581+
if (input_stream_zv) {
1582+
php_stream_from_zval(input_stream, input_stream_zv);
15691583
}
1584+
SG(rfc1867_input_stream) = input_stream;
15701585

15711586
zval post, files;
15721587
array_init(&post);
15731588
array_init(&files);
1574-
sapi_read_post_data();
1589+
sapi_read_post_data_ex(content_type ? ZSTR_VAL(content_type) : SG(request_info).content_type);
15751590
sapi_handle_post_ex(&post, &files);
15761591
RETURN_ARR(zend_new_pair(&post, &files));
15771592
}

main/SAPI.c

+13-3
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,11 @@ SAPI_API void sapi_handle_post(zval *arg)
174174
sapi_handle_post_ex(arg, NULL);
175175
}
176176

177-
SAPI_API void sapi_read_post_data(void)
177+
SAPI_API void sapi_read_post_data_ex(const char *content_type_)
178178
{
179179
sapi_post_entry *post_entry;
180-
uint32_t content_type_length = (uint32_t)strlen(SG(request_info).content_type);
181-
char *content_type = estrndup(SG(request_info).content_type, content_type_length);
180+
uint32_t content_type_length = (uint32_t)strlen(content_type_);
181+
char *content_type = estrndup(content_type_, content_type_length);
182182
char *p;
183183
char oldchar=0;
184184
void (*post_reader_func)(void) = NULL;
@@ -236,6 +236,11 @@ SAPI_API void sapi_read_post_data(void)
236236
}
237237
}
238238

239+
SAPI_API void sapi_read_post_data(void)
240+
{
241+
sapi_read_post_data_ex(SG(request_info).content_type);
242+
}
243+
239244
SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
240245
{
241246
size_t read_bytes;
@@ -260,6 +265,10 @@ SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
260265

261266
SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
262267
{
268+
if (SG(rfc1867_input_stream)) {
269+
return;
270+
}
271+
263272
if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
264273
php_error_docref(NULL, E_WARNING, "POST Content-Length of " ZEND_LONG_FMT " bytes exceeds the limit of " ZEND_LONG_FMT " bytes",
265274
SG(request_info).content_length, SG(post_max_size));
@@ -462,6 +471,7 @@ SAPI_API void sapi_activate(void)
462471
SG(request_info).headers_only = 0;
463472
}
464473
SG(rfc1867_uploaded_files) = NULL;
474+
SG(rfc1867_input_stream) = NULL;
465475

466476
/* Handle request method */
467477
if (SG(server_context)) {

main/SAPI.h

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ typedef struct _sapi_globals_struct {
120120
char *default_mimetype;
121121
char *default_charset;
122122
HashTable *rfc1867_uploaded_files;
123+
php_stream *rfc1867_input_stream;
123124
zend_long post_max_size;
124125
int options;
125126
bool sapi_started;
@@ -188,6 +189,7 @@ SAPI_API void sapi_free_header(sapi_header_struct *sapi_header);
188189
SAPI_API void sapi_handle_post(zval *arg);
189190
SAPI_API void sapi_handle_post_ex(zval *arg, zval *files);
190191
SAPI_API void sapi_read_post_data(void);
192+
SAPI_API void sapi_read_post_data_ex(const char *content_type);
191193
SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen);
192194
SAPI_API int sapi_register_post_entries(const sapi_post_entry *post_entry);
193195
SAPI_API int sapi_register_post_entry(const sapi_post_entry *post_entry);

main/php_content_types.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static const sapi_post_entry php_post_entries[] = {
3131
/* {{{ SAPI_POST_READER_FUNC */
3232
SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader)
3333
{
34-
if (!strcmp(SG(request_info).request_method, "POST")) {
34+
if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "POST")) {
3535
if (NULL == SG(request_info).post_entry) {
3636
/* no post handler registered, so we just swallow the data */
3737
sapi_read_standard_form_data();

main/php_variables.c

+13-1
Original file line numberDiff line numberDiff line change
@@ -405,17 +405,29 @@ static inline int add_post_vars(zval *arr, post_var_data_t *vars, bool eof, bool
405405
SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler)
406406
{
407407
zval *arr = (zval *) arg;
408-
php_stream *s = SG(request_info).request_body;
408+
php_stream *s = SG(rfc1867_input_stream) ? SG(rfc1867_input_stream) : SG(request_info).request_body;
409409
post_var_data_t post_data;
410410
bool store_in_global = files == NULL;
411411

412412
if (s && SUCCESS == php_stream_rewind(s)) {
413+
ssize_t total_len = 0;
414+
zend_long post_max_size = SG(post_max_size);
415+
bool check_post_max_size = s == SG(rfc1867_input_stream);
416+
413417
memset(&post_data, 0, sizeof(post_data));
414418

415419
while (!php_stream_eof(s)) {
416420
char buf[SAPI_POST_HANDLER_BUFSIZ] = {0};
417421
ssize_t len = php_stream_read(s, buf, SAPI_POST_HANDLER_BUFSIZ);
418422

423+
if (UNEXPECTED(check_post_max_size)) {
424+
total_len += len;
425+
if ((post_max_size > 0) && (total_len > SG(post_max_size))) {
426+
php_error_docref(NULL, E_WARNING, "POST length exceeds post_max_size (" ZEND_LONG_FMT " bytes)", SG(post_max_size));
427+
break;
428+
}
429+
}
430+
419431
if (len > 0) {
420432
smart_str_appendl(&post_data.str, buf, len);
421433

main/rfc1867.c

+14-2
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,18 @@ static int fill_buffer(multipart_buffer *self)
222222
/* calculate the free space in the buffer */
223223
bytes_to_read = self->bufsize - self->bytes_in_buffer;
224224

225+
php_stream *input_stream = SG(rfc1867_input_stream);
226+
225227
/* read the required number of bytes */
226228
while (bytes_to_read > 0) {
227229

228230
char *buf = self->buffer + self->bytes_in_buffer;
229231

230-
actual_read = (int)sapi_module.read_post(buf, bytes_to_read);
232+
if (EXPECTED(input_stream == NULL)) {
233+
actual_read = (int)sapi_module.read_post(buf, bytes_to_read);
234+
} else {
235+
actual_read = php_stream_read(input_stream, buf, bytes_to_read);
236+
}
231237

232238
/* update the buffer length */
233239
if (actual_read > 0) {
@@ -646,7 +652,7 @@ static char *multipart_buffer_read_body(multipart_buffer *self, size_t *len)
646652
*
647653
*/
648654

649-
SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
655+
static void rfc1867_post_handler_ex(char *content_type_dup, zval *arg, zval *files)
650656
{
651657
char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
652658
char *lbuf = NULL, *abuf = NULL;
@@ -1269,6 +1275,12 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
12691275
}
12701276
/* }}} */
12711277

1278+
SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
1279+
{
1280+
rfc1867_post_handler_ex(content_type_dup, arg, files);
1281+
SG(rfc1867_input_stream) = NULL;
1282+
}
1283+
12721284
SAPI_API void php_rfc1867_set_multibyte_callbacks(
12731285
php_rfc1867_encoding_translation_t encoding_translation,
12741286
php_rfc1867_get_detect_order_t get_detect_order,

sapi/cli/php_cli_server.c

+2
Original file line numberDiff line numberDiff line change
@@ -2214,6 +2214,7 @@ static void php_cli_server_request_shutdown(php_cli_server *server, php_cli_serv
22142214
destroy_request_info(&SG(request_info));
22152215
SG(server_context) = NULL;
22162216
SG(rfc1867_uploaded_files) = NULL;
2217+
SG(rfc1867_input_stream) = NULL;
22172218
}
22182219
/* }}} */
22192220

@@ -2303,6 +2304,7 @@ static zend_result php_cli_server_dispatch(php_cli_server *server, php_cli_serve
23032304
sapi_module.send_headers = send_header_func;
23042305
SG(sapi_headers).send_default_content_type = 1;
23052306
SG(rfc1867_uploaded_files) = NULL;
2307+
SG(rfc1867_input_stream) = NULL;
23062308
}
23072309
if (FAILURE == php_cli_server_begin_send_static(server, client)) {
23082310
php_cli_server_close_connection(server, client);

0 commit comments

Comments
 (0)