I am using php with yii framework to integrate with an external API. The goal is to submit a form that sends a request with 2 parameters to an internal endpoint (the action method described below), then have that action method forward the parameters along to the external API.
Since the parameters being sent are coming from a form, I need to be able to dynamically set them in the action method that queries the external API. I am doing this by setting the parameters from the front end request into variables, then embedding those variables in CURLOPT_POSTFIELDS.
The problem:
I receive the expected response if I hard code both parameter values into the action method, or if I embed only the $propertyId variable. When I embed the $customerName variable I receive the error response from the external API:
{"error":{"code":102,"message":"The format of your request body can not be parsed."}}}
I inserted a var_dump immediately following the $customerName variable assignment and confirmed it is indeed a string, which matches the expected data type based on the external API documentation.
string(9) "Test Name"
This is where I'm stuck, because hard coding a string gets the expected response, but embedding a variable containing a string with precisely the same value does not. I thought there could be an issue on the external API side, but seeing as the failure occurs only under such a specific condition I feel I'm just missing something when it comes to embedding variables in strings.
Full action method:
public function actionSearch()
{
$request = Yii::$app->request->post('params');
$propertyId = $request['propertyId'];
$customerName = $request['customerName'];
var_dump($customerName);
try {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://some/endpoint',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_POSTFIELDS =>'{
"auth": {
"type" : "basic"
},
"requestId" : 15,
"method": {
"name": "searchCustomers",
"version":"r1",
"params": {
"propertyId" : '. $propertyId .',
"search" : '. $customerName .' // problematic parameter
}
}
}',
CURLOPT_HTTPHEADER => array(
'Content-Type: APPLICATION/JSON; CHARSET=UTF-8',
'Authorization: Basic',
),
));
$response = curl_exec($curl);
curl_close($curl);
return json_decode($response, true);
} catch(\Exception $e) {
throw new LogicException('Error fetching customer data');
}
}
Alternative working CURLOPT_POSTFIELDS
CURLOPT_POSTFIELDS =>'{
"auth": {
"type" : "basic"
},
"requestId" : 15,
"method": {
"name": "searchCustomers",
"version":"r1",
"params": {
"propertyId" : "12345",
"search" : "Test Name"
}
}
}'
request payload from front end
{
params: {
propertyId: "12345",
customerName: "Test Name"
}
}
You've missed the wrap around the variable. Since you're creating a JSON, strings needs to be wrap with double qoute.
You can either wrap it on assignment or in JSON object.
$customerName = '"'. $request['customerName'] . '"';
Or much better;
$customerName = sprintf('"%s"', $request['customerName']);
Related
I can't figure out how to make my PHP script work and I'm not allowed to use debugging tools on the server or run it locally. Please help.
It is targeting an open data API (Statistics Norway / SSB), specifically this one:
$url = "http://data.ssb.no/api/v0/no/table/08940";
The API is queried with POST and provides output according to posted message body which must be formatted as JSON.
I build the $body with a nested array in PHP, and the output of json_encode($body, JSON_PRETTY_PRINT); is provided below (truncated).
This runs just fine in the SSB API Console as well as in Restlet Client.
{
"query": [
{
"code": "UtslpTilLuft",
"selection": {
"filter": "item",
"values": [
"1",
"2"
]
}
},
{
"code": "ContentsCode",
"selection": {
"filter": "item",
"values": [
"UtslippCO2ekvival"
]
}
},
{
"code": "Tid",
"selection": {
"filter": "item",
"values": [
"1990",
"1991"
]
}
}
],
"response": {
"format": "json"
}
}
Here is the script for the file_get_contents():
$json_body = json_encode($body);
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/json',
'content' => $json_body
)
);
$context = stream_context_create($options);
$file = file_get_contents($url, false, $context);
$output = json_decode($file, true);
I have looked at the answers given in How to post data in PHP using file_get_contents?, tried to replace json_encode() with http_build_query() and http_build_query(json_encode()), experimented with different 'header' but print_r($output) gives me nothing.
Edit: I removed $output = json_decode($file, true); and now it prints the JSON array! Still need to figure out how to turn that into a PHP variable but how can I do that without json_decode...?
Edit 2: I figured out the data is actually not regular JSON, but JSON-STAT, in the form of a unidimensional array. The proper call in the message body (response: format) is not "json" but "json-stat". With "json", the returned data was incompatible for json_decode().
Any tips on how to parse that to a regular associative array in PHP is highly appreciated!
I am have set up a proxy that allows me to retrieve data user side from a api only accessible server side. I have several endpoints setup and they all work just fine, but now i'm at a point where I need to send data back to the api to make a reservation. I need to
retrieve data from ajax request in proxy
send data in proxy to api
return success/error message from api to ajax request
I not sure how to do this. Here is my ajax request:
var settings2 = {
"async": true,
"crossDomain": true,
"url": "http://url?method=hello&format=json&entity=" + id,
"dataType": "json",
"data": data,
"method": "POST"
};
var a2 = $.ajax(settings2);
$.when(a2).done(function(d2) {
rp = d2;
console.log(JSON.stringify(rp));
});
and the php function and method I use for the other endpoints that only need to retrieve data from the api, it works for this:
function LocationReserve(data) {
header('Content-Type: application/json');
$url = 'api_url' . $_GET['entity'] ;
$auth = 'Authorization: key';
$ch = curl_init($url);
$options = array(
CURLOPT_HTTPHEADER => array(
$auth
),
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION, 1
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
// Method A: Say Hello to the API
if( strcasecmp($_GET['method'],'hello') == 0){
$response['code'] = 1;
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
$response['data'] = wssLocationReserve();
}
// --- Step 4: Deliver Response
// Return Response to browser
deliver_response($_GET['format'], $response);
with this as it is I get a response back
{"code":1,"status":200,"data":"{\"Message\":\"The requested resource does not support http method 'GET'.\"}"}
I added CURLOPT_POST => true to my options and now the response is
{"code":1,"status":200,"data":"<html><head><title>411 Invalid Request</title></head><body>Invalid Request: ??</body>\r\n"}
How can I modify this to accept the data from my ajax call, send it to the api_url, and send back the response?
**EDIT example expected data by api:
{
"ReservationDay": "05/15/2015",
"Units": [{
"UnitID": 12345,
"InsuranceID": 123 (or null)
}],
"PaymentInfo": {
"FirstName": "User",
"LastName": "Userson",
"Address1": "2727 N Central Ave",
"Address2": "",
"City": "Phoenix",
"State": "AZ",
"Zip": "85022",
"Phone": "602-2877878",
"Email": "email#example.com",
"CreditCard": "6011000000000000",
"ExpirationMMYY": "1215",
"CSC": "100"
}
}
"HTTP Status Code 411 (Length Required) is sent by the server as a response when it refuses to accept a message without a content-length header, for whatever reason."
1.- Test a request sending possible missing arguments.
2.- Have you the format in which the data must be send to the second endpoint? Check the specifications of the expected data and fix your second request.
I've made a call to https://login.windows.net/common/oauth2/token and received something like this in response:
{
"token_type": "Bearer",
"scope": "Directory.Read.All User.Read",
"expires_in": "3600",
"ext_expires_in": "0",
"resource": "https://graph.windows.net",
"access_token": {{really_long_token_1}},
"refresh_token": {{really_long_token_2}},
"id_token": {{really_long_token_3}}
}
I have a website hosted on HostGator that's trying to access an API I have located on Azure.
What is the correct form of a GET call to my API hosted on Azure? Here's what I have so far:
$url = 'https://myappservice.azurewebsites.net/api/getValues';
$options = array(
'http' => array(
'header' => array(
'x-ms-version: 2017-06-02',
'Authorization: Bearer {{really_long_token_1}}'
),
'method' => 'GET'
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
$var_dump($result);
I end up getting 500 Server Errors while making this call.
The 500 is Internal Error which indicates the server encountered an unexpected condition which prevented it from fulfilling the request.
It should not be relative to the authentication/authorization, please check whether there is code can cause this exception. Or you can just replace the code with a very easy code sample without any complex business logic just return the values.
I have found a couple of helpful links on stackoverflow but they haven't helped me complete my task because I am a complete beginner in trying to write PHP or use curl etc.
Send json post using php
Posting JSON data to API using CURL
I have been using Postman in Chrome to test API calls but I now want to put together a demo system on my Apache web server.
Does anyone have an example of a PHP webform posting to a json Object to a REST API?
Here is an example of what I want to send:
<?php
$url = "https://api.url/api/v1//accounts/create";
$jdata = json_encode($data);
$data = [{
"status": "active",
"username": ["uname"],
"password": ["pword"],
"attributes": {
"forenames": ["fname"],
"surname": ["lname"],
"emailAddress": ["email"]
},
}]
?>
Any advice would be fantastic. Like I said, I am new to curl and php, am unfamiliar with the array approach mentioned in the other articles and the ["info"] elements should be populated with the information filled in on my webform.
I hope I have been concise and explanitory but please let me know if you need anymore information.
Snook
Try something like the following, modifying steps 1 and 2 accordingly:
function sendRequest($data,$url)
{
$postdata = http_build_query(array('data'=>$data));
$opts = array('http' =>
array(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded \r\n",
//"X-Requested-With: XMLHttpRequest \r\n".
//"curl/7.9.8 (i686-pc-linux-gnu) libcurl 7.9.8 (OpenSSL 0.9.6b) (ipv6 enabled)\r\n",
'content' => $postdata,
'ignore_errors' => true,
'timeout' => 10,
)
);
$context = stream_context_create($opts);
return file_get_contents($url, false, $context);
}
// 1.- add your json
$data = '[{
"status" : "active",
"username" : ["uname"],
"password" : ["pword"],
"attributes" : {
"forenames" : ["fname"],
"surname" : ["lname"],
"emailAddress": ["email"]
},
}]';
// 2.- add api endpoint
$url= "https://api.url/api/v1//accounts/create";
// 3.- fire
$result = sendRequest($data,$url);
// 4.- dump result
echo $result;
die();
Good luck!!
I'm currently creating a Twitch notification web app in PHP.
For the moment, the authentication works fine :
Client wants use the app -> redirected on Twitch website to accept asked scopes -> redirected on my app website with a "code" parameter -> "code" sent by curl request -> response containing the accessToken.
I stored accessToken and client username in $_COOKIE and $_SESSION variable (set $_COOKIE doesn't work on all web browsers).
After that I have to check (in real-time ?) if the user has new followers. Certains web applications, as TNotifier, exists and do this very well... But I don't know how.
In the Twitch API, we have only for the follows request the possibility to list all of these followers. I thought directly i will have to make requests, again and again (with one second of delay), and compare the new request with the last one... But i think there 's an other way to make that ?
Here is the follows request :
curl -H 'Accept: application/vnd.twitchtv.v2+json' \
-X GET https://api.twitch.tv/kraken/channels/test_user1/follows
And the JSON response :
{
"_links": {
"next": "https://api.twitch.tv/kraken/channels/test_user1/follows?limit=25&offset=25",
"self": "https://api.twitch.tv/kraken/channels/test_user1/follows?limit=25&offset=0"
},
"follows": [
{
"_links": {
"self": "https://api.twitch.tv/kraken/users/test_user2/follows/channels/test_user1"
},
"user": {
"_links": {
"self": "https://api.twitch.tv/kraken/users/test_user2"
},
"staff": false,
"logo": null,
"display_name": "test_user2",
"created_at": "2013-02-06T21:21:57Z",
"updated_at": "2013-02-13T20:59:42Z",
"_id": 40091581,
"name": "test_user2"
}
},
...
]
}
Here is my code, but still thinking a better way exists...
$uknown=""; //to initialize my loop function.
comparaison($uknown);
function comparaison($u){
$options = array(
'http' => array(
'header' => 'Accept: application/vnd.twitchtv.v2+json',
'method' => 'GET',
)
);
$context = stream_context_create($options);
$result = file_get_contents('https://api.twitch.tv/kraken/channels/test_user1/follows', false, $context);
$decode_result = json_decode($result, true);
$follow=$decode_result['follows'][0];
$user=$follow['user'];
$last_follower=$user['display_name'];
if($last_follower != $u){
haveANewFollower($last_follower);
}
comparaison($last_follower);
}
Is it possible TNotifier use another way to check new followers ?
It's the only way, as there's no push way to do followers, so you have to rely on pulling. For subscribers there would be the possibility to listen for chat messages for new subscribers, but as this does not work for followers, you can only rely on the pull method using the kraken api.