I received an email suggesting that I encode the "foward slashes" in the signature. As Amazon stipulates that only A-Za-z0-9_.~- must remain uncoded. I am updating the above code and using rawurlencode() to encode the reserved characters in both the $NewString and $Signature. Be aware when using rawurlencode() with PHP versions before 5.3 that the output is not compliant with RFC 3986 as the tilde ( ~ ) character is also encoded. Please note that the code posted above will not work if the Request URL contains a plus sign ( + ). Which is the case when using the search function built into ASM2. The following code also corrects that issue. $String = preg_replace('/[\r\n\" "]/', '', $Request); $SecretAccessKey = ""; $StringArray = explode( '?', $String); $ValueStringArray = explode("&", $StringArray[1]); $ValueStringArray[] = "Timestamp=" .gmdate("Y-m-d\TH:i:s\Z"); asort($ValueStringArray); $NewString = implode("&", $ValueStringArray); $NewString = rawurlencode($NewString); $NewString = str_replace("%3D", "=", $NewString); $NewString = str_replace("%26", "&", $NewString); $NewString = str_replace("%7E", "~", $NewString); $url = parse_url($StringArray[0]); $PrependString = "GET\n" .$url['host']. "\n" .$url['path']. "\n" .$NewString; $Signature = base64_encode(hash_hmac("sha256", $PrependString, $SecretAccessKey, True)); $Signature = rawurlencode($Signature); $Signature = str_replace("%7E", "~", $Signature); $SignedRequest = $StringArray[0]. "?" . $NewString . "&Signature=" .$Signature; Code (markup):
Adding the Amazon product API signature to Freekrai's ASM2 (My Amazon Store Manager v 2.0) is quite easy! Look in ASM2's script folder for the aws4class.php file. Open the aws4class.php file and scroll down to the xmlquery() function. Add the API signature code as shown below. Please note that both $Request and $SignedRequest in the above API signature code need changed to "$url" as shown in the code below! function xmlquery($url){ // Add API Signature Code Here $String = preg_replace('/[\r\n\" "]/', '', $url); $SecretAccessKey = ""; $StringArray = explode( '?', $String); $ValueStringArray = explode("&", $StringArray[1]); $ValueStringArray[] = "Timestamp=" .gmdate("Y-m-d\TH:i:s\Z"); asort($ValueStringArray); $NewString = implode("&", $ValueStringArray); $NewString = rawurlencode($NewString); $NewString = str_replace("%3D", "=", $NewString); $NewString = str_replace("%26", "&", $NewString); $NewString = str_replace("%7E", "~", $NewString); $url = parse_url($StringArray[0]); $PrependString = "GET\n" .$url['host']. "\n" .$url['path']. "\n" .$NewString; $Signature = base64_encode(hash_hmac("sha256", $PrependString, $SecretAccessKey, True)); $Signature = rawurlencode($Signature); $Signature = str_replace("%7E", "~", $Signature); $url = $StringArray[0]. "?" . $NewString . "&Signature=" .$Signature; // End of API Signature Code $data = @implode("",file($url)); $this->xml = $data; $parser = xml_parser_create(); xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,1); xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0); xml_parse_into_struct($parser,$data,&$d_ar,&$i_ar); xml_parser_free($parser); $this->i_ar = $i_ar; $this->d_ar = $d_ar; return $d_ar; } Code (markup):
I've got this error when running the script : Warning: Call-time pass-by-reference has been deprecated in /xxxx/xxxxxxxx/public_html/xxxx/script/lib/aws.class.php on line 300 Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /xxxx/xxxxxxxx/public_html/xxxx/script/lib/aws.class.php:300) in /xxxx/xxxxxxxx/public_html/xxxx/script/lib/common.php on line 11 This is the script of line 300 : xml_parse_into_struct($parser,$data,&$d_ar,&$i_ar); This is the script of line 11 : session_start(); What should I do to fix the problem ?
I hadn't seen that error before so I did a search for it on Google. The error appears to be related to the ampersands (&) in the following line which are located before $d_ar and $i_ar. xml_parse_into_struct($parser,$data,&$d_ar,&$i_ar); Code (markup): Try simply removing the ampersands (&) and see what happens? It appears that this is pretty common when older scripts are used with newer versions of PHP. For reference what version of PHP are you using? Was ASM2 working ok before adding the API signature code? If you still have problems please let me know!
Finally, I have done developing amazon product advertising API Signature using php with the new requirement (access key and secret key). I use SOAP to complete it. Thanks to myhart for the clue. The owner of m*y*p*d*l*ptops.com/index.php NB : Replace * with a
I've been reading through this thread in the hope of finding some code I could convert to VBScript. It looks to me like I'm going to have problems with this, as some of the functions called in these scripts are not native to Windows or VBScript. I'm using Windows/ASP/Vbscript hosting and there doesn't seem to be any examples showing people how to sign a REST request using VBScript. I suspect some 3rd party COM objects might be required. Has anyone seen an example that could help me? Just found this request test code that uses some Javascript functions to do the signing - http:// developer. amazonwebservices. com/connect/entry.jspa?externalID=2609&categoryID=14 . I tested it and it runs on my server, hopefully I can now put something together that runs offline.
The Amazon Product API Signature Code I have posted above for ASM2 contains a couple errors. I meant to urlencode the Tilde (~) character not urldecode it! Also the str_replace() for Tilde (~) in the $Signature doesn't appear to be necessary. As Tilde (~) is not one of the characters in the Base64 alphabet. http://en.wikipedia.org/wiki/Base64 $NewString = str_replace("%7E", "~", $NewString); Code (markup): Replaced above line with: $NewString = str_replace("~", "%7E", $NewString); Code (markup): Deleted the following line: $Signature = str_replace("%7E", "~", $Signature); Code (markup): I have added rawurldecode() to decode the original $Request URL before processing. $String = rawurldecode($Request); $String = str_replace("%7E", "~", $String); Code (markup): Encoding encoded characters should never be done! Amazon states "Be sure that you do not double-escape any characters." As it can effect the results returned or even kept the script from working!!! This is especially important for characters in the $Signature as Amazon states "Most importantly, make sure the signature is URL encoded only once." Removed delete Space (" ") from the preg_replace() line. This was done so that keywords would remain separated. However when using ASM2's search utility it really doesn't matter as keywords are separated by the plus (+) sign. $String = preg_replace('/[\r\n]/', '', $String); Code (markup): I set the first explode() function to split the string at the first Question Mark (?). As a Question Mark (?) entered with an unfiltered search utility will cause the the Amazon API Product Request to fail! $StringArray = explode( '?', $String, 2); Code (markup): Added a preg_replace() line to filter the "Keywords" parameter. The characters Ampersand (&) and Equals (=) can really mess up the $Parameters array created by the second explode() function!!! $String = preg_replace('#Keywords=(.*?)&([A-Za-z]+)=#e', '"Keywords=".preg_replace("/[^0-9a-zA-Z]/"," ","$1")."&".$2."=";', $String); Code (markup): Added a preg_replace() line to delete more than one Space (" "). String = preg_replace('/[" "]+/', ' ', $String); Code (markup): Decided to label the $ValueStringArray as $Parameters. Hopefully this makes understanding the code a little easier? Checked the asort() function to confirm that it meets Amazon's requirement. "Sort your parameter/value pairs by byte value (not alphabetically, lowercase parameters will be listed after uppercase ones)." http://ascii-table.com/index.php The following Amazon API signature code includes all the above updates. I have tested it with ASM2 and also with a simple Keyword search script that I wrote. Using the explode() funtion has it's short comings and will fail if the original Amazon Request URL has an extra Ampersand (&) that isn't filtered. If you are having problems be sure to echo the original Request URL. Looking for characters that may need to be filtered out of the Parameters in addition to the Keyword Parameter that is filtered by the script. I found a helpful list of Amazon Parameters at the following page. http://www.npsites.com/2009/06/14/amazon-api-search-parameters-sorted-by-search-index.html If you have any problems, questions or suggestions concerning using the Amazon Product API Signature Code please let me know! $SecretAccessKey = ""; $String = rawurldecode($Request); $String = str_replace("%7E", "~", $String); $String = preg_replace('/[\r\n\" "]/', '', $String); $String = preg_replace('#Keywords=(.*?)&([A-Za-z]+)=#e', '"Keywords=".preg_replace("/[^0-9a-zA-Z]/"," ","$1")."&".$2."=";', $String); $String = preg_replace('/[" "]+/', ' ', $String); $StringArray = explode( '?', $String, 2); $Parameters = explode("&", $StringArray[1]); $Parameters[] = "Timestamp=" .gmdate("Y-m-d\TH:i:s\Z"); asort($Parameters); $NewString = implode("&", $Parameters); $NewString = rawurlencode($NewString); $NewString = str_replace("~", "%7E", $NewString); $NewString = str_replace("%3D", "=", $NewString); $NewString = str_replace("%26", "&", $NewString); $url = parse_url($StringArray[0]); $PrependString = "GET\n" .$url['host']. "\n" .$url['path']. "\n" .$NewString; $Signature = base64_encode(hash_hmac("sha256", $PrependString, $SecretAccessKey, True)); $Signature = rawurlencode($Signature); $SignedRequest = $StringArray[0]. "?" . $NewString . "&Signature=" .$Signature; Code (markup):
Hi, I hae a site that uses amazon's database of boos. ISBN 10 and ISBN 13s are handled a bit differently. The initial code seems to work fine for books with 10 digit ISBNs. But to search for 13 digit ISBNs one must search via IdType=EAN and SearchIndex=Books instead. That seems to return an error using these signed requests. this works perfectly if (strlen($isbn)==10) { $String = "AWSAccessKeyId=$AWSAccessKeyId& ItemId=$ItemId& Operation=ItemLookup& ResponseGroup=Medium& Service=AWSECommerceService& Timestamp=$Timestamp& Version=2009-01-06"; } PHP: this returns an error. I always use to use these attributes for ISBN 13s as this is how Amazon treats them. if (strlen($isbn)==13) { $String = "AWSAccessKeyId=$AWSAccessKeyId& ItemId=$ItemId& Operation=ItemLookup& ResponseGroup=Medium& Service=AWSECommerceService& SearchIndex=Books& IdType=EAN& Timestamp=$Timestamp& Version=2009-01-06"; } PHP: I ge the following error. When I click the XML link I see this page: <?xml version="1.0"?> <ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2009-01-06/"><Error><Code>RequestExpired</Code><Message>Request has expired. Timestamp date is 2009-08-02T13:50:36Z.</Message></Error><RequestID>5c66466b-6999-4ae8-95dd-73b1ad7ced22</RequestID></ItemLookupErrorResponse> Code (markup): Interestingly enough when I remove the signature from the end of the XML link it returns the proper page.
http://mierendo.com/software/aws_signed_query/ i used this method and it seems to work fine. I'm not sure why but its working.
The error in the second example you posted appears to be because the parameters are not arranged by "byte value". Should be arranged as shown below if creating the signed request without the use of a "sort function" in your code. if (strlen($isbn)==13) { $String = "AWSAccessKeyId=$AWSAccessKeyId& IdType=EAN& ItemId=$ItemId& Operation=ItemLookup& ResponseGroup=Medium& SearchIndex=Books& Service=AWSECommerceService& Timestamp=$Timestamp& Version=2009-01-06"; Code (markup): I tested the following which worked fine for me. <? $AWSAccessKeyId = ""; $SecretAccessKey = ""; $ItemId = "9780735714106"; $Timestamp = gmdate("Y-m-d\TH:i:s\Z"); if (strlen($ItemId)==10) { $String = "AWSAccessKeyId=$AWSAccessKeyId& ItemId=$ItemId& Operation=ItemLookup& ResponseGroup=Medium& Service=AWSECommerceService& Timestamp=$Timestamp& Version=2009-01-06"; }else{ $String = "AWSAccessKeyId=$AWSAccessKeyId& IdType=EAN& ItemId=$ItemId& Operation=ItemLookup& ResponseGroup=Medium& SearchIndex=Books& Service=AWSECommerceService& Timestamp=$Timestamp& Version=2009-01-06"; } $String = preg_replace('/[\r\n]/', '', $String); $String = str_replace("%3D", "=", str_replace("%26", "&", rawurlencode($String))); $PrependString = "GET\nwebservices.amazon.com\n/onca/xml\n" . $String; $Signature = rawurlencode(base64_encode(hash_hmac("sha256", $PrependString, $SecretAccessKey, True))); $SignedRequest = "http://webservices.amazon.com/onca/xml?" . $String . "&Signature=" . $Signature; echo $SignedRequest."<p>"; echo '<a href="'.$SignedRequest.'">API</a><p>'; $API = simplexml_load_file($SignedRequest); $ASIN = $API->Items->Item->ASIN; $ISBN = $API->Items->Item->ItemAttributes->ISBN; $EAN = $API->Items->Item->ItemAttributes->EAN; echo "<b>ASIN</b> ".$ASIN."<p>"; echo "<b>ISBN</b> ".$ISBN."<p>"; echo "<b>EAN</b> ".$EAN."<p>"; ?> Code (markup): Using the script at http://mierendo.com/software/aws_signed_query/ arranges the parameters by "byte value" using the ksort() function as mentioned above. The code I have posted for ASM2 will also arrange the parameters using PHP's asort() function.
Thanks. I made the code even better since I can pass either as the idtype ISBN instead of passing the EAN for 13 and the ASIN for 10. Then I can get both 10 and 13 digit ISBNs from the result. if (strlen($isbn)==10 || (strlen($isbn)==13)) { $String = "AWSAccessKeyId=$AWSAccessKeyId& IdType=ISBN& ItemId=$isbn& Operation=ItemLookup& ResponseGroup=Medium& SearchIndex=Books& Service=AWSECommerceService& Timestamp=$Timestamp& Version=2009-01-06"; } $String = preg_replace('/[\r\n]/', '', $String); $String = str_replace("%3D", "=", str_replace("%26", "&", rawurlencode($String))); $PrependString = "GET\nwebservices.amazon.com\n/onca/xml\n" . $String; $Signature = rawurlencode(base64_encode(hash_hmac("sha256", $PrependString, $SecretAccessKey, True))); $SignedRequest = "http://webservices.amazon.com/onca/xml?" . $String . "&Signature=" . $Signature; //echo $SignedRequest."<p>"; //echo '<a href="'.$SignedRequest.'">API</a><p>'; $API = simplexml_load_file($SignedRequest); $isbn10 = $API->Items->Item->ASIN; //$ISBN13 = $API->Items->Item->ItemAttributes->ISBN; $isbn13 = $API->Items->Item->ItemAttributes->EAN; $ProductName = $API->Items->Item->ItemAttributes->Title; $Binding = $API->Items->Item->ItemAttributes->Binding; $Manufacturer = $API->Items->Item->ItemAttributes->Manufacturer; $NumberOfPages = $API->Items->Item->ItemAttributes->NumberOfPages; $Edition = $API->Items->Item->ItemAttributes->Edition; $Authors = $API->Items->Item->ItemAttributes->Author; $Content = $API->Items->Item->EditorialReviews->EditorialReview->Content; $ImageUrlMedium = $API->Items->Item->MediumImage->URL; if(!$ImageUrlMedium){ $ImageUrlMedium = "images/noimage.gif"; } PHP:
Has anyone upgraded GhostScripter's Amazon Shop script? I'm working on it but haven't been successful yet.
I checked GhostScripter's website last night and found that they are running a special on their Amazon Shop script. It was reduced to $30 so I bought a copy thinking I can probably use it on one of my websites and earn the $30 back over time. I downloaded their latest version and while I haven't had time to upload it to a website yet. I found by looking though the files that they have included the Amazon API signature code in this version of their script. When I have time I will download the older version and see if I can figure out how to add my API signature code to it.
Amazing, I didn't know they updated to address this problem. Any info is appreciated. Thank you in advance.