0

I'm trying to post data to an API using PHP curl. When I manually paste the json_encoded output into the code it works fine but when I assign through a variable I get an error 400 Bad Syntax from the API.

I've tried manipulating the variable to ensure it is identical to a known working string but the printed output in the error log shows me that the escaping backslashes remain.

//Get the data
$sql = "SELECT name, date, amount FROM table";
$result = mysqli_query($conn, $sql);

//Convert the output to JSON format
$rows = array();

while($r = mysqli_fetch_assoc($result)) {

    $rows[] = $r;
}

$encodedJSON = json_encode($rows, JSON_NUMERIC_CHECK);

if (mysqli_num_rows($result) == 1) {
    $encodedJSON = '{ "single": ' . $encodedJSON . ' }';
} else {
    $encodedJSON = '{ "multiple": ' . $encodedJSON . ' }';  
}

$access_token = 'Bearer ' . $access_token;
$encodedJSON = addslashes($encodedJSON);            
error_log($encodedJSON);

//Start Curl        
$curl = curl_init();

curl_setopt_array($curl, array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => $encodedJSON,
    CURLOPT_HTTPHEADER => array(
      "Accept-Encoding: gzip, deflate",
      "Authorization: " . $access_token,
      "Cache-Control: no-cache",
      "Connection: keep-alive",
      "Content-Length: 354",
      "Content-Type: application/json",
      "accept: application/json",
      "cache-control: no-cache"
    ),
  ));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
} 

I suspect a backslash issue is at play here but I can't resolve it.

$encodedJSON is outputting to error_log. When I check the error_log file I can see that the string is outputting like this:

"{ \"multiple\": [{\"name\":\"Joe Bloggs\",\"date\":\"2019-08-06\",\"amount\":34},{\"name\":\"Bloggy Joe\",\"date\":\"2019-08-07\",\"amount\":237}] }"

The strange thing is, if I copy/paste this exact string and hardcode it into a new variable - let's say $HARDencodedJSON:

$HARDencodedJSON = "{ \"multiple\": [{\"name\":\"Joe Bloggs\",\"date\":\"2019-08-06\",\"amount\":34},{\"name\":\"Bloggy Joe\",\"date\":\"2019-08-07\",\"amount\":237}] }";

Then it outputs to the error log like this:

{ "multiple": [{"name":"Joe Bloggs","date":"2019-08-06","amount":34},{"name":"Bloggy Joe","date":"2019-08-07","amount":237}] }

In other words, the backslashes get stripped out of the hardcoded variable but they remain in the original one.

Likewise, if I were to swap out CURLOPT_POSTFIELDS => $encodedJSON, for CURLOPT_POSTFIELDS => $HARDencodedJSON, the whole thing works perfectly.

UPDATED: I'm still stumped here is anyone can help please?

With the following code in place I'm getting what looks like perfectly formed output in my error_log but the cURL is timing out:

$encodedJSON = json_encode(array("multiple"=>$rows),JSON_NUMERIC_CHECK);

I've removed addslashes so there's no further string manipulation.

Then I simply add the variable to my cURL setup as follows:

CURLOPT_POSTFIELDS => $encodedJSON,

The response is a cURL timeout as follows: cURL Error #:Operation timed out after 30000 milliseconds with 0 bytes received

If I addslashes back in, cURL does not timeout anymore and the API endpoint responds with an error 400 Bad Request.

Is there any way I can see the exact cURL command being sent over? I've tried a verbose debug but it doesn't show exactly what CURLOPT_POSTFIELDS is set to?

syncguy
  • 1
  • 1
  • Who introduced `$encodedJSON = addslashes($encodedJSON); ` then? – mario Aug 09 '19 at 18:16
  • I did. Without the slashes the curl times out. – syncguy Aug 09 '19 at 18:22
  • You shouldn't need to use `addslashes`. The slashes you have in the hard-coded string are necessary because you used double quotes as the delimiters around the string itself, they're not actually in the string itself. – Barmar Aug 09 '19 at 20:03
  • OK, with addslashes removed I'm getting a curl timeout. Then I followed the duplicate solution (How to POST JSON Data With PHP cURL?) and changed $encodedJSON to $encodedJSON = json_encode(array("multiple"=>$rows, JSON_NUMERIC_CHECK)); This solved the timeout but the Error 400 returned. I now see from the error_log that extra characters have been added to the end of the JSON string: ',"0":32}' I'm not sure what these mean and I'll dig into it now but if anyone knows, please comment. Thanks. – syncguy Aug 09 '19 at 20:18
  • @Barmar - I've updated the question. I don't think it's a dupe. Much appreciate any more advice you can offer? Thanks – syncguy Aug 10 '19 at 07:24
  • All, I've fixed it. The cURL time-out problem was caused by the hard-coded "Content-Length: 354" parameter! This was generated from Postman and once changed to strlen($encodedJSON) everything worked perfectly. Thanks everyone for your help. – syncguy Aug 10 '19 at 10:58

0 Answers0