I am able to connect with the help of apple news api but I can't able to send data in json format.
My code is below.
but when I try to attach json file. I am getting signature failure message.
<?php
$channel_id = 'xxxxxxxxxxxxxxxxxx';
$api_key_id = 'xxxxxxxxxxxxxxx';
$api_key_secret = 'xxxxxxxxxxxxxxxx';
// use the correct values above
$data = file_get_contents('article.json');
$Content_type="application/json";
$url = 'https://news-api.apple.com/channels/'.$channel_id;
$date = gmdate('Y-m-d\TH:i:s\Z');
$canonical_request = 'GET'.$url.$date.$Content_type;
$key = base64_decode($api_key_secret);
$hashed = hash_hmac('sha256', $canonical_request,$key,true);
$signature = base64_encode($hashed);
echo $signature;
//curl options
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $url);
$headers = array();
$headers[] = "Authorization: HHMAC; key={$api_key_id}; signature={$signature}; date={$date}";
$headers[] = "Content-Type: application/json";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
//curl_setopt($ch, CURLOPT_POST, true);
//curl_setopt( $ch, CURLOPT_POSTFIELDS, $data);
//get result
$server_output = curl_exec ($ch);
curl_close ($ch);
print_r(json_decode($server_output));
?>
Since you are sending a GET request, you are incorrectly including the content type when building the canonical request.
This should work for you, then:
$canonical_request = 'GET'.$url.$date;
For reference, see Apple News API Reference: Setting Up MAC/HMAC Authentication:
Create a canonical version of the request as a byte-wise concatenation of the following:
The HTTP method (for example, GET or POST, in all caps)
The full URL of the request
The current date in ISO 8601 format
If the request is a POST request and it includes an entity, include the following:
The value of the Content-Type header
The full content of the entity
Related
Im using 2ba its API to receive product information which I later on want to store inside my database. I am trying to create a post request for receiving the data I need. This is the request I want to get to working. And this is my code:
postApiData.php
<?php
/**
* Posts API data based on given parameters at index.php.
*/
// Base url for all api calls.
$baseURL = 'https://api.2ba.nl';
// Version number and protocol.
$versionAndProtocol = '/1/json/';
// All parts together.
$url = $baseURL . $versionAndProtocol . $endPoint;
// Init session for CURL.
$ch = curl_init();
// Init headers. Security for acces data.
$headers = array();
$headers[] = "Authorization: Bearer " . $token->access_token;
// Options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
// Execute request.
$data = curl_exec($ch);
// If there is an error. Show whats wrong.
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
echo "<br>";
echo "Error location: postApiData";
exit();
}
// Ends the CURL session, frees all resources that belongs to the curl (ch).
curl_close($ch);
// String to array.
$data = json_decode($data);
?>
index.php
// Specified url endpoint. This comes after the baseUrl.
$endPoint = 'Product/forGLNAndProductcodes';
// Parameters that are required or/and optional for the endPoint its request.
$parameters = [
'gln' => '2220000075756',
'productcodes' => ['84622270']
];
// Get Supplier info
include("postApiData.php");
print_r($data);
exit();
My API key does for sure work since I have done alot of different GET requests already, also im not getting an access denied error.
The error I get with this code is: The requested URL returned error: 500 Internal Server Error
I also receive a "Bad request" 400 error when I remove the curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters)); part
Is there anyone who knows what im doing wrong?
PS: It's not really possible to try this code yourself unless you have a 2ba account with working key's etc.
Okey I fixed it already...
I had to add some extra headers and change the $parameters values like this:
postApiData.php
// Added this above the authorization.
$headers[] = "Connection: close";
$headers[] = "Accept-Encoding: gzip,deflate";
$headers[] = "Content-Type: application/json";
// Removed the http_build_query part.
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
index.php
// Encoded in a json way as asked by 2ba request.
$parameters = json_encode($parameters);
Im trying to connect to the API services of 2ba. Somehow I just can't connect. I get the error: error: "invalid_client"
I dont know what to try, it feels like I need to hash my cliend_secret or complete url but I dont see that in the documentation.
This is my code (PHP):
<?php
// ---- GET TOKEN ----
// Base url for all api calls.
$baseURL = 'https://authorize.2ba.nl';
// Specified url endpoint. This comes after the baseUrl.
$endPoint = '/OAuth/Token';
// Parameters that are required or/and optianal for the endPoint its request.
$parameters = 'grant_type=password&username=abc#abc.com&password=123abc&client_id=myClientID&client_secret=myClientSecret';
// All parts together.
$url = $baseURL . $endPoint . '?' . $parameters;
//Init session for CURL.
$ch = curl_init();
// Options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
// Init headers for access to the binance API signed data.
$headers = array();
$headers[] = 'Content-type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: 0';
// Setting headers
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Execute request.
$data = curl_exec($ch);
// If there is an error. Show whats wrong.
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// Ends the CURL session, frees all resources and deletes the curl (ch).
curl_close($ch);
$result = json_encode($data);
echo($data);
exit();
?>
The authentication is oauth2 and I want to use the "Password Grant" flow since I can login automaticly this way. Also I see in the example code in C# that they encode the url, something im not doing yet but did try. It did not work.
// Using $encodedUrl like this: curl_setopt($ch, CURLOPT_URL, $encodedUrl); but does not work.
$encodedUrl = urlencode($url);
Alright so I fixed it. I now got my access token and am able to recieve data from the API. This is what I did:
// ---- GET TOKEN - FLOW: USER PSW ----
// No changes
$baseURL = 'https://authorize.2ba.nl';
// No changes
$endPoint = '/OAuth/Token';
// $parameters is now an array.
$parameters = array(
'grant_type' => 'password',
'username' => 'myUsername',
'password' => 'myPassword',
'client_id' => 'myClientID',
'client_secret' => 'myClientSecret'
);
// Removed the $parameter part
$url = $baseURL . $endPoint;
//Init session for CURL.
$ch = curl_init();
// Init headers for access to the binance API signed data.
$headers = array();
$headers['Content-Type'] = "application/x-www-form-urlencoded";
// NOTE: http_build_query fixed it.
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters)); // Automaticly encodes parameters like client_secret and id.
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Execute request.
$data = curl_exec($ch);
// If there is an error. Show whats wrong.
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// Ends the CURL session, frees all resources and deletes the curl (ch).
curl_close($ch);
$result = json_encode($data);
echo($data);
exit();
I'm trying to add a job to the Workflow Max API. I seem to be hitting the API but I keep getting the error message:
Message not in expected format. The following required element was missing - Job/ClientID
I'm sure that the client ID is added but something seems to be wrong. This is the code:
function post_job_to_workflow_max($job_data) {
// configure our connection to the api
$api_token = 'API_KEY';
$acc_key = 'ACC_TOKEN';
$url = 'https://api.workflowmax.com/job.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Job data must match the format required by WorkflowMax
// currently accepts XML data
// see: https://www.workflowmax.com/api/job-methods#POST%20add
$xml = new SimpleXMLElement("<Job></Job>");
$xml->addChild('Name', $job_data[0]);
$xml->addChild('Description', $job_data[1]);
$xml->addChild('ClientID', 18754031);
// $clientID = $xml->addChild('Client');
// $clientID->addChild('ID', 18754031);
// $clientID->addChild('Name', "TEST CLIENT");
$xml->addChild('State', 'Planned');
$xml->addChild('StartDate', $job_data[2]);
$xml->addChild('DueDate', $job_data[3]);
// print_r($xml);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
$result = simplexml_load_string($output);
print_r($result);
}
If there's anyone with experience of using WFM, would be good to hear how you approached it.
Thanks
So in answer to my own question, I did finally work this out.
The way I did this was to return the ID of the client from the function I used to post a client to WorkFlow Max. See code:
1) post the client
function post_client_to_workflowmax($client_data) {
// configure our connection to the api
$api_token = 'YOUR_TOKEN';
$acc_key = 'YOUR_KEY';
$url = 'https://api.workflowmax.com/client.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Client data must match the format required by WorkflowMax
// currently accepts XML data
// These indexes match up with how the data has been stored
// see: https://www.workflowmax.com/api/client-methods#POST%20add
$xml = new SimpleXMLElement("<Client></Client>");
$xml->addChild('Name', htmlspecialchars($client_data[2]));
$xml->addChild('Email', htmlspecialchars($client_data[9]));
$xml->addChild('Phone', htmlspecialchars($client_data[10]));
$xml->addChild('Address', htmlspecialchars($client_data[3]) . ' ' . htmlspecialchars($client_data[4]));
$xml->addChild('City', htmlspecialchars($client_data[5]));
$xml->addChild('Postcode', htmlspecialchars($client_data[7]));
$xml->addChild('Country', htmlspecialchars($client_data[8]));
$xml->addChild('IsProspect', 'No');
$contacts = $xml->addChild('Contacts');
$contact = $contacts->addChild('Contact');
$name = $contact->addChild('Name', htmlspecialchars($client_data[0]) . ' ' . htmlspecialchars($client_data[1]));
// POST request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
// Create an array from the data that is sent back from the API
$result = simplexml_load_string($output);
$clientID = NULL;
// here we get the ID created for this client and pass it into the variable $clientID
foreach($result->Client as $k => $v) {
$clientID = $v->ID;
}
return $clientID;
}
We then get that ID passed into our job posting function like so:
2) post a job to WFM
function post_job_to_workflow_max($job_data, $clientID) {
// configure our connection to the api
$api_token = 'YOUR_TOKEN';
$acc_key = 'YOUR_KEY';
$url = 'https://api.workflowmax.com/job.api/add?apiKey=' . $api_token . '&accountKey=' . $acc_key;
// Job data must match the format required by WorkflowMax
// currently accepts XML data
// see: https://www.workflowmax.com/api/job-methods#POST%20add
$xml = new SimpleXMLElement("<Job></Job>");
$xml->addChild('ClientID', $clientID);
$xml->addChild('Name', htmlspecialchars($job_data[0]));
$xml->addChild('Description', htmlspecialchars($job_data[1]));
$xml->addChild('State', 'Planned');
$xml->addChild('StartDate', htmlspecialchars($job_data[2]));
$xml->addChild('DueDate', htmlspecialchars($job_data[3]));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml->asXML()))
);
$output = curl_exec($ch);
curl_close($ch);
$result = simplexml_load_string($output);
}
And then calling these functions looks something like this:
$id = post_client_to_workflowmax($client);
post_job_to_workflow_max($job, $id);
Where $client must be an array of data. This worked for my case but might not work for your particular case so you may need to edit the fields etc.
Hopefully this helps someone who is stuck with the same problem. Not the most elegant code but it gets the job done.
I am currently using the following code:
<?php
/* Pre-requisite: Download the required PHP OAuth class from http://oauth.googlecode.com/svn/code/php/OAuth.php. This is used below */
require("OAuth.php");
$url = "https://yboss.yahooapis.com/geo/placespotter";
$cc_key = "MY_KEY";
$cc_secret = "MY_SECRET";
$text = "EYES ON LONDON Electric night in 100-meter dash";
$args = array();
$args["documentType"] = urlencode("text/plain");
$args["documentContent"] = urlencode($text);
$consumer = new OAuthConsumer($cc_key, $cc_secret);
$request = OAuthRequest::from_consumer_and_token($consumer, NULL,"POST", $url,$args);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);
$url = sprintf("%s?%s", $url, OAuthUtil::build_http_query($args));
$ch = curl_init();
$headers = array($request->to_header());//.',Content-Length: '.strlen($text));
//print_r($headers.',Content-Length: '.strlen($text));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// somehow this line is not solving the issue
// curl_setopt($ch,CURLOPT_HTTPHEADER,array('Content-Length:'.strlen($text)));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$rsp = curl_exec($ch);
print_r($rsp);
//echo "======= ENDING";
?>
With my own access keys and all, with the OAuth.php library.
Somehow I kept getting a Content-Length undefined error.
If I were to attempt to define Content-Length like this ( based on some answers seen here on StackOverFlow:
curl_setopt($ch,CURLOPT_HTTPHEADER,array('Content-Length:'.strlen($text)));
I do not get any response.
May I know how can this issue be solved?
Thanks!
PS: the php example comes from the official example: https://gist.github.com/ydn/bcf8b301125c8ffa986f#file-placespotter-php
LATEST EDIT
I've updated my code based on #alexblex's comment
<?php
/* Pre-requisite: Download the required PHP OAuth class from http://oauth.googlecode.com/svn/code/php/OAuth.php. This is used below */
require("OAuth.php");
$url = "https://yboss.yahooapis.com/geo/placespotter";
$cc_key = "MY_KEY";
$cc_secret = "MY_SECRET";
$text = "EYES ON LONDON Electric from Singapore Raffles Place";
$args = array();
$args["documentType"] = urlencode("text/plain");
$args["documentContent"] = urlencode($text);
$args["outputType"] = "json";
$consumer = new OAuthConsumer($cc_key, $cc_secret);
$request = OAuthRequest::from_consumer_and_token($consumer, NULL,"PUT", $url, $args);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);
$url = sprintf("%s?%s", $url, OAuthUtil::build_http_query($args));
$ch = curl_init();
$headers = array($request->to_header());//.',Content-Length: '.strlen($text));
//$headers = array($request->to_header().',Content-Length="'.strlen($text).'"');
//$headers = array($request->to_header().',Content-Length: 277');
print_r($headers);
//print_r($headers.',Content-Length: '.strlen($text));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request->to_postdata());
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$rsp = curl_exec($ch);
echo "\n\n\n\n";
var_dump($rsp);
//print_r($rsp);
?>
Currently, this new code returns a
{"bossresponse":{"responsecode":"500","reason":"non 200 status code
from backend: 415"}
error.
You send no POST data, hence no Content-Length being sent. To make a correct curl request you need to specify which data you like to send. In your case it is likely to be:
curl_setopt($ch, CURLOPT_POSTFIELDS, $request->to_postdata());
IF it should be a POST request. The PlaceSpotter docs reads:
The PlaceSpotter Web service supports only the HTTP PUT method. Other HTTP methods are not supported.
So I assume it should be PUT method instead:
$request = OAuthRequest::from_consumer_and_token($consumer, NULL,"PUT", $url,$args);
....
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
EDIT for 415 response code
It may be an issue with double urlencodeing.
Try to set arguments as unencoded text:
$args["documentType"] = "text/plain";
$args["documentContent"] = $text;
As per RFC-2616 Content-Type header indicates the size of the entity-body without headers. So if you would like to make POST requests without entity-body you should specify Content-Length: 0. Give this a try.
I'm trying to construct a PHP POST request that includes some binary data, following on from a previous StackOverflow question. The data is being submitted to this API call: http://www.cyclestreets.net/api/#addphoto
This is my PHP code:
$file = $_FILES['mediaupload'];
$file_field="#$file[tmp_name]";
$fields = array(
'mediaupload'=>$file_field,
'username'=>urlencode($_POST["username"]),
'password'=>urlencode($_POST["password"]),
'latitude'=>urlencode($_POST["latitude"]),
'longitude'=>urlencode($_POST["longitude"]),
'datetime'=>urlencode($_POST["datetime"]),
'category'=>urlencode($_POST["category"]),
'metacategory'=>urlencode($_POST["metacategory"]),
'caption'=>urlencode($_POST["description"])
);
$fields_string = http_build_query($fields);
echo 'FIELDS STRING: ' . $fields_string;
$url = 'https://www.cyclestreets.net/api/addphoto.json?key=$key';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec ($ch);
This is what my PHP file outputs:
FIELDS STRING: mediaupload=%40%2Fprivate%2Fvar%2Ftmp%2FphpHjfkRP&username=testing&password=testing&latitude=auto&longitude=auto&datetime=auto&category=cycleparking&metacategory=good&caption=
API RESPONSE: {"request":{"datetime":"1309886656"},"error":{"code":"unknown","message":"The photo was received successfully, but an error occurred while processing it."},"result":{}}
I believe this means that everything else about the request is OK, apart from the format of the binary data. Can anyone tell me what I am doing wrong?
CURL can accept a raw array of key=>value pairs for POST fields. There's no need to do all that urlencode() and http_build_query() stuff. Most likely the # in the array is being mangled into %40, so CURL doesn't see it as a file upload attempt.
$fields = array(
'mediaupload'=>$file_field,
'username'=> $_POST["username"),
etc...
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields);
The http_build_query function generates a URL encoded query string which means that the "#file.ext" is URL encoded in the output as a string and cURL doesn't know that you're trying to upload a file.
My advice would be not to include the file to upload in the http_build_query call and included manually in the CURLOPT_POSTFIELDS.
$file = $_FILES['mediaupload'];
$file_field="#$file[tmp_name]";
$fields = array(
'username'=>urlencode($_POST["username"]),
'password'=>urlencode($_POST["password"]),
'latitude'=>urlencode($_POST["latitude"]),
'longitude'=>urlencode($_POST["longitude"]),
'datetime'=>urlencode($_POST["datetime"]),
'category'=>urlencode($_POST["category"]),
'metacategory'=>urlencode($_POST["metacategory"]),
'caption'=>urlencode($_POST["description"])
);
$fields_string = http_build_query($fields);
echo 'FIELDS STRING: ' . $fields_string;
$url = 'https://www.cyclestreets.net/api/addphoto.json?key=$key';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, 'mediaupload=' . $file_field . '&' . $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec ($ch);