Search code examples
phpcurlphp-8

CURLOPT_POSTFIELDS not accepting array


Why isn't CURLOPT_POSTFIELDs accepting an array? Using PHP 8.2.15

I have two files:

// temp.php

exit(file_get_contents('php://input'));
// test.php

$fields = ['foo' => 'bar'];

$config = [
    \CURLOPT_RETURNTRANSFER => true,
    \CURLOPT_ENCODING => '',
    \CURLOPT_MAXREDIRS => 10,
    \CURLOPT_TIMEOUT => 10,
    \CURLOPT_FOLLOWLOCATION => true,
    \CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
];

$with_array_handle = \curl_init('http://localhost/temp.php');
\curl_setopt_array($with_array_handle, $config + [\CURLOPT_POSTFIELDS => $fields]);


$with_string_handle = \curl_init('http://localhost/temp.php');
\curl_setopt_array($with_string_handle, $config + [\CURLOPT_POSTFIELDS => http_build_query($fields)]);

echo '<pre>' . curl_exec($with_array_handle) . '</pre>';
echo '<pre>' . curl_exec($with_string_handle) . '</pre>';

temp.php echos back the request body. test.php requests temp.php twice and echoes both responses so test.php should be outputting the bodies of both requests to temp.php.

but what I'm actually getting is


foo=bar

The first request's body is empty if I use CURLOPT_POSTFIELDS. Why? The PHP documentation specifically says CURLOPT_POSTFIELDS accepts an array as input but that doesn't match the behavior I'm observing.

This parameter can either be passed as a urlencoded string like para1=val1&para2=val2&... or as an array with the field name as key and field data as value.


Solution

  • When you give it an array, the request is sent with Content-type: multipart/form-data. Apparently this causes the PHP processor to read the body itself, and it's not available to php://input. I suspect this is because this format is usually used for file uploads, so it needs to read the uploaded files into their temporary files, and built the $_FILES array; it would be difficult to keep it available for the input stream to re-read.

    In either case, the parameters are available in the $_POST array.