1

How can I send a raw JSON using PHP curl with a content type of application/x-www-form-urlencoded?

Let me explain:

I’m communicating with a webserver that accepts HTTP POST requests with a JSON object as the body of the request where normally we are used to seeing HTTP query parameters.

In my situation, I need to send a request with the following content-type

Content-Type: application/x-www-form-urlencoded

The body must be raw JSON.

So, there are many possibilities. I tried the following:

<?php
      $server_url = "http://server.com";
      $curl = curl_init($server_url);
      $data_array = array("a"=> "a_val", "b" => array("c"=>"c_val", "d"=>"d_val") );

 $options = array(
       CURLOPT_POST            => TRUE,
       CURLOPT_HTTPHEADER     => array('Content-Type: application/x-www-form-urlencoded'),
       CURLOPT_POSTFIELDS      => json_encode($data_array),
       CURLOPT_COOKIEJAR       => realpath('tmp/cookie.txt'),
       CURLOPT_COOKIEFILE      => realpath('tmp/cookie.txt')
        );

    curl_setopt_array($curl, $options);
    $return = curl_exec($curl);  
    var_dump($return);  
    curl_close($curl);
?>

I also tried to escape the json_encode():

...    
CURLOPT_POSTFIELDS      => "\"" . json_encode($data_array) .  "\"" ,
...

If the server was able to parse html parameters I could just do this:

...    
CURLOPT_POSTFIELDS      => http_build_query($data_array)
...

However, that is not the case and I need a workaround.

Please note that changing the content-type won’t work. I tried using text/plain, but the server would not accept it.

TRiG
  • 10,148
  • 7
  • 57
  • 107
Lothre1
  • 3,523
  • 7
  • 43
  • 64

2 Answers2

2

Usually the application/x-www-form-urlencoded requires a key-value paired parameters for HTTP post. So it’s very hard to suggest anything to you without seeing a sample POST data format. As per the document, you must place the URLencoded data with a variable. For example your JSON should go like this.

$post_data = "data=".urlencode(json_encode($data_array))

You can try sending the data without any key parameter, and it should not work

$post_data = urlencode(json_encode($data_array))
TRiG
  • 10,148
  • 7
  • 57
  • 107
Sabuj Hassan
  • 38,281
  • 14
  • 75
  • 85
0

I’m not entirely sure I understand your question, so I’m going to answer two different versions.

Send JSON data, but with an (inaccurate) application/x-www-form-urlencoded Content Type

I don’t know why you’d want to do this, but if you do, it should be fairly simple.

$data_array = array(
    'a' => 'a_val',
    'b' => array(
        'c' => 'c_val',
        'd' => 'd_val'
    )
);

$json = json_encode($data_array);

$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_USERAGENT, 'PHP/' . phpversion());
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
curl_setopt($c, CURLOPT_POSTFIELDS, $json);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
$result = curl_exec($c);
if (curl_errno($c)) {
    return trigger_error('CURL error [' . curl_errno($c) . '] ' . curl_error($c));
}
curl_close($c);

echo $result;

Bear in mind that you are, here, sending deliberately inaccurate data to the server. You’re sending JSON, but calling it urlencoded. You probably don’t want to do this; if, for some reason, you do need to do this, you’d probably be better off fixing whatever the real problem is, rather than using this hacky workaround.

If you were using Guzzle rather than cURL, it might be a little trickier. Guzzle has built-in support for both JSON and urlencoded, but if you want to mess about like this, you’d be better off not using that. Generate your JSON data yourself (using $json = json_encode($data)), and set the Content-Type in Guzzle by hand.

Send urlencoded JSON data

This is an odd setup, but accurate. At least you wouldn’t be lying in your HTTP headers.

Basically the same as above, but add this:

$json = json_encode($data_array);
$data = array('JSON' => $json);
$body = http_build_query($data);

And then set CURLOPT_POSTFIELDS to $body instead of to $json.

What you probably really should do: send JSON as JSON.

In most situations, you’d be better off sending JSON data (as in example one), and also setting the Content-Type to application/json. This is a smaller data size than example two (the urlencoding step increases the size of the data), and it has accurate header data.

TRiG
  • 10,148
  • 7
  • 57
  • 107