I converted the following Python code from the official docs(https://docs.sandbox.gemini.com/rest-api/#private-api-invocation) to PHP but I always get InvalidSignature error:
url = "https://api.gemini.com/v1/mytrades"
gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()
t = datetime.datetime.now()
payload_nonce = time.time()
payload = {"request": "/v1/mytrades", "nonce": payload_nonce}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()
request_headers = {
'Content-Type': "text/plain",
'Content-Length': "0",
'X-GEMINI-APIKEY': gemini_api_key,
'X-GEMINI-PAYLOAD': b64,
'X-GEMINI-SIGNATURE': signature,
'Cache-Control': "no-cache"
}
response = requests.post(url, headers=request_headers)
My PHP code is this and everything looks correct:
$b64 = base64_encode(utf8_encode(json_encode([ "request" => "/v1/balances", "nonce" => time() ])));
$header = [
'Content-Type: text/plain',
'Content-Length: 0',
'X-GEMINI-APIKEY: master-XXXXXXX',
'X-GEMINI-PAYLOAD: ' . $b64,
'X-GEMINI-SIGNATURE: ' . md5(hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64)),
'Cache-Control: no-cache'
];
$ch = curl_init('https://api.sandbox.gemini.com/v1/balances');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
echo curl_exec($ch);
Error:
{"result":"error","reason":"InvalidSignature","message":"InvalidSignature"}
I don't have any access to the API, but could you please try the following chagnes:
Remove the MD5 function from the signature calculation. The hash_hmac function in PHP already does this by default.
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64),
Switch around the payload and the key in the same line:
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', $b64, utf8_encode('XXXXXXXXXX')),
Related
I have never used Curl but I am trying to complete a self api project at my job just to gain some experience.
And I am stuck on the first step... I want to authenticate with an api.
So I am running this code and I expect to see a Success 200 response with my access token, etc but I get nothing.
No error, no feedback, the page just opens up blank
I have tired to use CURLINFO_HEADER_OUT from this page What Steps do you Take to Troubleshoot Problems with PHP cURL? but still I got a blank page
Anyway thank you to anyone in advantage for some tips
<?php
const TOKEN_ENDPOINT = 'xxxxxx';
const GRANT_TYPE = 'xxxxx';
const CLIENTID = 'xxxxxxxxxxx';
const CLIENTSECRET = 'xxxxxxxxxxxxxx';
const USERNAME = 'xxxxxxxxxxxxxxxxx';
const PASSWORD = 'xxxxxxxxxxxxxxx';
$clientCredentials = base64_encode(CLIENTID . ':' . CLIENTSECRET);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => TOKEN_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 => 'POST',
CURLOPT_POSTFIELDS =>'grant_type=' . GRANT_TYPE . '&username=' . USERNAME . '&password=' . PASSWORD ,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/x-www-form-urlencoded',
'Accept: application/json',
'Authorization: Basic ' . $clientCredentials
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response ;
?>
To check curl error, the best way is to use curl_error function
$response = curl_exec($curl);
if (curl_errno($curl)) {
$error_msg = curl_error($curl);
}
curl_close($curl);
echo $response ;
See the description of libcurl error codes here
See the description of PHP curl_errno() function here
See the description of PHP curl_error() function here
When all else fails, i do this (code snippet from my ApiHelper curl wrapper). Use your own logger or evidence printing mechanism. Most every time the answer to the puzzle is in the printed stuff :
// we simply stream curlopt debug info to a temporary
// file, so we can log it out later (when helper is set
// to verbose)
$st = microtime(true);
$verbiage = null;
if ($this->verbose) {
// write out the curl debug stuff
curl_setopt($ch , CURLINFO_HEADER_OUT , false);
curl_setopt($ch , CURLOPT_VERBOSE , true);
$verbiage = fopen('php://temp' , 'w+');
curl_setopt($ch , CURLOPT_STDERR , $verbiage);
}
$resp = curl_exec($ch);
$end = microtime(true); // get as float
$delta = 1000.0 * ($end - $st); // treat as float
$this->roundTripInMs = sprintf("%.2f" , $delta);
$this->getInstanceLogger()->debug("WS call : round trip took " . sprintf("%.2f" , $delta) . " ms.");
if ($this->verbose) {
// rewind and log the verbose output
rewind($verbiage);
$verboseLog = stream_get_contents($verbiage);
$this->getInstanceLogger()->info("Verbose cURL : \n$verboseLog");
fclose($verbiage);
}
$this->curlinfo = curl_getinfo($ch);
$this->verbose && $this->getInstanceLogger()->info("cURL info : \n" . json_encode($this->curlinfo , PEHR_PRETTY_JSON));
$this->httpStatus = curl_getinfo($ch , CURLINFO_RESPONSE_CODE);
if (!$resp) {
if ($this->verbose) $this->getInstanceLogger()->error("CURL request to [$url] failed\n" . json_encode($this->curlinfo , PEHR_PRETTY_JSON));
return 0;
}
curl_close($ch);
if ($resp && $this->verbose) $this->getInstanceLogger()->debug("Received json \n" . $resp);
I’m having a rough time getting a simple Oauth 1 api call to work. I’ve figured out how to access the data I want via Postman and have made successful calls for lists, starred items, etc. If I copy an already-run call from postman and rerun it locally, as long as the timestamp is the timeout time (3 minutes) the api will accept it and I’ll be able to receive and parse the json data.
I've tested and run all of the elements of the code in isolation and everything seems to work fine... What seems to not work is generating a proper signature.
Full code is below... Any help is appreciated!
<?php
// Include Manually Entered Credentials
include 'credentials.php';
####################################
// GENERATE TIMESTAMP:
$oathtimestamp = time();
// GENERATE NONCE:
function generateNonce() {
$length = 15;
$chars='1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';
$ll = strlen($chars)-1;
$o = '';
while (strlen($o) < $length) {
$o .= $chars[ rand(0, $ll) ];
}
return $o;
}
$oathnonce = generateNonce();
####################################
// API Determinants
$APIurl = "https://www.example.com/api/";
####################################
// GENERATE Oath1 Signature:
$signatureMethod = "HMAC-SHA1";
$oathVersion = "1.0";
$base = "POST&".$APIurl."&"."folder_id=starred"."&limit=25"."&oauth_consumer_key=".$oauth_consumer_key."&oauth_nonce=".$oathnonce."&oauth_signature_method=".$signatureMethod."&oauth_timestamp=".$oathtimestamp."&oauth_token=".$oauth_token."&oauth_version=".$oathVersion."&x_auth_mode=client_auth"."&x_auth_password=".$x_auth_password."&x_auth_username=".$x_auth_username;
//echo $base;
$key = $oauth_consumer_key."&".$oath_tokenSecret;
//echo $key;
$signature = base64_encode(hash_hmac('sha1', $oauth_consumer_key, $key));
//echo $signature;
$oath_getstringlength =
"folder_id=starred".
"&limit=25".
"&oauth_consumer_key=".$oauth_consumer_key.
"&oauth_nonce=".$oathnonce.
"&oauth_signature=".$signature.
"&oauth_signature_method=".$signatureMethod.
"&oauth_timestamp=".$oathtimestamp.
"&oauth_token=".$oauth_token.
"&oauth_version=".$oathVersion.
"&x_auth_mode=client_auth".
"&x_auth_password=".$x_auth_password.
"&x_auth_username=".$x_auth_username;
$oath_stringlength = strlen($oath_getstringlength);
//echo $oath_stringlength;
####################################
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://www.example.com/api/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>
"folder_id=starred".
"&limit=25".
"&oauth_consumer_key=".$oauth_consumer_key.
"&oauth_nonce=".$oathnonce.
"&oauth_signature=".$signature.
"&oauth_signature_method=".$signatureMethod.
"&oauth_timestamp=".$oathtimestamp.
"&oauth_token=".$oauth_token.
"&oauth_version=".$oathVersion.
"&x_auth_mode=client_auth".
"&x_auth_password=".$x_auth_password.
"&x_auth_username=".$x_auth_username,
CURLOPT_HTTPHEADER => array(
"Accept: */*",
"Accept-Encoding: gzip, deflate",
"Cache-Control: no-cache",
"Connection: keep-alive",
"Content-Length: $oath_stringlength",
"Content-Type: application/x-www-form-urlencoded",
"Host: www.example.com",
"User-Agent: curlAPICall",
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "... cURL Error #:" . $err;
} else {
echo $response;
$jsonresponse = json_decode($response, true);
print_r($jsonresponse);
}
?>
I just started using the BING translate API to do a small volume of translations into most of their supported languages and that works pretty well.
There is a GitHub project that has simple PHP code for making the API call to Microsoft. You mostly just need the API key, and it can be customized pretty easily.
Text-Translation-API-V3-PHP
// NOTE: Be sure to uncomment the following line in your php.ini file.
// ;extension=php_openssl.dll
// **********************************************
// *** Update or verify the following values. ***
// **********************************************
// Replace the subscriptionKey string value with your valid subscription key.
$key = 'ENTER KEY HERE';
$host = "https://api.cognitive.microsofttranslator.com";
$path = "/translate?api-version=3.0";
// Translate to German and Italian.
$params = "&to=de&to=it";
$text = "Hello, world!";
if (!function_exists('com_create_guid')) {
function com_create_guid() {
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
mt_rand( 0, 0xffff ),
mt_rand( 0, 0x0fff ) | 0x4000,
mt_rand( 0, 0x3fff ) | 0x8000,
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
}
function Translate ($host, $path, $key, $params, $content) {
$headers = "Content-type: application/json\r\n" .
"Content-length: " . strlen($content) . "\r\n" .
"Ocp-Apim-Subscription-Key: $key\r\n" .
"X-ClientTraceId: " . com_create_guid() . "\r\n";
// NOTE: Use the key 'http' even if you are making an HTTPS request. See:
// http://php.net/manual/en/function.stream-context-create.php
$options = array (
'http' => array (
'header' => $headers,
'method' => 'POST',
'content' => $content
)
);
$context = stream_context_create ($options);
$result = file_get_contents ($host . $path . $params, false, $context);
return $result;
}
$requestBody = array (
array (
'Text' => $text,
),
);
$content = json_encode($requestBody);
$result = Translate ($host, $path, $key, $params, $content);
// Note: We convert result, which is JSON, to and from an object so we can pretty-print it.
// We want to avoid escaping any Unicode characters that result contains. See:
// http://php.net/manual/en/function.json-encode.php
$json = json_encode(json_decode($result), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo $json;
I also have a Google Cloud account and am looking for something similar for a few languages that Google supports that BING does not. For v2, it is not too hard to call Google to make the return the translations.
I found this GitHub project that seems to work for v2 API calls with an API key, but unfortunately I think that is a fee-for-service program now ?
google-cloud-php-translate
That also seems to work pretty well if you have an API key. If you are using v3, they apparently updated the libraries and support. You can make a CURL call from the command line and they have some of that documented on their website, but I am looking for a way to make the call using a PHP file.
require 'vendor/autoload.php';
use Google\Cloud\Translate\TranslateClient;
$translate = new TranslateClient([
'key' => 'APIKEY'
]);
// Translate text from english to french.
$result = $translate->translate('Hello world!', [
'target' => 'fr'
]);
echo $result['text'] . "\n";
// Detect the language of a string.
$result = $translate->detectLanguage('Greetings from Michigan!');
echo $result['languageCode'] . "\n";
// Get the languages supported for translation specifically for your target language.
$languages = $translate->localizedLanguages([
'target' => 'en'
]);
foreach ($languages as $language) {
echo $language['name'] . "\n";
echo $language['code'] . "\n";
}
// Get all languages supported for translation.
$languages = $translate->languages();
foreach ($languages as $language) {
echo $language . "\n";
}
Not sure that is even possible, but the best I can come up with is something like this based upon the command line CURL, but the authentication is wrong and fails. I do have the .json file for my Project/Service credentials. The ${PROJECT_ID} I presume is the project ID for the account, and Bearer $(gcloud auth application-default print-access-token) I am not sure about. There are some instructions about how to obtain that through the CLI, but is there a way to get that via a PHP file ? Like I say, the v2 version works fine.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://translation.googleapis.com/v3beta1/projects/${PROJECT_ID}/locations/global:detectLanguage");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\n mimeType: 'text/plain',\n content: 'Omnia Gallia est divisa in tres partes'\n}");
curl_setopt($ch, CURLOPT_POST, 1);
$headers = array();
$headers[] = 'Authorization: Bearer $(gcloud auth application-default print-access-token)';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
} else {
echo $result;
}
curl_close ($ch);
There might be clues here, but it talks about exporting the path for the credentials file and running PHP scripts from the command line instead of from a server.
Google Cloud Translate API Samples
I have an irrational dislike for using client libraries, so I didn't install the Google PHP library. From what I can tell, the only way to get the authentication to work is to actually go through the whole Oauth2 process. I think the PHP library handles some of that for you, but this code should work as a standalone solution.
First, make sure you've got your Google Cloud Platform account set up, then create a project, then enable the Translation API, after that, create and configure an API key before creating and configuring an OAuth 2.0 client (make sure you enter the correct redirect url). Nothin' to it! ;-)
If you succeed in getting all of that squared away, you should be good to go!
The page effectively redirects the user to the same page they were just on, but includes the results of a GET request in the url. The response contains a code, that can be used to make another GET request in order to retrieve the access token, and once you've got the access token, you can make a POST request to perform the actual translation.
<?php
$clientId = "{your client id}";
$clientSecret = "{your client secret}";
$clientRedirectURL = "{your redirect URL}";
$login_url = 'https://accounts.google.com/o/oauth2/v2/auth?scope=' . urlencode('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-translation') . '&redirect_uri=' . urlencode($clientRedirectURL) . '&response_type=code&client_id=' . $clientId . '&access_type=online';
if (!isset($_GET['code'])){
header("location: $login_url");
} else {
$code = filter_var($_GET['code'], FILTER_SANITIZE_STRING);
$curlGet = '?client_id=' . $clientId . '&redirect_uri=' . $clientRedirectURL . '&client_secret=' . $clientSecret . '&code='. $code . '&grant_type=authorization_code';
$url = 'https://www.googleapis.com/oauth2/v4/token' . $curlGet;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$data = curl_exec($ch);
$data = json_decode($data, true);
curl_close($ch);
$accessToken = $data['access_token'];
$apiKey = "{your api key}";
$projectID = "{your project id}";
$target = "https://translation.googleapis.com/v3/projects/$projectID:translateText?key=$apiKey";
$headers = array(
"Content-Type: application/json; charset=utf-8",
"Authorization: Bearer " . $accessToken,
"x-goog-encode-response-if-executable: base64",
"Accept-language: en-US,en;q=0.9,es;q=0.8"
);
$requestBody = array();
$requestBody['sourceLanguageCode'] = "en";
$requestBody['targetLanguageCode'] = "pt";
$requestBody['contents'] = array("So, I guess this thing works?");
$requestBody['mimeType'] = "text/plain";
$ch = curl_init($target);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestBody));
$data = curl_exec($ch);
curl_close($ch);
echo $data;
}
Also, I found this tutorial quite helpful.
This probably won't evaluate:
'Authorization: Bearer $(gcloud auth application-default print-access-token)'
It's rather:
// $cmd = 'gcloud auth application-default login';
$cmd = 'gcloud auth application-default print-access-token';
$token = shell_exec($cmd);
besides it probably should be a service account.
It seems google/cloud replaces google/cloud-translate. For Translate, you could edit the translate-v2.json or add translate-v3beta1.json; but v3beta1 has a whole other REST API than v2 ...
I have this command-line cURL example:
curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
-d "{\"data\":{\"name\":\"Device1 Callflow\", \"numbers\":[\"1001\"], \"flow\":{\"module\":\"device\",\"data\":{\"id\":\"$DEVICE_ID\"}}}}" \
http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
My task is to convert this into a PHP function, where the needed values are passed into the function:
function someFunc($AUTH_TOKEN, $ACCOUNT_ID, $DEVICE_ID, $numbers) {}
Normally, I use this sort of code:
function setLimits($auth_token, $accountID, $feature1_cnt, $feature2_cnt) {
$service_url = "http://ip.add.re.ss:8000/v2/accounts/$accountID/limits";
$data = '{"data":{"feature1": ' . $feature1_cnt . ',"feature2": ' . $feature2_cnt . '}}';
$ch = curl_init($service_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Auth-Token: $auth_token",'Content-Type: application/json', 'Content-Length: ' . strlen($data)));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if ($response === false) {
$info = curl_getinfo($ch);
curl_close($ch);
die('error occured during curl exec. Additional info: ' . var_export($info));
}
$decoded = json_decode($response);
if (isset($decoded->response->status) && $decoded->response->status == 'ERROR') {
die('error occured: ' . $decoded->response->errormessage);
}
return(true);
}
BUT, for a specific API call, I need to pass this as the service URL:
http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
How do I do that?
First, change:
$data = '{"data":{"feature1": ' . $feature1_cnt . ',"feature2": ' . $feature2_cnt . '}}';
to:
$data = [
"data" => [
"feature1" => $feature1_cnt,
"feature2" => $feature2_cnt
]
];
You will make a mistake typing out JSON, and it won't be easy to find or fix.
Second, python -mjson.tool
json.tool [...] to validate and pretty-print:
PHP's JSON validation is pretty much just checking if json_decode() returned NULL, and then you can check json_last_error() and json_last_error_msg() for error info. It is not robust.
You can encode JSON in "pretty-printed" format with:
json_encode($foo, JSON_PRETTY_PRINT);
But I can't think of an earthly reason why you would want to do that other than if there are human eyeballs that are going to be looking at it.
Lastly, in answering your question I've realized that I have no actual idea what you're getting at and you really need to clarify why you think you need to do anything you asked about. [other than the validation, I suppose]
I have two problem with hmac
First:
$klucz = "";
$url = "";
$nazwaUsera = "";
$nazwaKlucza = "faktura";
$curlHandle = curl_init($url);
$hashWiadomosci = hmac($klucz, $url .$nazwaUsera.$nazwaKlucza);
$headers = array(
'Accept: application/pdf',
'Content-type: application/pdf; charset = UTF-8',
'Authentication: IAPIS user='.$nazwaUsera.', hmac-
sha1='.$hashWiadomosci
);
if is hmac problem is: Fatal error: Uncaught Error: Call to undefined function hmac()
Bat if is
$klucz = "";
$url = "";
$nazwaUsera = "";
$nazwaKlucza = "faktura";
$curlHandle = curl_init($url);
$hashWiadomosci = hash_hmac($klucz, $url, $nazwaUsera.$nazwaKlucza);
$headers = array(
'Accept: application/pdf',
'Content-type: application/pdf; charset = UTF-8',
'Authentication: IAPIS user='.$nazwaUsera.', hmac-
sha1='.$hashWiadomosci
);
problem is: Warning: hash_hmac(): Unknown hashing algorithm: EC8A18CEC9D1F1B2
how solved this?
Try this:
hashWiadomosci = hash_hmac('sha256', $klucz . $url, $nazwaUsera.$nazwaKlucza);
First parameter must be the hash algorithm you need to be used (you can call hash_algos to inspect supported algorithms in your platform. I.E. md5", "sha256", "haval160,4".