PHP URL query parameters in Etsy OAuth 1.0 not working - php

After getting all the credentials I'm now requesting a resource from Etsy API. It's working fine without query parameters to the url but when I add them I get signature invalid.
Here's what I got working without the query parameters in the url:
// enconding, sorting and creating the base URI
function buildBaseString($baseURI, $method, $params){
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}
// create encoded header
function buildAuthorizationHeader($oauth){
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
$consumer_key = 'the_key';
$consumer_secret = 'the_secret';
$shop_id = '00000000000';
$oauth_access_token = 'access_token';
$oauth_access_token_secret = 'token_secret';
$receipts_by_status_url = 'https://openapi.etsy.com/v2/shops/'.$shop_id.'/receipts/opens';
$oauth = array(
'oauth_callback' => 'oob',
'oauth_consumer_key' => $consumer_key,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $oauth_access_token,
'oauth_version' => '1.0',
);
$base_info = buildBaseString($receipts_by_status_url, 'GET', $oauth);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
$header = array(buildAuthorizationHeader($oauth), 'Expect:', 'Content-Type: application/x-www-form-urlencoded');
/*
* Set curl options
*/
//ob_start();
//$curl_log = fopen('php://output', 'w');
$ch = curl_init($receipts_by_status_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 25);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// Execute curl
$result_token = curl_exec($ch);
when I add the parameters to the url:
$receipts_by_status_url = 'https://openapi.etsy.com/v2/shops/'.$shop_id.'/receipts/opens/?includes=Listings';
I get signature invalid.
$base info:
'GET&https%3A%2F%2Fopenapi.etsy.com%2Fv2%2Fshops%2F12962774%2Freceipts%2Fopen%3Fincludes%3DListings&oauth_callback%3Doob%26oauth_consumer_key%thekey%26oauth_nonce%3D1607965396%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1607965396%26oauth_token%oauthtoken%26oauth_version%3D1.0'
$oauth signature:
0Dr9wz24LU6NPkO7eKvP//HCOWk=
$header:
0 => string 'Authorization: OAuth oauth_callback="oob", oauth_consumer_key="consumerkey", oauth_nonce="1607965396", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1607965396", oauth_token="oauthtoken", oauth_version="1.0", oauth_signature="0Dr9wz24LU6NPkO7eKvP%2F%2FHCOWk%3D"' (length=301)
1 => string 'Expect:' (length=7)
2 => string 'Content-Type: application/x-www-form-urlencoded
What am I doing wrong?

I got it working.
I Manually created the base string without the function in the question, this was the root of the problem, because when I added parameters to the endpoint it didn't work.
The server takes the parameters in the authrization header and creates an OAuth signature and compares it to yours, if the don't match you'll get invalid signature like in my case.
The base string should be 3 chunks of data concatenated together and rawurlencoded:
Http method '&' url endpoint '&' params
Things to make sure:
Use a url endpoint without query parameters
Make sure the whole base string has only two ampersands.
Sort params alphabetically.
Use Postman and succeed in sending the request there, after that you can compare the signature generated in the header there to yours, when you can match it then it should work.
Make sure you're using the long url (with query params) in cURL, the clean one is only to create the base string.
I didn't notice but Etsy is actually sending the base string they created from the params in the response when the signature is invalid, all I had to do is compare mine to theirs and fix it.
Hope I helped anyone

Related

Google Translate API v2, v3 PHP

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 ...

Amazon MWS Order API timestamp must follow ISO8601

I am using Amazon MWS order API (ListOrders) and I can successfully run it on Amazon Scratchpad but I am getting the following error
Sender
MalformedInput
timestamp must follow ISO8601
Below is the php script which I got from some Stackoverflow post
$base_url = "https://mws.amazonservices.com/Orders/2013-09-01";
$method = "POST";
$host = "mws.amazonservices.com";
$uri = "/Orders/2013-09-01";
$params = array(
'AWSAccessKeyId' => "AWSAccessKeyId",
'Action' => "ListOrders",
'SellerId' => "SellerId",
'SignatureMethod' => "HmacSHA256",
'SignatureVersion' => "2",
//'Timestamp'=> gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time()),
'Timestamp'=> gmdate("Y-m-d\TH:i:s\Z", time()),
'Version'=> "2013-09-01",
'MarketplaceId' => "MarketplaceId",
'CreatedAfter'=>'2014-07-06T19%3A00%3A00Z',
'CreatedBefore'=>'2014-07-08T19%3A00%3A00Z'
);
// Sort the URL parameters
$url_parts = array();
foreach(array_keys($params) as $key)
$url_parts[] = $key . "=" . str_replace('%7E', '~', rawurlencode($params[$key]));
sort($url_parts);
// Construct the string to sign
$url_string = implode("&", $url_parts);
$string_to_sign = "GET\nmws.amazonservices.com\n/Orders/2013-09-01\n" . $url_string;
// Sign the request
$signature = hash_hmac("sha256", $string_to_sign, AWS_SECRET_ACCESS_KEY, TRUE);
// Base64 encode the signature and make it URL safe
$signature = urlencode(base64_encode($signature));
$url = "https://mws.amazonservices.com/Orders/2013-09-01" . '?' . $url_string . "&Signature=" . $signature;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$parsed_xml = simplexml_load_string($response);
print '<pre>';
print_r($response);
Can anyone help find my mistake?
You are sending three date values:
'Timestamp'=> gmdate("Y-m-d\TH:i:s\Z", time()),
'CreatedAfter'=>'2014-07-06T19%3A00%3A00Z',
'CreatedBefore'=>'2014-07-08T19%3A00%3A00Z'
For a start, you can get rid of the second parameter to gmdate() since it defaults to time() anyways. Other than that it's fine and should not be the cause of your problem.
The other two parameters have url encoded characters (the colon is encoded as %3A) which you then send through rawurlencode() to encode once more. That will replace the percent sign of above encoing with %25. The CreatedAfter value you are actually sending to Amazon for CreatedAfter is therefore 2014-07-06T19%253A00%253A00Z. Try this instead:
'Timestamp'=> gmdate("Y-m-d\TH:i:s\Z"),
'CreatedAfter'=>'2014-07-06T19:00:00Z',
'CreatedBefore'=>'2014-07-08T19:00:00Z'
I too had the same issue with the java api .i fixed mine by sending the timestamp in following format "yyyy-MM-dd'T'hh:mm:ss'Z'".

twitter oauth request token fails

i tried to implement "Sign in with Twitter"
i see lots of questions at this topic here, i've read lots of them and stuck at all
i used folowing links :
implementing Sign in with Twitter
POST oauth/request_token
Creating a signature
Authorizing a request
and the result is response : Failed to validate oauth signature and token (may be it's most often error =))
what i've done:
date_default_timezone_set('UTC');
$oauth_consumer_key = 'mYOauThConsuMerKey'; //from app settings
function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
$oauth_nonce = generate_nonce();
$http_method = 'POST';
$base_url = 'https://api.twitter.com/oauth/request_token';
$oauth_signature_method = 'HMAC-SHA1';
$oauth_timestamp = time();
$oauth_token = 'mytokenFromAPPsettoings';
$oauth_version = '1.0';
$oauth_callback = 'http://twoends.home/backend';
$params = array(
rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
rawurlencode('oauth_token')=>rawurlencode($oauth_token),
rawurlencode('oauth_version')=>rawurlencode($oauth_version),
);
ksort($params);
$parameter_string = http_build_query($params,'','&');
$base_string = strtoupper($http_method).'&';
$base_string .= rawurlencode($base_url).'&';
$base_string .= rawurlencode($parameter_string);
$oauth_consumer_secret = 'myappconsumersecret';
$oauth_token_secret = 'mytokensecret';
$oauth_signing_key =rawurlencode($oauth_consumer_secret).'&'.rawurlencode($oauth_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_string, $oauth_signing_key, true));
$DST ='OAuth ';
foreach($params as $key=>$value){
$DST .= $key.'='.'"'.$value.'"&';
}
$DST = rtrim($DST,'&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$DST));
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
so,this code was struggled much and it still produces error
in one topic i've read that token isn't needed on this stage : with it or without - nothing matters - still same error
tried to play with time (set UTC) - same error
also i tried to use someones working code like this but that didn't work for me
why i'm not using someones lib - because i want to go through algo step-by-step, but i'm tired with it and neeed help
thx in advance, any help appreciated, may be got an example of working step-by-step guide ?
There appear to be several things wrong with your code:
1) Your params array should contain oauth_consumer_key instead of oauth_token
$params = array(
rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
rawurlencode('oauth_consumer_key')=>rawurlencode($oauth_consumer_key),
rawurlencode('oauth_version')=>rawurlencode($oauth_version),
);
2) Your signing key for a request token should be constructed using oauth_consumer_secret followed by an ampersand:
$oauth_signing_key =rawurlencode($oauth_consumer_secret).'&';
3) You don't appear to be setting the signature anywhere in the Authorization header. Do:
$DST ='OAuth ';
foreach($params as $key=>$value){
$DST .= $key.'='.'"'.$value.'"&';
}
$DST .= 'oauth_signature='.rawurlencode($oauth_signature)
It looks like the oauth_callback url is being triple encoded in the basestring. It should be of the form:
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&
oauth_callback%3Dhttp%253A%252F%252Ftwoends.home%252Fbackend%26
oauth_consumer_key%3Dapp_cons_keyQjQ7u5lgwA ...
In your basestring:
oauth_callback%3Dhttp%25253A%25252F%25252Ftwoends.home%25252Fbackend
The culprit appears to be 'http_build_query'.
i'd like to take a new look at a problem and post new data
thanks to #Jonny S i found few mistakes and got another error =)
so, my workflow now looks:
function to generate nonce,additional info: oauth_nonce in api, oauth.net
function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
Implementing Sign in with Twitter (this link shows us what header we should POST in advance) and shows us direction to move - POST oauth/request_token
this page links with oauth docs section 6.1
there we can find what parameters are needed to request token, but in official docs you would not find "oauth_calback" param which is a required param in twitter API!
the next step i do - collecting needed params:
oauth_consumer_key
$oauth_consumer_key = 'YoUrS KEy FrOm aPP ApI';
oauth_nonce
$oauth_nonce = generate_nonce();
oauth_callback
$oauth_callback = 'http://twoends.home/backend';
oauth_sinature_method
$oauth_signature_method = 'HMAC-SHA1';
oauth_timestamp
$oauth_timestamp = time();
oauth_version
$oauth_version = '1.0';
additional parameters (needed in process):
Base URL
$base_url = 'https://api.twitter.com/oauth/request_token';
HTTP Method
$http_method = 'POST';
OAuth Signature (the most tricky part)
here we have an API page on how to do it Creating a signature
first we need to collect all needed params together,percent encode and sort them, i pushed them to array:
$params = array(
rawurlencode('oauth_consumer_key')=>rawurlencode($oauth_consumer_key),
rawurlencode('oauth_nonce')=>rawurlencode($oauth_nonce),
rawurlencode('oauth_callback')=>rawurlencode($oauth_callback),
rawurlencode('oauth_signature_method')=>rawurlencode($oauth_signature_method),
rawurlencode('oauth_timestamp')=>rawurlencode($oauth_timestamp),
rawurlencode('oauth_version')=>rawurlencode($oauth_version),
);
and then sort:
ksort($params);
then i'm creating parameter string:
$parameter_string = http_build_query($params,'','&');
result:
param string :oauth_callback=http%253A%252F%252Ftwoends.home%252Fbackend&oauth_consumer_key=oauth_consumer_key_wQjQ7u5lgwA&oauth_nonce=46fa649c21ac5315d4d4510ff68ad630&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1381930918&oauth_version=1.0
next i need to create base_string, which will be used to create signature as data param for hash_hmac() function
$base_string = strtoupper($http_method).'&';
$base_string .= rawurlencode($base_url).'&';
$base_string .= rawurlencode($parameter_string);
result:
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%25253A%25252F%25252Ftwoends.home%25252Fbackend%26oauth_consumer_key%3Dapp_cons_keyQjQ7u5lgwA%26oauth_nonce%3D46fa649c21ac5315d4d4510ff68ad630%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1381930918%26oauth_version%3D1.0
next i get consumer_secret from APP settings to create signing key which will be used to create signature as a third param at hash_hmac() function
$oauth_consumer_secret = 'consumer_secret_from_app_settings';
$oauth_signing_key = rawurlencode($oauth_consumer_secret).'&';
one thing to mention: in 1st step (request_token we don't need to put any token)
this step creates signature:
$oauth_signature = base64_encode(hash_hmac('sha1', $base_string, $oauth_signing_key, true));
now we need to add signature to params array and build header string
$params['oauth_signature'] = rawurlencode($oauth_signature);
ksort($params);
building header string can be found at Building the header string
$DST ='OAuth ';
foreach($params as $key=>$value){
$DST .= $key.'='.'"'.$value.'", ';
}
$DST = rtrim($DST,', ');
//or we can make it by hand as below
//$DST .= 'oauth_nonce="'.rawurlencode($oauth_nonce)
// .'", oauth_callback="'.rawurlencode($oauth_callback)
// .'", oauth_signature_method="HMAC-SHA1", oauth_timestamp="'
// .rawurlencode($oauth_timestamp).'", oauth_consumer_key="'
// .rawurlencode($oauth_consumer_key).'", oauth_signature="'
// .rawurlencode($oauth_signature).'", oauth_version="1.0"';
the final step (i hope) is to send a request:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$DST));
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
echo '<pre>';
print_r($info);
echo '</pre>';
this code produces error 400 - bad request
if i remove curl_setopt($ch, CURLOPT_POST, true); i get error - 401
request info dump :
Array
(
[url] => https://api.twitter.com/oauth/request_token
[content_type] =>
[http_code] => 400
[header_size] => 66
[request_size] => 471
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.710993
[namelookup_time] => 0.081279
[connect_time] => 0.23482
[pretransfer_time] => 0.550913
[size_upload] => 0
[size_download] => 0
[speed_download] => 0
[speed_upload] => 0
[download_content_length] => 0
[upload_content_length] => -1
[starttransfer_time] => 0.710976
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => 199.16.156.104
[certinfo] => Array
(
)
[primary_port] => 443
[local_ip] => 192.168.1.234
[local_port] => 54994
[request_header] => POST /oauth/request_token HTTP/1.1
Host: api.twitter.com
Accept: */*
Authorization: OAuth oauth_callback="http%3A%2F%2Ftwoends.home%2Fbackend", oauth_consumer_key="your_consumer_keyCwQjQ7u5lgwA", oauth_nonce="1ba83f0af239f439c1524096c33faefe", oauth_signature="QZZvrJ8wzCQOYhiKJeT4vz%2FWCcg%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1381931941", oauth_version="1.0"
Content-Length: -1
Content-Type: application/x-www-form-urlencoded
Expect: 100-continue
)
hope this will help to understand where to find the error, in advance i'll also try to use Fiddler to trace request
---------------------------------------
solved by using new API

Twitter api 1.1 oauth fails when searching hashtags

I'm using a modified php-script I found on the internet to function as a proxy between javascript and twitter api 1.1 (I need to do this because javascript can't do oauth operations and api 1.1 requires exactly that: authentication).
The script works fine - up until I search for a hashtag, then oauth fails.
Here's an example of the curl_info I get from twitter when searching for #z25org
url: http://api.twitter.com/1.1/search/tweets.json?q=%40z25org
content_type: application/json;charset=utf-8
http_code: 200
As you can see this works (http_code: 200). But when I search for a hashtag:
url: http://api.twitter.com/1.1/search/tweets.json?q=%23z25org
content_type: application/json; charset=utf-8
http_code: 401
I get http_code 401: Unauthorized access. The json:
{"errors":[{"message":"Could not authenticate you","code":32}]}
Here's my php code: (well, the biggest part of it)
<?php
// Some characters that need to be replaced
$specialCharacters = array(
"#"=>"%40",
"#"=>"%23",
" "=>"%20",
""=>""
);
/*
* Ok, no more config should really be needed. Yay!
*/
// We'll get the URL from $_GET[]. Make sure the url is url encoded, for example encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=10&include_rts=false&exclude_replies=true')
if(!isset($_GET['url'])){
die('No URL set');
}
$url = $_GET['url'];
// Figure out the URL parmaters
$url_parts = parse_url($url);
parse_str($url_parts['query'], $url_arguments);
$full_url = $config['base_url'].$url; // Url with the query on it.
$base_url = $config['base_url'].$url_parts['path']; // Url without the query.
if (!dbglog(" > ORIGINAL: ".$full_url)) { die("Huh?"); }
// Replace characters
foreach($specialCharacters as $lookup => $replace) {
$full_url = str_replace($lookup,$replace,$full_url);
}
if (!dbglog(" > REPLACED: ".$full_url)) { die("Huh?"); }
/**
* Code below from http://stackoverflow.com/questions/12916539/simplest-php-example-retrieving-user-timeline-with-twitter-api-version-1-1 by Rivers
* with a few modfications by Mike Rogers to support variables in the URL nicely
*/
function buildBaseString($baseURI, $method, $params) {
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}
function buildAuthorizationHeader($oauth) {
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
// Set up the oauth Authorization array
$oauth = array(
'oauth_consumer_key' => $config['consumer_key'],
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $config['oauth_access_token'],
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
$base_info = buildBaseString($base_url, 'GET', array_merge($oauth, $url_arguments));
$composite_key = rawurlencode($config['consumer_secret']) . '&' . rawurlencode($config['oauth_access_token_secret']);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
// Make Requests
$header = array(
buildAuthorizationHeader($oauth),
'Expect:'
);
$options = array(
CURLOPT_HTTPHEADER => $header,
//CURLOPT_POSTFIELDS => $postfields,
CURLOPT_HEADER => false,
CURLOPT_URL => $full_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false
);
try {
$feed = curl_init();
curl_setopt_array($feed, $options);
$result = curl_exec($feed);
$info = curl_getinfo($feed);
curl_close($feed);
} catch (Exception $e) {
die("Error: ".$e);
}
// Send suitable headers to the end user.
if(isset($info['content_type']) && isset($info['size_download'])){
header('Content-Type: '.$info['content_type']);
header('Content-Length: '.$info['size_download']);
}
echo($result);
?>
I had this same issue when building this library.
This commit specifically might yield some more information.
The issue that you have basically is that you are URL encoding incorrectly - maybe even twice. If you view the code from the source above (it's very similar, seems like it's been modified there), then it'll work exactly as you wanted.
TLDR: Use the above single file instead, or just copy/paste the code out of it. It's pretty much what you want.
As OP found: he also tried replacing it with %2523 (where %25 = %). It's still advisable to check out the above library.

Unable to generate Tumblr API Request Token in PHP

First, a note: My host does not have the PECL OAUTH or HTTP extensions installed.
The purpose of this: I'm hoping to create an interface to easily follow and unfollow a given list of Tumblr names.
Problem: Can't get past the authentication step.
Code:
$request_url = 'http://www.tumblr.com/oauth/request_token';
$consumer_key = COSUMER_KEY;
$consumer_secret = CONSUMER_SECRET;
$oauth_key = urlencode_rfc3986($consumer_secret) . '&';
$time = time();
$nonce = md5(microtime() . mt_rand());
$callback_url = 'http://krisallengallery.com/easyfollowr/index.php';
$params = array('oauth_consumer_key' => $consumer_key,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => $time,
'oauth_nonce' => $nonce,
'oauth_version' => '1.0a',
'oauth_callback' => $callback_url);
uksort($params, 'strcmp');
$oauth_header = 'Authorization: OAuth ';
$raw_signature = 'GET&' . urlencode_rfc3986($request_url) . '&';
$raw_suffix = array();
foreach($params as $key => $param)
{
$raw_suffix[] = $key . '=' . $param;
}
$raw_signature .= urlencode_rfc3986(implode('&', $raw_suffix));
$oauth_signature = urlencode_rfc3986(base64_encode(hash_hmac('sha1', $raw_signature, $oauth_key, true)));
$params['oauth_signature'] = $oauth_signature;
uksort($params, 'strcmp');
$raw_head = array();
foreach($params as $key => $param)
{
$raw_head[] = $key . '="' . $param . '"';
}
$oauth_header .= implode(',', $raw_head);
$session = curl_init($request_url);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($session, CURLOPT_HEADER, true);
curl_setopt($session, CURLOPT_HTTPHEADER, array($oauth_header));
$response = curl_exec($session);
curl_close($session);
echo $response;
function urlencode_rfc3986($input)
{
return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($input)));
}
Any ideas of where I'm going wrong?
ETA: Made some modifications. It's still not working, but the error I'm getting now is oauth_signature does not match expected value
I can't test it so I'll give you a couple of things to try and see if there is any improvement.
'$oauth_timestamp' in your $params array should actually be 'oauth_timestamp' (no $ sign). Also, when generating the query string, you shouldn't be enclosing the values in quotes.
You should change the foreach($params) loop to this instead:
foreach($params as $key => $param)
{
$raw_signature .= $key . '=' . urlencode($param) . '&';
$oauth_header .= $key . '=' . $param . ',';
}
$raw_signature = rtrim($raw_signature, '&');
$oauth_signature = base64_encode(hash_hmac('sha1', $raw_signature, $oauth_key));
$oauth_header .= 'oauth_signature=' . $oauth_signature;
Also, I think you should be using a GET request instead of POST for cURL.
Hope that helps.
I'm not entirely sure what I was doing wrong, but fortunately, I found fangel's OAuth script on GitHub that implements everything I need to generate tokens. It looks like I was on the the right track, though.
ETA: Furthermore, there is jacobbudin's TumblrOAuth library on GitHub, which uses fangel's script and some forked then updated code, that handles all the Tumblr authentication for a user for your application.
I'm sure I'll be back with more questions when I start trying to build my Followr script.
Exclude the 'oauth_callback' => $callback_url from the $params array and its all good. After excluding it server returns a 200 code:
HTTP/1.1 200 OK Server: nginx Date: Fri, 04 Oct 2013 19:52:51 GMT Content-Type: application/x-www-form-urlencoded Transfer-Encoding: chunked Connection: close Set-Cookie: tmgioct=524f1c93c799700263374730; expires=Mon, 02-Oct-2023 19:52:51 GMT; path=/; httponly P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL" oauth_token=smKHczH7Mt1MTGilqERZ28oNjJ4OP31lVtBHYTRAY8BH3f73hc&oauth_token_secret=4AxBTP8YannLZDdvR9IiTJTJIEKXocPJEHHSDd5TKQOrE6kr0N&oauth_callback_confirmed=true

Categories