Retrieving response after posting data using PHP Curl - php

I am trying to make an API call to Localbitcoins API using Curl, but I am having difficulty getting the response to return properly. I have looked at my Curl request and nothing looks out of place.
Here is the API call I am trying to get:
Base URL: https://localbitcoins.com/oauth2/access_token/
Required arguments: client_id, client_secret, username, password, grant_type=password
Optional arguments: None
If successful, JSON like so will be returned immediately:
{
"access_token": the access token,
"scope": "read",
"expires_in": seconds to expiry,
"refresh_token": a refresh token
}
and here is the function I have written to try and retrieve the access_token:
function authenticate($parameters) {
$url = 'https://localbitcoins.com/oauth2/access_token/';
$parameters['client_id'] = 'redacted';
$parameters['client_secret'] = 'redacted';
$data = http_build_query($parameters);
// Initialize the PHP curl agent
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, "curl");
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
// curl_setopt($ch, CURLOPT_VERBOSE, true);
$result = curl_exec($ch);
if ($result === false)
throw new Exception ("curl Error: " . curl_error($ch));
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_status != 200)
throw new Exception("Request Failed. http status: " . $http_status);
curl_close($ch);
// Trim any whitespace from the front and end of the string and decode it
$result = json_decode(trim($result));
if (($error = get_json_error()) !== false) {
throw new Exception("json_decode failed: " . $error);
}
// Verify that we got a valid response
if (!isset($result->status))
{
throw new Exception("API response did not contain 'status'");
exit;
}
if ($result->status == 'error')
{
throw new Exception("API call failed: " . $result->message);
exit;
}
// The API call succeeded, return the requested data
return $result->data;
}
and calling the function:
authenticate(array(
'grant_type' => 'password',
'username' => 'redacted',
'password' => 'redacted'));
All this returns is FATAL ERROR and a 400 ERROR for BAD REQUEST. Any help would be greatly appreciated!

I don't think it's worth your time to develop for the current Localbitcoins API. It's very poorly documented with a lot of broken features. If you look at the Developer forum, it's not well maintained and its riddled with complaints:
https://localbitcoins.com/forums/#!/dev/developers-and-affiliates
I personally inquired on the status of the API with one of the Localbitcoin developers, and he told me that they are pushing out an updated API within the next two weeks.
As per your question specifically, it seems like the issue has existed since October 2013:
https://localbitcoins.com/forums/#!/dev/developers-and-affiliates#problems-with-grant-typepa
Doesn't look like anyone from the Localbitcoins team has resolved it either. I think you are better off holding off for their new API.
Cheers!

can you try this...
$result = curl_exec($ch);
echo nl2br($result);
curl_close($ch);

Related

php cURL - connect, if token invalid, POST login credentials, convert token output into new variable

An API requires a valid token to be in the URL. The token only lasts 10 mins.
the opening part of my script is:
<?php
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, "https://rota.com/publicapi/XXtokenXX/date/2020-04-02/locations/");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec ($curl);
curl_close ($curl);
I need some code to do this:
If response is not a valid token,
Then POST username=name&password=pass to rota.com/publicapi/login
the response will be:
<auth>
<token>XXnew-tokenXX</token>
</auth>
I then need to re-attempt to connect to API with curl, using this new token in the URL
I am out of my depth with this part of the script. Any help appreciated. I'm a keen amateur, so clear instruction and code are appreciated. Thanks in advance
this worked. Had to trim the new token as for some reason when using it within the url string it was adding a space to each end.
<?php
//try to use an existing token
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, "https://rota.com/publicapi/XXtokenXX/date/2020-04-02/locations/");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec ($curl);
curl_close ($curl);
// if token invalid try and get a new one
if ($output == 'Token not valid or login credentials have expired') {
$curl2 = curl_init();
curl_setopt ($curl2, CURLOPT_URL, "https://rota.com/publicapi/login/");
curl_setopt($curl2, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl2, CURLOPT_POSTFIELDS,
"username=user&password=pass");
$output2 = curl_exec ($curl2);
curl_close ($curl2);
echo $output2 ;
// create new url and display it
$curl3url = "https://rota.com/$output2/date/2020-04-02/locations/" ;
trim($curl3url," "); ;
echo '<br>curl3url is<br>' ; echo $curl3url ;
// try connect to API with new URL and print the output
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL, $curl3url);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
$output3 = curl_exec ($curl_handle);
curl_close ($curl_handle);
echo $output3 ;
}
else {
$xml = simplexml_load_string($output, null, LIBXML_NOCDATA) or die("Could not load xml");
}
?>
You will want to encapsulate the cURL with a class/method or a function so you can easily redo the call. If there is an SDK, it's probably worth using. If not, try something like a class or encapsulation to clean up your code.
Based on your own answer, it would be better to make a function for the cURL part:
# Contain all your call login inside this function,
# it keeps copy/paste down to minimum
function transmit($path, &$token, $attr = false, $method = 'get', $retry = true)
{
# I would trim any leading/trailing separator because it will add it
# automatically down below
$path = trim($path, '/');
# Fetch the token if it's not already set though ignore if login or
# it will likely do an infinite loop
if(empty($token) && $path != 'login')
$token = fetchToken();
# Since this will almost never change, just assign it here. If they ever change
# then you just change it in this one spot instead of every instance in your
# whole site where you copy/pasted it
$endpoint = "https://rota.com/publicapi";
# Create the query automatically
if($attr) {
$query = http_build_query($attr);
$attr = '?'.$query;
}
# Create the final path
# array_filter will remove empty attributes before imploding to a path
$url = implode('/', array_filter([
$endpoint,
# Make sure to remove the token on a login call
($path == 'login')? false : $token,
$path,
$attr
]));
# Standard start here
$curl = curl_init();
# Compile the endpoint
curl_setopt ($curl, CURLOPT_URL, $url);
# If you want to specifically post, then accommodate. Just change "$method" in
# when you call this function
if($method == 'post') {
# First check if there is a query already created
if($query)
curl_setopt($curl2, CURLOPT_POSTFIELDS, $query);
}
# Standard bit here
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
# Standard exec
$response = curl_exec($curl);
# Same ol
curl_close($curl);
# Just check for a portion of the string is necessary
if(stripos($response, 'Token not valid') !== false) {
# Fetch the token, if it fails, the program will throw exception
$token = fetchToken();
# If you have it set to retry original, it will try again
if($retry) {
# Set to stop retrying here. You don't want an infinite loop
return transmit($path, $token, $attr, $method, false);
}
# Stop at this point
return false;
}
# If token was valid, send back original response
return $response;
}
# Create a function to fetch the token in the background
function fetchToken()
{
# Send a post
$fetchToken = transmit('login', false, [
'username' => 'whatever',
'password' => 'whatever'
], 'post', false);
if($fetchToken) {
# Convert the string to xml
$xml = simplexml_load_string($output, null, LIBXML_NOCDATA);
# Assign token to session for storage and then also update the session
# for calls that happen after this call
$token = trim($xml->token->__toString());
}
# Stop the program if token not fetched
if(empty($token))
throw Exception('An error occurred fetching the security token.');
# Assign to session and return the token
return $_SESSION['rota_token'] = $token;
}
So you should be able to do it like this:
# Try and get token
# If this line throws error, use:
# $token = ($_SESSION['rota_token'])? $_SESSION['rota_token'] : false;
$token = ($_SESSION['rota_token'])?? false;
# Fetch the data and make sure to pass the token to each transmit()
$data = transmit('date/2020-04-02/locations/', $token);
print_r($data);
Anyway I have not fully tested this, so there might be something in the syntax, but it's heavily commented so you can get what is supposed to happen.

Cannot upload an image on imgur [API 3]

I'm trying to upload images on imgur but I often have problem and I am not able to upload the image.
In the code I'll publish I don't understand why I keep getting the boolean value: false as result of curl_exec($ch); and not a json string. From the PHP Manual it means that the post failed but I don't understand why.
Here I successfully read the image from a post request
$imageContent = file_get_contents($myFile["tmp_name"][$i]);
if ($imageContent === false) {
// Empty image - I never get this error
} else {
//Image correctly read
$url = $this->uploadLogged($imageContent);
}
While here is my attempt to upload it
public function uploadLogged($image){
$upload_route = "https://api.imgur.com/3/image";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $upload_route);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer '.$this->access_token));
curl_setopt($ch, CURLOPT_POSTFIELDS, array('image' => base64_encode($image)));
$response = curl_exec($ch);
$responseDecoded = json_decode($response);
curl_close ($ch);
$link = $responseDecoded->data->link;
if( empty($link) ){
throw new Exception("Cannot upload the image.<br>Response: ".json_encode($response));
}
return $link;
}
Moreover $this->access_token correspond to a valid access token
when curl_exec returns bool(false), there was an error during the transfer. to get an extended error description, use the curl_errno() and curl_error() functions. to get even more detailed info of the transfer, use the CURLOPT_VERBOSE and CURLOPT_STDERR options of curl_setopt. eg
$curlstderrh=tmpfile();
curl_setopt_array($ch,array(CURLOPT_VERBOSE=>1,CURLOPT_STDERR=>$curlstderrh));
$response = curl_exec($ch);
$curlstderr=file_get_contents(stream_get_meta_data($curlstderrh)['uri']);
fclose($curlstderrh);
if(false===$response){
throw new \RuntimeException("curl_exec failed: ".curl_errno($ch).": ".curl_error($ch).". verbose log: $curlstderr");
}
unset($curlstderrh,$curlstderr);
should get you both the libcurl error code, an error description, and a detailed log of what happened up until the error, in the exception message.
common issues include an SSL/TLS encryption/decryption error, timeout errors, and an unstable connection.

Google identity toolkit: JWT verification fails with status 500, "message": null

According to the implementation guide and common sense, I'd like to verify the JWT token issued to an user who has logged in to my site through the Google Identity Toolkit, to prevent forgery and.. just in case.
A POST request through cURL (code below) to https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo containing the idToken (string), localId (list) and email (list) should suffice. My application uses as a local id the tokenId issued by the IDSP.
However, this is what I get:
Error: call to URL https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=MyAPIKey failed with status 500, response { "error": { "code": 500, "message": null } } , curl_error , curl_errno 0
And frankly, I'm at utter loss: my Google-fu only turned up logging out and back in, but unsurprisingly it hasn't solved the issue.
Of further concern is the necessity of fetching the user display name and image, through the same relyingparty.
Code
function verifytoken($data){
$url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=MyAPIKey";
var_dump($data);
$content = json_encode($data);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER,
array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 201 ) {
die("Error: call to URL $url failed with status $status, response $json_response, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
$response = json_decode($json_response, true);
var_dump($response);
}
$tok=array('idToken'=>$gitkitUser->getUserId(),'localId'=>array($gitkitUser->getUserId()),'email'=>array($gitkitUser->getEmail()));
verifytoken($tok);
To verify the Google Identity Toolkit JWT token, you do not need to make any HTTP request. It is recommended to use one of the Google Identity Toolkit libraries (Java/Python/Php/Ruby/Go/Nodejs) to do that locally. The token already includes the email/name/photo_url of the user.

Trying to make an API request using PHP with AWS Route53

I need to make one API request to AWS Route53 to create a reusable delegation set. You can't do this through the console web interface, it has to be through the API.
Here is the documentation for making this API request: http://docs.aws.amazon.com/Route53/latest/APIReference/api-create-reusable-delegation-set.html
<?php
$baseurl = "route53.amazonaws.com/2013-04-01/delegationset";
$body = '<?xml version="1.0" encoding="UTF-8"?>
<CreateReusableDelegationSetRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
<CallerReference>whitelabel DNS</CallerReference>
</CreateReusableDelegationSetRequest>';
$ch = curl_init();
// Set query data here with the URL
curl_setopt($ch, CURLOPT_URL, $baseurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POSTFIELDS, $body );
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: route53.amazonaws.com','X-Amzn-Authorization: '));
curl_setopt($ch, CURLOPT_TIMEOUT, '3');
$rest = curl_exec($ch);
if ($rest === false)
{
// throw new Exception('Curl error: ' . curl_error($crl));
print_r('Curl error: ' . curl_error($ch));
}
curl_close($ch);
print_r($rest);
?>
I know the request isn't signed/authenticated, but I'm not even able to connect to the server. I would at least like to get an error message that says I'm not authenticated before I continue. Instead all I get is "connection refused".
I'm sure I'm doing something completely wrong here. But Google has been of no use.
scrowler was right. I changed:
$baseurl = "route53.amazonaws.com/2013-04-01/delegationset";
to
$baseurl = "https://route53.amazonaws.com/2013-04-01/delegationset";
I got the error message I was expecting and now I can work on the next step.

OAuth, PHP, Rest API and curl gives 400 Bad Request

We got a couple of apps, utilizing the car2go Rest-API with OAuth 1.0.
All our web apps stopped working 2 days ago. All curl POST requests are failing now with the following error:
400 Bad Request
Your browser sent a request that this server could not understand.
Error code: 53
Parser Error: [Content-Length: -]
I spend a lot of time trying to figure out if the problem is my oauth workflow. But in the end all parameters and signatures and stuff is correct. I successfully fire the POST via Postman (REST-Client)
So my conclusion is that somehow the php code for the curl is suddenly not working anymore.
This is the (very ugly) curl function. A difference to most tutorials about curl POST is, that I'm passing a full URL with all parameters already attached, so I don't need CURLOPT_POSTFIELDS.
function curlAPI($params) {
//open connection
$ch = curl_init();
$url = $params['url'];
curl_setopt($ch,CURLOPT_HEADER,false);
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
curl_setopt($ch, CURLOPT_MAXREDIRS,50);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
if($params['type'] == 'POST') {
// POST
curl_setopt($ch,CURLOPT_POST, true);
} else if($params['type'] == 'DELETE') {
// DELETE
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
} else if($params['type'] == 'PUT') {
$update_json = array();
// PUT
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS,'');
} else {
// GET
curl_setopt($ch,CURLOPT_POST,0);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
//execute post
$result['result'] = curl_exec($ch);
// debug
if (FALSE === $result['result']) {
$result['errorInfo'] = curl_error($ch).' - '.curl_errno($ch);
}
$reponseInfo = array();
$reponseInfo['info'] = curl_getinfo($ch);
$reponseInfo['error'] = curl_error($ch);
//close connection
curl_close($ch);
$result['reponseInfo'] = $reponseInfo;
return json_encode($result);
}
Ok, this is what fixed this nightmare:
curl_setopt($ch,CURLOPT_HTTPHEADER ,array('Content-Length: 0'));
Aparrently it's not ok to send a curl POST without a header.

Categories