Amazon Web Services signature error - php

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
$AWS_ACCESS_KEY_ID = "KEY";
$AWS_SECRET_ACCESS_KEY = "ACCESS KEY";
$base_url = "http://webservices.amazon.com/onca/xml?";
$url_params = array('Operation'=>"ItemSearch",'Service'=>"AWSECommerceService",
'AWSAccessKeyId'=>$AWS_ACCESS_KEY_ID,'AssociateTag'=>"associateTag",
'Version'=>"2011-08-01",'Availability'=>"Available",'Condition'=>"All",
'ItemPage'=>"1",'ResponseGroup'=>"Images,ItemAttributes,EditorialReview",
'Keywords'=>"Amazon");
// Add the Timestamp
$url_params['Timestamp'] = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
// Sort the URL parameters
$url_parts = array();
foreach(array_keys($url_params) as $key)
$url_parts[] = $key."=".$url_params[$key];
sort($url_parts);
// Construct the string to sign
$string_to_sign = "GET\webservices.amazon.com\n/onca/xml?\n".implode("&",$url_parts);
$string_to_sign = str_replace('+','%20',$string_to_sign);
$string_to_sign = str_replace(':','%3A',$string_to_sign);
$string_to_sign = str_replace(';',urlencode(';'),$string_to_sign);
// 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 = base64_encode($signature);
$signature = str_replace('+','%2B',$signature);
$signature = str_replace('=','%3D',$signature);
$url_string = implode("&",$url_parts);
$url = $base_url.$url_string."&Signature=".$signature;
print $url;
$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);
$xml_response = curl_exec($ch);
echo $xml_response;
?>
this returns an signature error;
why?
this is the output, keys and tag are replaced for privacy
http://webservices.amazon.com/onca/xml?AWSAccessKeyId=KEY&AssociateTag=ASSIOCATE TAG&Availability=Available&Condition=All&ItemPage=1&Keywords=Amazon&Operation=ItemSearch&ResponseGroup=Images,ItemAttributes,EditorialReview&Service=AWSECommerceService&Timestamp=2012-05-27T09:35:43.000Z&Version=2011-08-01&Signature=KEVlbW6G9ygvHheTf5m0ymguE64LEaYGDtQZQe0bCLQ%3D

Not sure if you still need help with this, but it's most likely failing due not providing a valid associate tag in your call.
'AssociateTag'=>"associateTag"
So you need to change this value to:
'AssociateTag'=>"(my-assigned-associate-tag)"
You MUST use the associate tag given to you by Amazon. I think associate tags usually end with the number '20', but I can't verify that. If you don't know your associate tag, login to your affiliate account here: Amazon affiliate page
...and it will be the 'Signed in as/Tracking ID' value in the upper left hand corner of the page.

signature error is mainly due to the mismatch of access key id and secret key id
please cross verify this ids.
also check the associateTag

Related

Gravity Forms WebAPI (GET Forbidden - PHP)

I'm trying to use the Wordpress Gravity Forms Web API to get entries from a form and simply display them. I have this so far, I have made sure to check my API Key and Private Key are correct, with no luck. No matter what I do, I get a Forbidden response.
Here is my code, is there something I'm doing wrong that you can notice?
<?php
$api_key = 'here';
$private_key = 'here';
$method = 'GET';
$endpoint = 'http://website.co.uk/gravityformsapi/';
//$route = 'entries';
$route = 'forms/1/entries/';
$expires = strtotime('+60 mins');
$string_to_sign = sprintf('%s:%s:%s:%s', $api_key, $method, $route, $expires);
$sig = calculate_signature($string_to_sign, $private_key);
$api_call = $endpoint.$route.'?api_key='.$api_key.'&signature='.$sig.'&expires='.$expires;
$ch = curl_init($api_call);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
print_r($response);
echo $api_call;
function calculate_signature($string, $private_key) {
$hash = hash_hmac("sha1", $string, $private_key, true);
$sig = rawurlencode(base64_encode($hash));
return $sig;
}
?>
Thanks!
The user account in the impersonation settings needs to have the appropriate capability, in this case gravityforms_view_entries. You may need to explicitly assign that capability to the role.
Also, try removing the trailing slash from the route.

Convert PHP Curl To Python

I've been trying to translate some PHP code to Python 3 but can't quite get it to work. In PHP I have the following:
$request = "https://api.example.com/token";
$developerKey = "Basic VVVfdFdfsjkUIHDfdsjYTpMX3JQSDNJKSFQUkxCM0p0WWFpRklh";
$data = array('grant_type'=>'password',
'username'=>'name',
'password'=>'pass',
'scope'=>'2346323');
$cjconn = curl_init($request);
curl_setopt($cjconn, CURLOPT_POST, TRUE);
curl_setopt($cjconn, CURLOPT_HTTPHEADER, array('Authorization: '.$developerKey));
curl_setopt($cjconn, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($cjconn, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($cjconn, CURLOPT_POSTFIELDS,http_build_query($data));
$result = curl_exec($cjconn);
curl_close($cjconn);
$tokens = json_decode($result,true);
$accesstoken = $tokens['access_token'];
echo $accesstoken."\n";
I tried converting it to the following in Python:
import pycurl, json
url = 'https://api.example.com/token'
data = json.dumps({"grant_type":"password",
"username":"name",
"password":"pass",
"scope":"2346323"})
key = 'Basic VVVfdFdfsjkUIHDfdsjYTpMX3JQSDNJKSFQUkxCM0p0WWFpRklh'
c = pycurl.Curl()
c.setopt(pycurl.URL,url)
c.setopt(pycurl.HTTPHEADER,['Authorization: {}'.format(key)])
c.setopt(pycurl.POST,1)
c.setopt(pycurl.POSTFIELDS,data)
c.perform()
But I get the following error:
<faultstring>String index out of range: -1</faultstring>
How can I correct this, or is there a more pythonic solution?
If anyone is interested in the solution, I came up with the following which worked:
def getToken(self):
"""Retrieves the token from provider"""
#The data to be passed to retrieve the token
tokenData = {'grant_type':'password',
'username':TOKENUSERNAME,
'password':TOKENPASSWORD,
'scope':TOKENSCOPE}
#The header parameters
header_params = {'Authorization':KEY}
#Make the request for the token
r = requests.post(TOKENURL,data=tokenData,headers=header_params)
#Check the status code
if r.status_code not in [200,203]:
self.log.logentry("There was an error retrieving the data from Linkshare: {}:{}".format(r.status_code,r.text))
sys.exit()
#Extract the data from the response
data = r.json()
#Parse the access token
token = {'token':data['access_token'],
'type':data['bearer']}
return token

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

How do I use PHP, Twitter API to get more or all of my followers?

I have a twitter api php script successfully spits out the last 100 of my followers
$flwrs_url = "http://api.twitter.com/1/statuses/followers/exampleuser.json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $flwrs_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$curlout = curl_exec($ch);
curl_close($ch);
$response = json_decode($curlout, true);
foreach($response as $friends){
$id = $friends['id'];
$screen_name = $friends['screen_name'];
....
(I used exampleuser instead of my own account)
How do I extend this to include more or all of my followers?
Thank you
According to the Twitter API Documentation for GET followers/ids the request should return up to 5000 followers.
However, if not all followers are returned by the API, there should be a next_cursor element in the response which can be used to retrieve the next batch of followers. You only have to append the value of next_cursor as cursor to the request (see also the API documentation).
Please note that you are using Version 1 of the Twitter API which has been deprecated recently. That is, it will stop working probably early next year. You should upgrade to Version 1.1 as soon as possible. There are new guidelines in place, one of them is that all requests must be authenticated with oAuth.
Thanks for the answer Florian. BTW stumbing around I think I found the correct way to do what I was looking for. Correct me if I'm wrong.
after using the:
$code=$tmhOAuth->request('GET', $tmhOAuth->url('1/followers/ids'),
array('screen_name' => $user, 'cursor' => $cursor));
technique to grab all 5000 followers (user ids). I use the following code to grab batches of 100 (user details) at a time:
$status_url = "http://api.twitter.com/1/users/lookup.json?user_id=";
$lastNum=$last; // $lastNum=100;
$i=$first; // $i=0;
while($i<$lastNum){
if ($i==($lastNum-1)){
$status_url = $status_url . "$followers[$i]";
}else{
$status_url = $status_url . "$followers[$i],";
}
$i++;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $status_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$curlout = curl_exec($ch);
curl_close($ch);
$response = json_decode($curlout, true);
$i = 0;
foreach($response as $friends){
$id = $friends['id'];
$screen_name = $friends['screen_name'];
$name = $friends['name'];
$thumb = $friends['profile_image_url'];
$url = $friends['screen_name'];
$location = $friends['location'];
$description = $friends['description'];
echo "$i) $id $screen_name $name $location $description<br />";
$i++;
}
I realize I need to put "sleep" in between each of these "batches of 100", but I'm not quite sure how much to use.

Interoperable access authorization request for google cloud storage fails with 'signature does not match' error

I'm trying to create a bucket on GCS using API v1.0 (interoperable mode) in PHP but I'm getting a 'signature does not match' error response.
Here's what I'm doing:
$access_id = "GOOGxxxxxx";
$secret_key = "xyxyxyxyx/xyxyxyxyx";
$bucket = "random_bucket_name";
$url = 'https://'.$bucket.'commondatastorage.googleapis.com';
$timestamp = date("r");
$canonicalizedResources = "/ HTTP 1.1";
$stringToSign = utf8_encode("PUT "."\n"."\n"."\n".$canonicalizedResources);
$signature = base64_encode(hash_hmac("sha1",$stringToSign,$secret_key,true));
$authSignature = $access_id.":".$signature;
$headers = array('Host: '.$bucket.'.commondatastorage.googleapis.com',
'Date: '.$timestamp, 'x-goog-api-version: 1',
'x-goog-project-id: xxxyyyxy','Content-Length: 0',
'Authorization: GOOG1 '.$authSignature);
$c = curl_init($url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c,CURLOPT_HTTPHEADER,$headers);
$xml = curl_exec($c);
And here's the response that I get:
<?xml version='1.0' encoding='UTF-8'?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you
provided. Check your Google secret key and signing method.</Message>
<StringToSign>
GET
Sat, 03 Mar 2012 14:56:53 -0800
x-goog-api-version:1
x-goog-project-id:xxxyyyxy
/random_bucket_name/
</StringToSign>
</Error>
Any ideas where I'm going wrong?
Here's Google's documentation on this:
https://developers.google.com/storage/docs/reference-methods#putbucket
One thing I noticed is that even though I specify "PUT" in the "stringToSign" variable ... the response says that I used "GET" ... ?
Any help would be appreciated.
There are a few problems here:
Your canonicalized resource should be "/bucket/", not "/ HTTP 1.1".
You need to include your two custom headers (x-goog-version and x-goog-project-id) in the string to sign.
The string to sign must include the timestamp sent in the Date: header.
You need to set CURLOPT_PUT so that curl knows to send a PUT request, rather than the default GET request (that's why your error response alludes to a GET request).
Here's a corrected version of your code, which I tested and used to create a new bucket:
<?php
$access_id = "REDACTED";
$secret_key = "REDACTED";
$bucket = "your-bucket";
$url = 'https://'.$bucket.'commondatastorage.googleapis.com';
$timestamp = date("r");
$version_header = "x-goog-api-version:1";
$project_header = "x-goog-project-id:REDACTED";
$canonicalizedResources = "/".$bucket."/";
$stringToSign = utf8_encode("PUT\n\n\n".$timestamp."\n".$version_header."\n".$project_header."\n".$canonicalizedResources);
$signature = base64_encode(hash_hmac("sha1",$stringToSign,$secret_key,true));
$authSignature = $access_id.":".$signature;
$headers = array('Host: '.$bucket.'.commondatastorage.googleapis.com',
'Date: '.$timestamp, $version_header,
$project_header,'Content-Length: 0',
'Authorization: GOOG1 '.$authSignature);
$c = curl_init($url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c,CURLOPT_HTTPHEADER,$headers);
curl_setopt($c, CURLOPT_PUT, TRUE);
$xml = curl_exec($c);
print($xml);
?>
P.S. All the details on HMAC authentication for Google Cloud Storage are provided here: https://developers.google.com/storage/docs/reference/v1/developer-guidev1#authentication

Categories