Sign Amazon Product Advertising API REST Requests with PHP and Python
published: 08 May 2009, last updated: 29 Dec 2012
The Amazon® Product Advertising API (formerly know as Amazon Associates Webservices) can be used to access Amazon's product data for advertising purposes. By August 15, 2009, all calls to the API must be signed (with HMAC and SHA-256) to authenticate the request. I have written a PHP and a Python function which build authenticated requests.
Since its publication, soon after the announcement from Amazon, the PHP script has been successfully used in production by dozens of websites (including my own). Most other scripts that you will find on the internet are probably based on this one.
Download the Code
If you use this script, a link back to this website would be appreciated but is not required.
- PHP Function 2.0 (1.5 kB)
It uses hash_hmac and requires PHP 5 >= 5.1.2 See below for a hash_hmac implementation for older versions of PHP.
- Python Function 1.0 (1.5 kB)
Has been tested with Python 2.5 and 2.6 (but should work with newer versions, too) and has been tested on Google App Engine.
Older Versions
- PHP Function 1.0 (1.6 kB)
It uses hash_hmac and requires PHP 5 >= 5.1.2 See below for a hash_hmac implementation for older versions of PHP.
Other Downloads
- hash_hmac for PHP 4 (0.6 kB)
Implements the hash_hmac function for PHP 4 and PHP 5 < 5.1.2 This uses the free SHA-256 library for PHP 4
- SHA256 for PHP 4 (4.9 kB)
Implements the sha256 function for older PHP versions. This is an unmodified version that was downloaded from nanolink.ca.
PHP Documentation
Description
The function signs your request and returns a URL.
aws_signed_request($region, $params, $public_key, $private_key, $associate_tag=NULL, $version='2011-08-01')
Parameters
- $region
Amazon region (
"ca","com","co.uk","de","fr"or"co.jp")- $params
An associative array of parameters with the parameter names as keys.
- $public_key
Your public key.
- $private_key
Your private key.
- $associate_tag
Optional Associate Tag. If
NULL, you have to add your AssociateTag to the$paramsarray.- $version
Optional API version.
Return Values
Returns the signed URL as a string.
Example
Here is a simple example. You have to replace $public_key, $private_key and $associate_tag with your own values.
<?php
include('aws_signed_request.php');
$public_key = '********';
$private_key = '********';
$associate_tag = '********';
// generate signed URL
$request = aws_signed_request('com', array(
'Operation' => 'ItemLookup',
'ItemId' => 'B008GG93YE',
'ResponseGroup' => 'Small'), $public_key, $private_key, $associate_tag);
// do request (you could also use curl etc.)
$response = @file_get_contents($request);
if ($response === FALSE) {
echo "Request failed.\n";
} else {
// parse XML
$pxml = simplexml_load_string($response);
if ($pxml === FALSE) {
echo "Response could not be parsed.\n";
} else {
if (isset($pxml->Items->Item->ItemAttributes->Title)) {
echo $pxml->Items->Item->ItemAttributes->Title, "\n";
}
}
}
?>
The output of this script should be:
Kindle, 6" E Ink Display, Wi-Fi
Python Documentation
Description
The function signs your request and returns a URL.
aws_signed_request(region, params, public_key, private_key, associate_tag=None, version='2011-08-01')
Parameters
- region
Amazon region (
"ca","com","co.uk","de","fr"or"co.jp")- params
A dictionary of parameters with the parameter names as keys.
- public_key
Your public key.
- private_key
Your private key.
- associate_tag
Optional Associate Tag. If
None, you have to add your AssociateTag to theparamsdict.- version
Optional API version.
Return Values
Returns the signed URL as a string.
Example
Here is a simple example. You have to replace public_key, private_key and associate_tag with your own values.
#!/usr/bin/python
from aws_signed_request import aws_signed_request
import urllib
from xml.dom import minidom
public_key = '********'
private_key = '********'
associate_tag = '********';
# generate signed URL
request = aws_signed_request('com', {
'Operation': 'ItemLookup',
'ItemId': 'B008GG93YE',
'ResponseGroup': 'Small'}, public_key, private_key, associate_tag)
# do request
try:
response_obj = urllib.urlopen(request);
except IOError:
print "Request failed."
else:
response = response_obj.read()
pxml = minidom.parseString(response)
items = pxml.getElementsByTagName('Title')
print items[0].firstChild.nodeValue
The output of this script should be:
Kindle, 6" E Ink Display, Wi-Fi
Questions?
If you have questions regarding these scripts or if you need help with specific problems, do not hesitate to contact me.
Comments (207)
Comments are temporarily closed. Please contact me if your question is not answered.
thank your for your script....it's very help to work with SHA algorithm
ENOXRH , my script is not working , do you plz share with me your script
Thanks, saved me some time typing (used most of it)! Note, per the docs, the host should be:
webservices.amazon.com
Yes, in the documentation they are using webservices.amazon.com, but in the AWS forums, people say ecs.amazonaws is better. But both will work...
Wrong information! ecs.amazonaws does not work with "co.jp", but webservices.amazon does. So the latter is better...
why is str_replace("%7E", "~", rawurlencode($s)) required instead of urlencode($s)?
Amazon requires that you encode the parameters as specified in <a href="http://www.ietf.org/rfc/rfc3986.txt" target="_blank">RFC 3986</a>. The space character, for example, has to be encoded as "%20" and not as "+" like urlencode() does. In addition, the following characters are reserved and may not be encoded: "-", ".", "_" and "~". rawurlencode() encodes "~" as "%7E" so we have to replace it.
Hello,
i am testing the signature function on a Server with PHP 4.0. The hash_hmac function is required > PHP 5.1. What is the function for PHP < 5.1?
If you have access to the mhash function you could use it: <a href="http://www.php.net/manual/en/function.mhash.php" target="_blank">http://www.php.net/manual/en/function.mhash.php</a>
If not, you have to build your own hmac function. On the website I have mentioned above, someone submitted a hmac function for md5. You could modify that by replacing the md5 function with a sha256 function (for example this one: <a href="http://www.nanolink.ca/pub/sha256/)" target="_blank">http://www.nanolink.ca/pub/sha256/)</a> and by enclosing the return value with pack("H*", ...).
Hello,
thanks for your info. Is this the only way to do that in PHP 4??
Yes, I think it is the only way. But creating the hmac function as described is not very complicated:
<?php
// please use the sha256 from: <a href="http://www.nanolink.ca/pub/sha256/" target="_blank">http://www.nanolink.ca/pub/sha256/</a>
include("sha256.inc.php");
function hash_hmac($algo, $data, $key, $raw_output=False)
{
// RFC 2104 HMAC implementation for php.
// Creates a sha256 HMAC.
// Eliminates the need to install mhash to compute a HMAC
// Hacked by Lance Rushing
// source: <a href="http://www.php.net/manual/en/function.mhash.php" target="_blank">http://www.php.net/manual/en/function.mhash.php</a>
// modified by Ulrich Mierendorff to work with sha256 and raw output
$b = 64; // block size of md5, sha256 and other hash functions
if (strlen($key) > $b) {
$key = pack("H*",$algo($key));
}
$key = str_pad($key, $b, chr(0x00));
$ipad = str_pad('', $b, chr(0x36));
$opad = str_pad('', $b, chr(0x5c));
$k_ipad = $key ^ $ipad ;
$k_opad = $key ^ $opad;
$hmac = $algo($k_opad . pack("H*", $algo($k_ipad . $data)));
if ($raw_output)
{
return pack("H*", $hmac);
}
else
{
return $hmac;
}
}
?>
This script should work with PHP 4.
Hello,
thanks a lot, it works wonderful.......
Vanessa
thanks for the script, i could not have done it without you !
vielen dank... hat mir sehr viel arbeit erspart ;)
Thanks so much! you got me over the hump.
I think Amazon is making a big mistake requiring this. I think it is a little too complex, and doesn't this slow down requests when you start hashing values?
This new signing of requests destroys certain application concepts, but I can understand why they implemented such a system. It also prevents misuse of their service.
And I do not think that it significantly slows down requests, because hashing does not take that long. Calling the base64-encoded hash_hmac function in PHP 100 times takes around 0.002 seconds.
As long as amazon is still limiting the API request rate to 1 request per second per IP, then hashing overhead is moot -- the far greater bottleneck is said rate limit.
Honestly, my framework does a chain of requests for some pages without caching any results. Furthermore, I have a dozen sites using the same framework on the same VPS and I have yet to see a limit applied. I believe this is more of a recommendation than an enforced limit. ;-)
The rule is sometimes relaxed a bit and bursts may be allowed, but as soon as you get 503 errors you know that you are doing too many requests...
did not work for me
Please provide some more information. Which PHP version are you using? What happens if you run the example (error codes)?
it doesn't work with Keyword search when the keyword is a phrase with spaces in it. Any idea to modify it?
Do you have an example? Something like
$pxml = aws_signed_request("com", array("Operation"=>"ItemSearch",
"SearchIndex"=>"Books",
"Keywords"=>"Harry Potter"), $public_key, $private_key);
print_r($pxml);
works for me.
Hi,
thank you all for your help. I got your code to work under PHP with the usage of the alternat SHA256 code and a different XML parser.
I've uploaded my test code, if anyone else has trouble to get it to work under PHP4.
<a href="http://doena-soft.de/signed_php_requests_sample/signed_php_requests_sample.zip" target="_blank">http://doena-soft.de/signed_php_requests_sample/s...</a>
Hi,
using PHP 4.4.9 the sha256.inc.php class results in high load and dies with a fatal error on line 94:
Fatal error: Maximum execution time of 60 seconds exceeded in /srv/www/htdocs/test/auth/sha256.inc.php on line 94.
Any ideas what could produce this loop (even with the original sample file) ?
Thanks a lot in advance !
Exactly the same problem here on the same version of PHP.
Any headway with this would be great.
Am in over my head with this.
ditto. this pegs my cpu on php 4.4.9.
Thank you for this script, but there is one problem more than hash_hmac function if the server have php <5
simplexml_load_string() is also php5 :(
Hmm.. I did not know that. But you could try another XML parser. Someone posted a PHP 4 example in the comment above.
you ruck. THis helps a lot.
Very cool script. I was trying to get it to work and was having trouble understanding how they want it to work. Your script saved me. Thank you!!!
After reading Amazon's new requirements and looking at the C++, Java and Perl examples, I was envisioning a major project with lots of coding and test time. Your code is simple, understandable and works flawlessly.
Thank you!
thank you sir. very helpful, saved me an hour or so by being able to drop in this method instead of rewriting my existing loader. good job with taking the array() full of the api params - that's what let me drop this right in.
Just A note Here do we pass the $assoctag any more ?
Just add this as a parameter to the $params array.
Im using this with PHP5, and getting this error "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
I tried cross-check my public/private keys in the amazon product api website but its already correct.
Im using PHP5 on hostmonster.
Could you post an example script that does not work?
Try obtaining a new signature from Amazon Services.
BTW, thanks a lot to ULRICH, it worked beautifully, flawless, and couldn't find a better way to use some of the most obscure PHP instructions you utilise so efficiently here.
Oscar
Great work!!
I could finally do it with your help. Thanks. : )
great func... 10x alot!!!!!
Thanks so much! Really great script.
thank you so much, lets make profit togather
I tried out your script and it works, but it seems to return fewer results than when I used the unsigned requests. Here's an example that's getting fewer results.
example search index: HomeGarden
example keyword: newmans own dog food
UNSIGNED VERSION (finds 46 results):
$request = 'http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId='.$amazon_api.'&Operation=ItemSearch&'.'SearchIndex='.$amazon_index.'&Keywords='.$keywords.'&ItemPage='.$ItemPage.'&MinimumPrice=1&ResponseGroup=Medium,OfferSummary,Offers,VariationSummary';
$response = file_get_contents($request);
$parsed_xml = simplexml_load_string($response);
SIGNED VERSION (returns no results):
$parsed_xml = aws_signed_request($amazon_region, array("Operation"=>"ItemSearch","SearchIndex"=>$amazon_index,"Keywords"=>$keywords,"ItemPage"=>$ItemPage,"MinimumPrice"=>1,"ResponseGroup"=>"Medium,OfferSummary,Offers,VariationSummary"), $amazon_api, $amazon_secret_key);
I am using your function unchanged. Any suggestions on how to fix this?
The signed version of it isn't displaying as I copied and pasted it, so I'll put it on separate lines so it's more readable:
$parsed_xml = aws_signed_request($amazon_region,
array("Operation"=>"ItemSearch",
"SearchIndex"=>$amazon_index,
"Keywords"=>$keywords,
"ItemPage"=>$ItemPage,
"MinimumPrice"=>1,
"ResponseGroup"=>"Medium,OfferSummary,Offers,VariationSummary"),
$amazon_api,
$amazon_secret_key);
I've tried your request with $keywords="newmans own dog food"; $ItemPage=; $amazon_index="HomeGarden". It worked and returned 46 results. Maybe there is something wrong with your code.
I figured it out. A few lines before the call, the script was changing spaces in the keyword to %20. That change is not necessary with your code, so I removed it.
Thanks for taking the time to respond and for creating this script!
I to am getting blank results using this, regardless what keywords or which category.
Getting closer to D day... hope everyone else is able to sort it out :(
Hmm.. Please post a complete example so that we can figure it out.
I was having the same problem as well. Nothing was showing, but the response had data. Then I realized that the ItemSearch operation no longer was returning the OfferListingId once I commented out my line that was checking to see if there was an offer berfore displaing it started showing my items.
if(isset($current->Offers->Offer->OfferListing->OfferListingId)){ //only show items for which there is an offer
Had to change quit a bit of code since it appears th esigned version of ItemSearch does not return the OfferListingId and just about anything under Offers->Offer I have not looked to closely but it just appears all this data is no longer returned.
I hope this helps.
I made a SOAP version of the function:
<a href="http://insidethings.blogspot.com/2009/07/today-i-decided-to-update-my-aws-amazon.html" target="_blank">http://insidethings.blogspot.com/2009/07/today-i-...</a>
Doesn't work for me.
Thank you very much! Yes, this saved me hours...
Thanks a lot for this very precious function.
It works most times for me; however I've got trouble with param names that include a dot '.' like when you do batch requests (see <a href="http://docs.amazonwebservices.com/AWSECommerceService/2009-07-01/DG/BatchRequests.html)" target="_blank">http://docs.amazonwebservices.com/AWSECommerceSer...</a> or multiple operations requests (see <a href="http://docs.amazonwebservices.com/AWSECommerceService/2009-07-01/DG/MultipleOperationRequests.html)." target="_blank">http://docs.amazonwebservices.com/AWSECommerceSer...</a> Your PHP encodes the dots as '_' before signing the request, which it should probably not.
In the "create the canonicalized query" section, if you replace the line "$param = str_replace("%7E", "~", rawurlencode($param));" with "$param = str_replace("%7E", "~", $param);" then it works with parameters containing dots, though it may be less future-proof (in case Amazon eventually uses other reserved characters in param names).
Thanks again!
For me, batch requests are working and (rawurlencode(".") === ".") evaluates to true. Are you sure that there is no error in your code?
You're right, I was misled by PHP considering '_'s instead of '.'s ;)
You can ignore and even delete my comment, except for "thanks a lot for this very precious function"!
My requests were formatted differently than yours. Thanks so much for the ideas - here's what I ended up with for PHP - works very well!
<a href="http://www.everygoodpath.net/PHP-sample-Amazon-request-sign-authenticate" target="_blank">http://www.everygoodpath.net/PHP-sample-Amazon-re...</a>
I linked back to you in my solution, as your method is very helpful
Thanks a lot. I modified all my itemsearch request with your script(s) and find the same results as before. :)
Thank you very much! I'm finding this tutorial.
"und wenn du glaubst es geht nicht mehr, kommt von irgendwo ein skript noch her"
Vielen Dank, du hast mich vor dem Sprung aus dem Fenster bewahrt...
Thank you for the code, it worked great and saved me a lot of headaches :)
Nice function. It helped me in development of my own class. Thank you.
thank you so muchB)
Wow, what an amazing little script... this is really amazing and adapted in no time to replace part of my existing script (using my existing XML parser).
Would definitely recommend this script to others!
I have received an error stating that my signature did not match that of Amazon's. I double checked my keys and I am 100% sure they are correct.
Here is my request string which looks good as well. Does any have a clue as to what the issue might be?
<a href="http://ecs.amazonaws.com/onca/xml?" target="_blank">http://ecs.amazonaws.com/onca/xml?</a>
AWSAccessKeyId=MYACCESSID&
ItemPage=1&
Keywords=canon&
MerchantId=All&
Operation=ItemSearch&
ResponseGroup=OfferListings%2CMedium%2COffers%2CReviews&
SearchIndex=All&
Service=AWSECommerceService&
Timestamp=2009-08-05T05%3A03%3A06Z&
Version=2009-06-01&
Signature=MYSIGNATURE
Are you using the exactly the same aws_signed_request function or have you modified parts of it?
If not, it could be possible that your keys are the problem. I've heard that if you signed up for AWS years ago, that the keys may not work with the authentication and that you have to apply for a new pair. But I am not sure if this could be the problem.
You were right! I regenerated my keys and it just worked. Very weird but it is definitely an issue on Amazon's part. Thank you very much for your code and support.
Did you only have to regenerate your secret key, or did you somehow also regenerate your regular access key? the reason I ask is because it's easy to change your own secret key, but not the access key. Also, after pouring over this page over and over again and also regenerating my own secret key, it did not seem to work :(
Fantastic!
Thanks, you saved me some time figuring out, why my signatures weren't valid. The str_replace did the trick.
Still waiting for the universal multi language url_encode function, which would work the same on every system and client.
Thank you so much. I feel that Amazon made this far too complicated and provided poor documentation. Venting over.
I used your script with a very slight modification. Prior to the signed request, my script started like this:
$xml = simplexml_load_file("http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&SubscriptionId=xxxxxxxx&Operation=ItemSearch&SearchIndex=DVD&Keywords=B001MVWFAE&ResponseGroup=Images,Tracks,ItemAttributes,EditorialReview");
Now my script starts like this:
include "aws_signed.php";
$myParams = array("Operation"=>"ItemSearch","SearchIndex"=>"DVD","Keywords"=>"B001MVWFAE", "ResponseGroup"=>"Images,Tracks,ItemAttributes,EditorialReview");
$xml = aws_signed_request("com",$myParams,"ACCESS_KEY","SECRET_KEY");
and with that change to my script, I modified the end of your function from the $request var on down :
// create request
$request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature;
// parse XML
$pxml = simplexml_load_file($request);
if ($pxml === False) {
return False; // no xml
}
else {
return $pxml;
}
Works perfectly. Thanks.
Thanks!
Getting close to the deadline and this definitely saved me some time and headaches!
hi
I'll second "Don H." - "Amazon made this far too complicated and provided poor documentation." Generally finding ANYTHING in the Amazon documentation is a pain in the arse!
Thank you for you excellent function - works fine for me, will see after the 15th. Your post saved me hours of development time!
Thank a lot!
Thank You. Worked like a charm!
i am geting the following error. anyone can help me out??
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
thanks
I am using a php toolkit called asm4. i wonder how to integrate this into my toolkit. thanks
I think you have to go through the code and replace all your old Amazon requests with this new function.
it work for me. it is very usefull. thank you ,thank you ,thank you
THANK YOU! YOU ARE A GOD!
Thank you. Thank you. Thank you. Works great! You are a lifesaver!
I see I should pay more attention to the aws newsletter. i only realized that the old logic with the SubscriptionId will no longer work when it no longer worked.... I saw me studying the amazon documentation and PHP coding all night long - and then I found your script which made it all a whole lot easier. Thank You :)
Thanks for the script !!! Helped so much !
Question after making the changes to he donwloaded file do i need to upload t my server and under which name .
thanks
Hi Ulrich,
thought I'd let you know- your function has just made it into videoDB (<a href="http://videodb.net)." target="_blank">http://videodb.net).</a>
Best regards,
Andreas
Cool, this project looks interesting.
Your function saved quite a lot of my time when a huge application broke that solely relies upon AWS. Thanks a LOT. I owe you a glass of beer. You accept donations?
Hi, Thanks for your comment. My PayPal address is u.mierendorff@googlemail.com :)
Hi Ulrich,
Do you also have an Associate ID?
Being able to random rotation it, so you get some scratch would be nice! Please add it to your about page, we who care will share the love.
Best Regards,
Sam
Hi,
ID rotation is a good idea, but I am not sure, whether it is allowed by Amazon to use the ID on websites that you don't own.
I think Associate IDs have to be allowed on other domains, as one of the "Amazon Web Services Developer Advisory Council" flogs this:
<a href="http://www.associate-o-matic.com/comparison.html" target="_blank">http://www.associate-o-matic.com/comparison.html</a>
Were the 'free' version captures 10% of revenues for themselves.
And not sure of the legalities, but if you're truly paranoid, get a new Associate ID for some other domain than your main one and release that?
I have to think that you'll end up with much more revenue that way than just the random paypal donation.
my 2 cents,
Sam
Thanks a lot!
You save my day. I ignored all the mails amazon was sending the last weeks, because I knew, that the amazon api is really complex . But since 2 weeks unsigned requests do not work anymore and I was totally frustrated with the poor examples on the aws homepage, especially in PHP. I found your script and after one hour all requests are working again, thx a lot :)
Thank you - Trying to add Amazon's prices to our site and this is going to help immensely!
Thank you so much, I had wasted 1 day for this functionality and still had no solution. Thank you so much
Thank you very much.
I want to know how to implement PHP function to be synchronized in order to delay to call AWS after previous calling for one second?
I did this by storing a timestamp in shared memory for every request. To determine how long I have to wait until I can make a new request I calculate the difference between the timestamp in shared memory and and the current time. If you have more than one PHP instance running, you have to use semaphores or similar technology to ensure atomicity of all operations.
please help me my store shows the following and not product comes up..
----------------------------------------------------------------------------------------------------------
Warning: file_get_contents(<a href="http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=hgf45QD0k6M1o9Sk0V92&Operation=ItemSearch&SearchIndex=Books&Keywords=books,%20text%20books&ItemPage=1&MinimumPrice=1&ResponseGroup=Medium,OfferSummary,Offers,VariationSummary)" target="_blank">http://ecs.amazonaws.com/onca/xml?Service=AWSECom...</a> [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /home2/rpc/public_html/bos/index.php on line 41
Found Books, Text Books Products.
Warning: Invalid argument supplied for foreach() in /home2/rpc/public_html/bos/index.php on line 62
Have you tried to catch the error (with @) and redo the request if it fails?
Dude, you kick ass. This is the sweetest bit of code I've seen that works, the others want an arm and a leg for this code you've so graciously posted. May karma reward you.
works great!!!!!!!!!
5 * from my side
great job posting this. Amazon is such a worthless company when it comes to affiliates. I just use their site for the content images and text :) They pissed me off enough I even use their info to send visitors to a competitor affiliate link
This PHP code works perfectly. It would have taken me great effort and lots of time to figure out out to program this myself. You saved me lots of time. It slipped into my application with ease. Thank you!
Puzzle. Using PHP 5.2.... Function works fine to provide signed $request. I know because if in the php script I use echo $request to see it, then cut-and-paste as a URL into browser, I get a display of all the xml info from Amazon. The view source shows <?xml version="1.0" ?><ItemLookupResponse xmlns= ...[lots of info].... </ItemLookupResponse>
However, continuing in the php script , I get $pxml coming out as false.... even though I expect there is content in $request. Thus
$pxml = file_get_contents($request);
var_dump($pxml);
result is bool(false)
so I have nothing for the script to continue processing.
So why always false?
Maybe there is something wrong with your php configuration. Are you able to load other websites with file_get_contents?
Ah... Fixed! Thanks.
Thanks for pointing me in the right direction. Googling I found that
In php.ini I had to change
allow_url_fopen = On
or
allow_url_fopen = 1
I had thought I was using this function successfully previously, but in fact, my working application used an "include" from local host. and not file_get_contents. So when the Amazon script was needing a remote file, I had never needed file_get_contents before.
Good to know that everything is now working. :) And thank you for posting the fix, because other users may have similar problems.
Using base64-encoding on a secure hash like sha256 is useless, you only end up with a larger string that really is not safer in any way. Just a thought for improvement ;)
This is correct if you base64-encode the hex representation of the hash value. The base64-encoded binary representation of the hash value (which we are using here) is approx. 31% smaller.
Thank you soooo much, you saved my day after some good +2 hours
Thank you! I was using some code I'd found on Amazon before and I could not get it to work. This code worked a charm.
Thank you very much, This is the one that i looking for after amazon changed them rule.
Thanks, runs very fine with 1 Product.
How can i change that code, that i get more than one result?
Thanks Peter.
You have to use the appropriate parameters. You can find more info here: <a href="http:\/\/docs.amazonwebservices.com\/AWSECommerceService\/latest\/DG\/" target="_blank"><a href="http://docs.amazonwebservices.com/AWSECommerceSer...</a>" target="_blank">http://docs.amazonwebservices.com/AWSECommerceSer...</a></a>
Thank you!!! I tried a whole bunch of different scripts and code samples and this is the first and only thing that worked for me!!! Thanks a million!
Thanks! My site went down because this and your code is going to help me get it back up quickly! Good show!
Frank Z (I'd sign on but Google OpenID isn't supported...)
Thats awesome, great script. I did hell lot of digging in amzon to find a right script for php. It resolved my issue in seconds.
Thanks a lot to the author of script. Its quite simple and efficient.
you really rock.
Priya
Great function good work.
It's worth noting that the params have to be sorted in byte order before a valid key will be generated.
i.e not alphabetical, low case letters come before upper case.
You examples work because the param order is correct at entry but for more complex queries a sort function should be added.
Please look at the code, line 50. This should work...
My Bad! Sorry, I'm not sure how I missed that :)
Thanks a lot but I can't run this script it say "Did not work.".
Sorry for not replying earlier. The system filtered your comment as spam, and I haven't noticed it.
To answer your question: This could happen, if the request wasn't correct, for example if you forgot to replace the $public_key and $private_key variables.
Thaaaaaaaaaaaaaaaaaaaaaaank you. I was working on this for 3 days now. The documentation was not clear enough. None of the code workes but your finally is working every time. Thank you so much
1 word: thanks
Thank you! I search many times to find such a good example!
Help me Please ............ If in use XAMPP and magento version 1.4 . What 's did I do ? If I want to use Product Advertising API from amazon but I don't know . Where is put this code in magento because I not programmer . Please Hepme Please.
Sorry, I cannot help you with this. You may want to ask this question in a forum related to magento or you need to learn PHP.
Thanks for the script!!!
How can I know all request type and how to query like below astore?
<a href="http://astore.amazon.com/rockwell-sonicraft-20" target="_blank">rockwell</a>
The documentation ( <a href="http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/" target="_blank">http://docs.amazonwebservices.com/AWSECommerceSer...</a> ) contains most of the information you need to build your requests.
used your example above and it returns only one result for me no matter what i put as search string
$pxml = aws_signed_request("com", array("Operation"=>"ItemSearch","SearchIndex"=>"Electronics","Keywords"=>"xbox","AssociateTag"=>"xxxxxx"),
$public_key, $private_key);
f ($pxml === False)
{
echo "Did not work.
";
}
else
{
if (isset($pxml->Items->Item->ItemAttributes->Title))
{
echo $pxml->Items->Item->ItemAttributes->Title, "
";
}
else
{
echo "Could not find item.
";
}
}
?
This is not suprising, because the example code only echos one title. You will need to use something like this:
if (isset($pxml->Items->Item))
{
foreach ($pxml->Items->Item as $item)
{
if (isset($item->ItemAttributes->Title))
{
echo $item->ItemAttributes->Title, "<br />\\n";
}
}
}
Additionally, you can use print_r($pxml) to see the complete structure of the object and you can find useful information in the SimpleXML documentation, too.
$method = "GET";
$host = "ecs.amazonaws.com";
$uri = "/onca/xml";
$params["Operation"] = "ItemSearch";
$params["SearchIndex"] = $SearchIndex;
$params["Keywords"] = $Keywords;
$params["ResponseGroup"] = "Medium,Offers";;
$params["Service"] = "AWSECommerceService";
$params["AWSAccessKeyId"] = $KEYID;
$params["Timestamp"] = gmdate("Y-m-dTH:i:s");
$params["Version"] = "2009-03-31";
ksort($params);
$canonicalized_query = array();
foreach ($params as $param=>$value)
{
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param."=".$value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$string_to_sign = $method."
".$host."
".$uri."
".$canonicalized_query;
// calculate HMAC with SHA256 and base64-encoding
$signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));
// encode the signature for the request
$signature = str_replace("%7E", "~", rawurlencode($signature));
echo $request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature;
This is my code for SearchItem operation but its giving me error "not a valid value for Signature. Please change this value and retry your request".
I tried every way but unable to fix it.Can anyone plz help what im doing wrong.Thanks.
Are you using your correct <i>private</i> key?
I have found problem
" Fatal error: Cannot redeclare hash_hmac() in /home1/ctwosevo/public_html/subdomain/samsungc3050/aws_signed_request.php on line 42 "
What should i do?
Line 42 of the original aws_signed_request.php does not contain anything called "hash_hmac" (this is used later in the code), so I guess you are using a modified version of the script. If you post this script and your PHP version, we could possibly find a solution.
Thanks a lot for thsi vey usefull script !
Thanks for this very useful script! Awesome!
Very nice piece of codes, hey, do you have any script that searched Amazon for "No of results " returned against each Keywords? i Want to knwo the stock avaliablity for eachkeyword in my list.
Any thoughts?
Sorry for the late reply. If you make an API request, Amazon will return the total number of results. You could just check if it is 0. There are also some other parameters that can be used to return available products only.
Works like a charm! :-) Thanks for writing..
Thank you for the code
There is a catch. When using PHP, you must use rawurlencode() rather than urlencode(). Otherwise, Amazon won't recognize the spaces.
It great and very helpful for mu.
so much thanks.
Thanks for the script. It works very fine ;) Ive just really sad about the signature and the horrible documentation from amazon... But your Script makes me happy :)
Thanks for the script! Not much example on PHP were available from Amazon... Been scratching my head with the Signature part :S
Guess I still got a lot to learn in PHP...
Thanks for the great Script - you get me going with it.
One thing happens to me since last week thends me to think that something has changed, maybe on amazon side. This should not depend on my changes as also happens with my first saved version. Also Google is full with the error crawling for aws_signed_request.php:3,
Fatal error: Cannot redeclare aws_signed_request() (previously declared in aws_signed_request.php:3) in aws_signed_request.php on line 102
Best regards, xcomm
Ok, as found here:
<a href="http://www.digimantra.com/technology/php/avoid-fatal-error-redeclare-function-php/" target="_blank">http://www.digimantra.com/technology/php/avoid-fa...</a>
I enclosed the aws_signed_request() function in aws_signed_request.php with e check and it works fine again.
if(!function_exists('aws_signed_request'))
{
function aws_signed_request($region, $params, $public_key, $private_key)
{
...
}
}
Best regards, xcomm
nice, take a look at my script if something is not working here: <a href="http://www.fairtec.at/it-blog-mainmenu-16" target="_blank">http://www.fairtec.at/it-blog-mainmenu-16</a>
Thanks a lot for your code !
This was a lifesaver.
Dustin do you tell me that how do you implement this fucntion in your request
Thanks for sharing this!
Hi , this is nice api , but my problem is that i could not generate the right signatures so plz help me and brielfy tell me how to generate the exact signature with the parameters.
Great! Thanks! Works!
thanks a lot ! you should be proud by yourself for sharing this as it helps a lot !
I get all the data I need, thak You. I like that script.
Is there anyone who could show me an example for making an affiliate-link to amazon; so that I get payed from amazon, if someone is buying anything. I can not find any information about the link syntax. Or is it just enough to do this:
echo "<a href='" . $pxml->Items->Item->DetailPageURL ."'>Buy me!</a>";
Using the URLs that are returned from the API is recommended, but make sure that you add your AssociateTag to the API-requests.
You can also build the links yourself. They have the following format: amazon.{com|ca|co.uk|fr|co.jp|de|it}/dp/{ASIN}?tag={Your Associate ID}
awesome! It works! It fixed my signature issue.
Thank you a thousand times! You saved me approx. 345.390.109.234.888 hours or programming!
Amazon documentation is INFURIATING, this saved me a whole lot of time.
Thanks for a great help... It really worked a lot for me
Please.. say how to get a product's attributes.. because i'm trying to make a table for difference between product X and Y..
so pls give code for that..
ex: consider two brand tv (samsung & Onida)
attributes i want like size, color, special feature...
Pls help.. advance thanks..!
The official documentation contains information on ResponseGroups. You have to chose the correct ResponseGroup(s) and then you will be able to extract these attributes. It also helps to look at the response to see how it is structured.
Save a lot of my time. Thx you sire!
I didnt get the exact price of the product, i mean the price that set in our price section. How can i get that ?
It could be possible that the information that the API returns is outdated. You should also make sure that you extract the correct offer from the API response. The official documentation contains information about that.
It could be possible that the data from the API is slightly outdated. You should also make sure that you extract the correct offer from the response. The official documentation explains that in detail.
It's working perfectly, thanks.
You can even lookup via ISBN-13 with this query
$pxml = aws_signed_request("com", array("Operation"=>"ItemLookup","IdType"=>"ISBN","ItemId"=> $your_ISBN,"ResponseGroup"=>"Images,ItemAttributes","SearchIndex"=>"Books"), $public_key, $private_key);
Hey,
first of all: great thing!
But it doesn't work for me and it doesn't display any error message. There's just happening nothing! I figured around by adding echos somewhere in the code and found out that after
// calculate HMAC with SHA256 and base64-encoding
$signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));
nothing happens. The script seems stopped, but it's not loading and there is no error message. (There's also nothing displayed when I switch error_reporting to e_all...
Really would like to use this!
If you have any suggestions...
Thanks in advance
liskel
Hey,
I just got it :) My Server didn't support encryption... Don't ask why... On my local machine it's working fine! Thank you very much!
Man. you're the best. thanks for this script, it saved my life...
Thanks again
Hi, this worked for me... but now I can't make it work with amazon.it (italian site), any idea? Does it need to be update somehow? Thanks!
Please replace "ecs.amazonaws.".$region with "webservices.amazon.".$region. $region should be "it" in your case. I will update the script soon.
Does this work for you?
This works perfectly!!
Is there any need to cache the results? Or is it fine as is?
Yes, you should cache the response, because the number of allowed requests per hour is limited. Make sure to read the Product Advertising API License Agreement, it tells you how long you are allowed to cache the data.
Hello. Tried to use but error "Es gab einen Fehler bei der Abfrage. " comes along.
Is there a possibility to get the exact error ? $pxml->Errors or something ?
By the way: How do I have to include the private/public keys ?
In the files I got from amazon, the looked like this:
---- Start
dwfhlsdjkhlsj
fkjghsdlfkjgdlfg
kfgldjkldkjg
dlfkjgldjfhg
----- End
Do I just add the lines like this :
$private_key= "dwfhlsdjkhlsjfkjghsdlfkjgdlfgkfgldjkldkjgdlfkjgldjfhg";
Thanks in advance.
Maik
If an error occurs, the XML will contain an error message. You can extract that from the XML response. For the exact structure of the error messages, please look at the documentation: <a href="http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/" target="_blank">http://docs.amazonwebservices.com/AWSECommerceSer...</a>
Regarding the private key: I think this is the correct way to construct the key. Just try if it works. If not, it could be possible that you got multiple private/public key pairs from Amazon and that this was the wrong one.
excelentt!!!
can i get LCC no.,publishers details of a book from amazon api link
Please try to use a response group like "Large" and look at the complete XML response. If it does contain these details you will not be able to extract them via the API. If your request works you can then try to limit your response group to something smaller than "Large" to save bandwidth and to speed up your requests.
The signature don't work anymore... =(
The generation of the signature is still working but you may have to modify a few things so that the complete functions continues to work with the updated version of the API:
1. Replace
$host = "ecs.amazonaws.".$region;
with
$host = 'webservices.amazon.'.$region;
2. Replace
$params["Version"] = "2009-03-31";
with
$params["Version"] = "2011-08-01";
3. Make sure that you add a parameter named "AssociateTag" with your Amazon Associate Tag as the value to your list of parameters for each request.
With these modifications it should continue to work. I will soon upload an updated version of the script.
Script scheint nicht mehr zu funktionieren, seit 2 Tagen keine Verbindung mehr zu amazon.
Bitte probieren Sie die Modifikationen die ich in folgender Antwort beschrieben habe: <a href="http://mierendo.com/software/aws_signed_query/#IDComment217403332" target="_blank">http://mierendo.com/software/aws_signed_query/#ID...</a>
Für "de" geht es leider noch immer nicht.
Es sollte mit den genannten Änderungen auch für .de funktionieren. Wenn Sie möchten, können Sie mir Ihr Script einmal per Email schicken. Vll. finden wir dann den Fehler.
Hello,
there is a new api version... anyone a idea how i could make that work?
thx
Please look at my answer to a similar question: <a href="http://mierendo.com/software/aws_signed_query/#IDComment217403332" target="_blank">http://mierendo.com/software/aws_signed_query/#ID...</a>
THANK YOU, GRACIAS, MERCI , спасибо
Really, I never would have done it without your help
=)
bless you.
:-)
You have to insert a param AssociateTag for making latest API version working. Example:
$params["AssociateTag"] = "xyz123";
You may also want to change $params["Version"] or simply comment out for using default version.
Correct. I've already mentioned this in a previous comment. Please note that the associate tag should be a valid one, so you have to create an an Amazon Associate account.
Thank you!!!
Damit klappt es wieder ohne Probleme!!!
I have created a page that requests 20 or 30 individual product data (30 ASIN). Unfortunately, this slows down the page load. I guess the reason is that every request is an individual signed request. Can anyone confirm that? And is there any solution for this? My idea was to request all 30 individual product data (30 ASIN) using a single signed request. Is it possible to request multiple products with a single signed request? How does he code looks like? Thanks in advance for any help on this!
You can use a comma-separated list of ASINS in your requests to get up to 10 ASINs at once. Also look into "batch-request" with which you can double the number of products returned by the API.
In addtion, do not forget to implement caching, so that frequent accesses to certain pages do not result in the same API requests over and over again.
Thanks a million--as many others have said, this saved me lots of time and headache!
Cheers!
Thanks you very much, this helped me tremendously where the Amazon docs were not. Well laid out and simple example. Also +1 for endurado mentioning the new AssociateTag addition.
You rock. Thank you.
Wonderful it works awesome!! Thank you!!
Thanks very much. i have been searching for hours, but amazon seems not to be able to explain its code after many years. This was very helpfull
With a few tweaks, works pretty good. Thank you. I am learning coding, and it is amazing, but got it to work with your guidance. Smart!
Hallo,
vielleicht genau das Skript, das ich gesucht habe. Leider bekomme ich es nicht zum Laufen... :/
Die Änderungen aus den Kommentaren habe ich bereits durchgeführt, allerdings bin ich mir nicht ganz sicher, wo ich meinen AssociateTag platzieren muss.
Freue mich über jeden Tipp!
Danke
Marc
Der AssociateTag ist einfach ein weiterer Parameter im Array $params. Dann sollte es funktionieren.
Hm, "Did not work"...
Dabei nutze ich die komplette Codevorgabe, lediglich meinen Tag sowie die Keys habe ich abgeändert..
index.php:
...
$public_key = "20stelligerKey";
$private_key = "40stelligerKey";
$pxml = aws_signed_request("de", array("Operation"=>"ItemLookup","ItemId"=>"B000X9FLKM","ResponseGroup"=>"Small"), $public_key, $private_key);
...
aws_signed_request.php:
...
// some paramters
$method = "GET";
// $host = "ecs.amazonaws.".$region; ALT
$host = 'webservices.amazon.'.$region;
$uri = "/onca/xml";
// additional parameters
$params["Service"] = "AWSECommerceService";
$params["AWSAccessKeyId"] = $public_key;
$params["AssociateTag"] = "meintag-21";
// GMT timestamp
$params["Timestamp"] = gmdate("Y-m-d\TH:i:s\Z");
// API version
// $params["Version"] = "2009-03-31"; ALT
$params["Version"] = "2011-08-01";
...
Grüße
Marc
Hi Thanks for the great article,
But I need one more help,
Can you please tell me How can i get top 50 item info... Currently return 10 item information by default....
Thanks in advance..