Response to json Payload in POST API not in Json Format - php

I have a Rest API that accepts a Json Payload, i format the Data and import this into the SQL Database. However when the payload is received the sender is waiting for a response.
They do not want a Typical HTTP 200 OK, they want a formatted Json Response with the Price etc for the submission.
Whenever i output the response to the body, it does not appear to be formatted as a Json and appears as a string, this is causing errors with the flow of the program.
i wanted to check the formatting is correct and the method.
ignoring all the handler and authorization i am typically picking up the payload via:
$payload = (file_get_contents('php://input'));
do what i need to do with the data
then respond as follow:
(of course this is wrapped in a statement of handlers but the successful segment of the code)
http_response_code(200);
$data = array(
"sub_total" => 1000,
"ExtraeChargeTotal" => 0,
"Vat" => 0,
"Total" => 1000
);
$response = json_encode($data);
echo $response ;
is this the correct way to respond? everything works how i think it should, an appears to work in postman.
however the response is a string and not in Json

To resume the comments, when json datas must been sent with PHP, it's important to force the Content-Type header by this way :
header('Content-Type: application/json; charset=utf-8');
After the header, send the datas with echo.
For exemple in this case :
http_response_code(200);
$data = array(
"sub_total" => 1000,
"ExtraeChargeTotal" => 0,
"Vat" => 0,
"Total" => 1000
);
if($response = json_encode($data)){
header('Content-Type: application/json; charset=utf-8');
echo $response ;
}

Related

Returning an array from PHP to jQuery from Ajax

I'm trying to get PHP returned array from Ajax.
Here is my Ajax call:
And my PHP code is this:
Query is running perfectly.
I have tried to get values like alert(data[0].program_title) in ajax success. But it also returns Undefined.
How can I fix this issue?
In your PHP code:
//remove
return $data
//change with
echo json_encode($data);
Just before flushing the data back to the stream (returning), convert your data ($data variable in this case) to JSON string using json_encode and add the proper content-type application/json using header function.
However, the best practice is to provide some metadata to your data included in your transfer, like the size of data and count of elements in data and if paginated, which page the data refers to and what the maximum available pages and maximum element size of a page are.
Here's a sample body structure for a more robust data transfer:
$response = [
'page' => 0, // e.g.
'count' => count($data),
'data' => $data,
'max_page' => 3, // e.g.
'item_per_page' => 15, // e.g.
'status_code' => 200, // e.g.
];
header ( "Content-Type: application\/json", true , 200);
return json_encode(
$response
, JSON_INVALID_UTF8_SUBSTITUTE
| JSON_NUMERIC_CHECK
| JSON_PRESERVE_ZERO_FRACTION
| JSON_UNESCAPED_LINE_TERMINATORS
| JSON_UNESCAPED_SLASHES
| JSON_UNESCAPED_UNICODE
);
Try this:
$data = [];
if ($numRows>0) {
while($row=$result->fetch_assoc()) {
$data[] = $row;
}
}
Replace return with echo and add json_encode
echo json_encode($data);

Sending HTTP request using Guzzle

I am trying to send a post request using Guzzle 6 http client. I am sending two requests one with content type as application/x-www-form-urlencoded (form_params in Guzzle) and the other as application/json (json in Guzzle).
I initialise the client as below (forms_params and json respectively):
$data1 = array("c1" => "a", "c2" => null)
$client = new Client();
$response = $client->post(
"http://localhost/callback",
array(
"form_params" => $data1, // send as x-www-form-urlencoded
)
);
$data2 = array("c1" => "a", "c2" => null)
$client = new Client();
$response = $client->post(
"http://localhost/callback",
array(
"json" => $data2, // send as json
)
);
The response that I receive does have not identical data/body:
Output for form_params : Data -> {"c1":"a"}
Output for json : Data -> {"c1":"a","c2":null}
I am not understanding why it does not send identical data for above requests. Could this be a bug in Guzzle? Is there any way to solve this (apart from removing nulls before sending request)?
UPDATE : As requested endpoint code (both requests are read using same code)
if ($$_SERVER["CONTENT_TYPE"] == "application/json") {
$jsonstr = file_get_contents("php://input");
$formData = json_decode($jsonstr, true);
} else {
$formData = $_POST;
}
echo "Data -> " . json_encode($formData);
UPDATE 2 : I went through the links provided in comments about this being expected behaviour in Guzzle.
But why I asked this question in first place is because I faced an issue of signature mismatch.
When I send the request, I add a header with a signature which is nothing but hash_hmac("sha256", json_encode($data), "secret_key"). So I get different signatures when sending data as json and form_params (since the data received is different in case of form_params as null values are discarded/not sent). First, I thought it might be because of a bug in Guzzle but it isn't.
Is there anyway to solve this signature issue?
As Jon Stirling and Lawrence Cherone noticed already, it's not a bug according to Guzzle's authors.
So the solution for you is to cast values to a string for form_params. It makes sense, because URL encoded format (unlike JSON) doesn't have types (all is a string). And you everyone defines own conversion rules. In PHP (using http_build_query) it works like this, skipping nulls at all.

json output for muliple files

I am using this php code which works flawless for one file but when I upload multiple files generated json contains error.
$response = array('file' => ''.$file.'', 'date' => ''.date("d:m:y").'', 'save' => ''.$saving.'%');
echo json_encode($response);
If I am using one file the json output is valid
{"file":"http:\/\/xyy.com\/3\/4\/23968281479202046440249.png","date":"15:11:16","save"
:"<br>Original Size:8.3 Kb, Compressed Size:2.9Kb, Saving:65%"}
but if I am using two or more files json output is invalid and contains error.
{"file":"http:\/\/xxxxxxx.com\/4\/352118314792022053319009.png","date":"15:11:16","save"
:"Saving:68%"}{"file":"http:\/\/way2enjoy.com\/pdf\/1\/2\/3\/4\/270182314792022054204908.png","date":"15:11:16"
,"save":"Saving:65%"}
Any help will be great to make it work for multiple files.
The string with two file objects looks like a couple of JSON objects printed one after another. You should join the arrays before encoding and printing them in order to produce a valid JSON object, e.g.:
$date = date("d:m:y");
$response = [
['file' => $file1, 'date' => $date, 'save' => $saving.'%'],
['file' => $file2, 'date' => $date, 'save' => $saving.'%'],
];
// Also, use the correct MIME type for JSON content
header('Content-Type: application/json');
echo json_encode($response);
Otherwise, make separate HTTP requests for each file.

Encoding PHP POST response's JSON body into HMAC SHA256, and then into Base64

How to receive raw JSON response from HTTP POST webhook?
I am working with an API and to verify that the POST to the webhook is indeed from the appropriate company API, they suggest this method:
To allow a client to verify a webhook message has in fact come from SIGNIFYD, an X-SIGNIFYD-SEC-HMAC-SHA256 header is included in each webhook POST message. The contents of this header is the Base64 encoded output of the HMAC SHA256 encoding of the JSON body of the message, using the team's API key as the encryption key. To verify the authenticity of the webhook message, you should calculate this value yourself and verify it equals the value contained in the header.
For the test environment, the "secret" key is ABCDE instead of the "Team API key."
I am receiving it in PHP like so:
<?php
// Get relevant Signifyd custom headers to be used for verification
$header_sig_topic = $_SERVER['HTTP_X_SIGNIFYD_TOPIC'];
$header_sig_sec_hmac = $_SERVER['HTTP_X_SIGNIFYD_SEC_HMAC_SHA256'];
// Get POST body
$webhookContent = "";
$webhook = fopen('php://input' , 'r');
while (!feof($webhook)) {
$webhookContent .= fread($webhook, 4096);
}
fclose($webhook);
?>
then I am processing it into the hash like so:
<?php
$sig_ver_sha = hash_hmac('sha256', $webhookContent, $secret);
$sig_ver_hash = base64_encode( $sig_ver_sha );
?>
However, I am going wrong somewhere, because the hash I calculate is
OTc1YzExZDY2ZTE1MTVmYmJmNWNhNDRhNWMxZGIzZDk0NmM3OGE4NDU2N2JkYTJmZDJlYWI0ODRhNjlhNTdiYg==
while the header for an identical sample response header always comes with
W+D70ded8u5DG7P4BcG0u2etvAqQZvxz70Q4OXh0vlY=
I thought I was getting the JSOn body wrong somehow so I've tried every combination of json_encode and json_decode but nothing helps, my hash never matches.
I've also tried using $webhookContent = json_decode(file_get_contents('php://input'), true); to store the POST body but that just comes up empty ($_POST doesn't work either).
Am I doing something else wrong other than receiving the JSON?
The JSON that comes as the body of the test response which always comes with W+D70ded8u5DG7P4BcG0u2etvAqQZvxz70Q4OXh0vlY= as the hash key to be used for verification:
{ "analysisUrl": "https://signifyd.com/v2/cases/1/analysis",
"entriesUrl": "https://signifyd.com/v2/cases/1/entries", "notesUrl":
"https://signifyd.com/v2/cases/1/notes", "orderUrl":
"https://signifyd.com/v2/cases/1/order", "guaranteeEligible":false,
"status":"DISMISSED", "uuid":"709b9107-eda0-4cdd-bdac-a82f51a8a3f3",
"headline":"John Smith", "reviewDisposition":null, "associatedTeam":{
"teamName":"anyTeam", "teamId":26, "getAutoDismiss":true,
"getTeamDismissalDays":2 }, "orderId":"19418",
"orderDate":"2013-06-17T06:20:47-0700", "orderAmount":365.99,
"createdAt":"2013-11-05T14:23:26-0800",
"updatedAt":"2013-11-05T14:23:26-0800",
"adjustedScore":262.6666666666667, "investigationId":1,
"score":262.6666666666667, "caseId":1,
"guaranteeDisposition":"APPROVED"}
If it helps to see where I'm going wrong, an example is provided but it's in Python:
Mac sha256HMAC = javax.crypto.Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(teamAPIKEY.getBytes(), "HmacSHA256");
sha256HMAC.init(secretKey);
String encodedHMAC256 = Base64.encodeBase64String(sha256HMAC.doFinal(jsonBody.getBytes("UTF-8")));
My error was in simply not specifying the $raw_output parameter of the hash_hmac() function as true.
raw_output
When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
So, since I wasn't specifying $raw_output as true, I was getting hexits instead of raw binary output, which looked like this: 975c11d66e1515fbbf5ca44a5c1db3d946c78a84567bda2fd2eab484a69a57bb.
EDIT: The answer here is
<?php
$sig_ver_sha = hash_hmac('sha256', $webhookContent, $secret, true);
$sig_ver_hash = base64_encode( $sig_ver_sha );
?>

Trying to understand how to format this PHP POST to a Curl POST format

I am connecting with an API via curl and POSTing to it.
The API support simply says that I should form my request as so:
"If you send a POST request to the correct URL with a content-type of JSON and a body like what's below you should be off to a good start:
{
"contact": {
"email": "justin#myapi.com",
"last_name": "Johnston",
"company": "MyApi",
"first_name": "Justin"
}
}
However, I think this is for a regular PHP post maybe and not for CURL which is what I am using.
So, the curl code I have is:
//Set Curl options
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "first_name=" . $db->f('fname') . "&last_name=" . $db->f('lname') . "&email=" . $db->f('Email') . "&company=" . $db->f('studio_name') . "");
However, when I run the POST, the response I get back from the API says:
{"error":"Invalid parameters. Should be a hash in the form { 'contact' : { } }."}
So, I am assuming that is because my POSTFIELDS are not correct, and I understand I need to lead with "Contact", but I am not sure how to format it and haven't been able to find an example. Any idears?
Thanks very much for any help you could give! I really do appreciate it!!
Craig
To expand on the comment I posted...
I think the problem is you're sending a string as the parameter, where
it should be a JSON object. just use json_encode() to encode an
array of data and send that via POST instead of the string you're
forming
You need to create a JSON string (usually by encoding an array of data):
$data = array(
"contact" => array(
"first_name" => $db->f('fname'),
"last_name" => $db->f('lname'),
"email" => $db->f('Email'),
"company" => $db->f('studio_name')
)
);
$data = json_encode($data);
This will give you the JSON you need to post, so just change your line of code setting the parameters to this:
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
Edit: As requested in a comment, I'll attempt to explain a little more:
The POST request is sent to the server, and you can send any data you want with the request. In the example given in the question, this is valid JSON and they have specified that the body of the request should also be JSON (I'm assuming in the same format):
{
"contact": {
"email": "justin#myapi.com",
"last_name": "Johnston",
"company": "MyApi",
"first_name": "Justin"
}
}
In my solution above I've explained how to get a string containing valid JSON for an array of data; this string can be sent as the contents of the request.
The problem with what you were trying is that the whole data would have literally been sent like this:
first_name=Justin&last_name=Johnston&email=justin#myapi.com&company=MyApi
It's understandable to be confused, as is this is how you would get the data returned from an HTML form, and is quite a common way of sending variables via POST. However in this case you need to use JSON, which is why that won't work.

Categories