2

The following will use cURL to send data as well as files using content-type application/x-www-form-urlencoded.

I do not wish to use Content-Type: application/x-www-form-urlencoded but instead use Content-Type: application/json.

I can successfully send just data using Content-Type: application/json.

How can one send both data and files using Content-Type: application/json?

Below code x-www-form-urlencoded only and is given for reference only

<?php
//Given:
$method='post';
$url='http://php.net/manual/en/function.curl-setopt.php';
$data=['hello'=>123];
$files=["image"=>["name" => "picture.jpg","type" => "image/jpeg","tmp_name" => "/path/on/server/to/tmp/phprj5rkG","error" => 0,"size" => 174476]];

//For using content-type application/x-www-form-urlencoded

$postData = [];
if($files) {
    //cURL doesn't work out of the box with both files and POST data.
    foreach ($files as $name=>$file){
        $postData[$name] = new \CURLFile($file['tmp_name'],$file['type'],$file['name']);
    }
    if($data) {
        foreach (explode('&', http_build_query($data)) as $pair){
            list($name, $value) = explode('=', $pair, 2);
            $postData[urldecode($name)] = urldecode($value);
        }
    }
}
else {
    $postData=http_build_query($data);
}

$options=[
    CURLOPT_RETURNTRANSFER => true,     // return web page
    CURLOPT_HEADER         => false,    // don't return headers
    CURLOPT_FOLLOWLOCATION => true,     // follow redirects
    CURLOPT_ENCODING       => "",       // handle all encodings
    CURLOPT_AUTOREFERER    => true,     // set referrer on redirect
];
switch ($method) {
    case "get":
        if ($postData) {$url = sprintf("%s?%s", $url, $postData);}
        break;
    case "post":
        $options[CURLOPT_POST]=1;
        $options[CURLOPT_POSTFIELDS]=$postData?$postData:'';
        break;
    case "put":
        $options[CURLOPT_CUSTOMREQUEST]="PUT";
        if ($postData) {$options[CURLOPT_POSTFIELDS]=$postData;}
        break;
    case "delete":
        $options[CURLOPT_CUSTOMREQUEST]="DELETE";
        if ($postData) {$options[CURLOPT_POSTFIELDS]=$postData;}
        break;
}
$options[CURLOPT_URL]=$url;
$ch      = curl_init();
curl_setopt_array( $ch, $options );

$rsp=curl_exec( $ch );
user1032531
  • 24,767
  • 68
  • 217
  • 387
  • unless you convert all your file data to base64-encoded text and set the content as the value of an attribute within your JSON object, then you can't. JSON is a text-only format. The normal way to send both files and data in a HTTP request is to use a [multi-part request](https://stackoverflow.com/questions/16958448/what-is-http-multipart-request) which has its own structure and content-type. It's split into parts (one part for each file, and a separate part at the end for any other textual data) – ADyson Dec 19 '18 at 14:09
  • @ADyson Converting to base64 seems to bring more complication than benefit. I guess I need to use multi-part as you stated and add the the json text to the "separate part at the end for any other textual data", right? How should one inform the receiver that this text is json encoded and not x-www-form-urlencoded? Thanks! – user1032531 Dec 19 '18 at 14:17
  • You set the overall content-type to multipart, then you set the content-type of that individual section to the appropriate type (json in your case). In a multi-part request each section can have its own content type. e.g. here's a brief example of such a request body (ignore the fact they used base-64 for the image part, you don't have to do that, but it shows that you set the content-type for each section): https://stackoverflow.com/a/9082243/5947043 . So then your next job is to research how to construct that with cURL. I'd be surprised if you can't find some existing material on it. – ADyson Dec 19 '18 at 14:24
  • @ADyson Perfect! That is what I hoped to hear. If you know of any docs that talk about how to set content types for each section using PHP, please let me know. Otherwise, hunting I go! – user1032531 Dec 19 '18 at 14:29
  • @Quentin Did you mean to say one shouldn't say negative for both your two statements? – user1032531 Dec 19 '18 at 14:30

0 Answers0