//you can use this version under any version of the GPL (GNU Public License) //20020816/JvG, released under the GNU GPL //... //20090623/JvG, busy adding the signing that Amazon requires from 20090815 //20090804/JvG, refixed the do/du problem for used products (which had gone after going back to an old version) and added the (server) locale functionality to the signed version //20090804/JvG, rewrote the scripts to make the new version (with signing) more like the old version so that the caching would work again but didn't test it yet, this also made show_url work again //20090812/JvG, added the comments for 20090804 and 20090812 and tested the caching and I am going to try to put the script online //20090816/JvG, always use signed request, started adding better time measurement //20090826/JvG, script will now create cache directory itself //20090826/JvG, got simplexml object printing working //20090827/JvG, added printing a simple HTML-header to have utf8 rendered correctly //20090827/JvG, added the $tab variable in all echo statements so all HTML is indented properly //20090827/JvG, removed a lot of old outdated messages from this list //Thanks for all the questions, improvement tips and help! //Feel free to send more feedback to me at ganswijk@xs4all.nl! //Please mention AWS or Amazon in the subject line to avoid my spamfilters error_reporting(error_reporting()&~E_NOTICE); //this prevents a lot of warnings on a Windows server, but you can comment-out this line for debugging $Amicrotime['total'][0]=getmicrotime(); //time at start of total process //send html-header so utf8's are correctly shown echo "\n"; echo " \n"; echo " \n"; echo " \n"; echo " \n"; $tab=' '; //tab how much? $jaap=$false; //($_SERVER['PHP_SELF']=='/jaap/php/amazon/amazonv4.php' or $_SERVER['PHP_SELF']=='/jaap/php_linux/amazon/amazonv4.php'); //I use this flag to develop new things for the script on my local PC. $jb=false; //this is a test for someone, please change it to false if it isn't already //Set these to correspond with your site. //This will determine the first results that the user will see. //The user can overrule them using the search form. $Adefault=array( 'language' =>'en', //what language to render the page in 'locale' =>'us', //which server's products? available: ca,de,fr,jp,uk,us //'mode' =>'books', //what product category? 'page' =>1, //first page to show (we are counting from 1 not 0) //'search' =>'Machiavelli', //what to search for? 'operation' =>'ItemSearch', //what to do? 'searchindex' =>'Books', //what product category for search? 'searchparameter' =>'Author', //what kind of search? 'searchparameterdata'=>'Machiavelli', //what to search for? //here some debugging flags you can put at the end of the URL to call this script with, like: '?show_array=true' 'show_array' =>false, //debug: show complete incoming array? You can use this to see what other information Amazon is sending 'show_url' =>false, //debug: show XML request url to be send to Amazon? 'show_xml' =>false, //debug: show incoming XML code from Amazon? ); //change the debug options to true if you want to activate them or call the script with '?show_array=true' to see what actual information you're getting from Amazon and how little my standard script is actually showing of it include "data.php"; //static data about Amazon (servers, search fields) v3- include "data_v4.php"; //static data about Amazon (servers, search fields) v4+ include "language.php"; //translate the output to the prefered language of the user include "aws_signed_request.php"; //see: http://mierendo.com/software/aws_signed_query/, please note that I'm using an slightly adapted version of the script: I do my own XML-interpreting //20090624: the following isn't relevant anymore it seems, 20100221: yes it is: $Aassociates_id=array( 'de'=>'chipdir00' , // <-- replace with your amazon.de associate ID, or leave it as it is 'fr'=>'chipdir010', // <-- replace with your amazon.fr associate ID, or leave it as it is 'jp'=>'INVALID' , // <-- replace with your amazon.co.jp associate ID, or leave it as it is 'uk'=>'chipdir03' , // <-- replace with your amazon.co.uk associate ID, or leave it as it is 'us'=>'chipdir' , // <-- replace with your amazon.com associate ID ); //If you haven't gotten your own associate ID yet, get it from: //http://associates.amazon.com/exec/panama/associates/apply // //Normally you will want to start selling books via Amazon.com only, //just to see if it works and pays well (which it normally doesn't). // //You can save yourself a lot of trouble by not applying for an associate ID //at the other local Amazon sites yet, but leaving mine in for the time being //and perhaps I'll make a few pounds, euro's and/or yen. As soon as I would //receive a noticable amount of cash I'll track you down an will warn you //to get your own ID's there. // //please note that all those local Amazons send out all of their communications //in their local languages, so French, German and Japanese for example and //that you first have to earn enough money per branch before you get paid. //And the Japanese branch only seems to pay in gift-certificates, so you'd //have to buy Japanese books for example. // //if you want to disable any of the foreign branches, please do so in the //file data.php, but please consider that we're living in an ever better //connected world and sometime later you might want to add them again //if only as a service to your visitors. //20090623: The signed request version requires these two parameters: //$public_key="xxxxxx"; //you have to get this from Amazon on page https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key //$private_key="xxxxxx"; //you have to get this from Amazon on page https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key $public_key =""; $private_key=""; //other flags: //this doesn't seem to be relevant anymore: //$f_rich=true; //when set to true this will convert the URL so you'll get 7.5% on qualifying books instead of 5%. It doesn't work yet outside of the USA. //change it to false when you prefer to get only 5% ;-) //see http://forums.prospero.com/n/mb/message.asp?webtag=am-assosdev&msg=6.1&ctx=0, or search the forum for 'nosim' //This is only helpful for certain books //correction: keep this option set to true, to prevent the showing of Amazon's annoying distraction pages. //20080530: i don't know if this is still relevant for version 4 $f_user_search=true; //add a user search form and allow user searches? //============================================================================= //==You don't have to change anything below this line to start earning money.== //============================================================================= if ($jaap) { print_array($_GET,$tab); } //what are the user's prefered languages? $Ahttp_lang=split(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']); if ($jaap) { print_array($Ahttp_lang,$tab); } //try to find the visitor's prefered language, this is still experimental foreach ($Ahttp_lang as $i=>$d) { if ($Axl[$l=substr($d,0,2)]) { $pref_lang=$l; break; } } $Adefault['language']=$pref_lang; if ($jaap) { echo $tab."prefered available language='$pref_lang'
\n"; print_array($Ahttp_lang,$tab); } //for all parameters see if the user has overruled it or use the default foreach ($Adefault as $i=>$d) { $$i=$_GET[$i]?$_GET[$i]:$d; if ($jaap) echo $tab."$i = '".$$i."'
\n"; } //this is a test for someone: if ($jb) { $operation ='SellerListingSearch'; $show_array=1; } //use which servers? $norserver=$Aserver[$locale]['nor']; $xmlserver=$Aserver[$locale]['xml']; //20090817: this is no longer used it seems: //$dev_token='D2WMCOIPS9D14E'; //you can replace this with your own developer token after you have changed the script a lot //get one from http://associates.amazon.com/exec/panama/associates/join/developer/application.html //see: //http://forums.prospero.com/n/mb/message.asp?webtag=am-assocdevxml&msg=378.1&ctx=0 //this is the data that is used to form the request for AWS //this is the part that is search specific if ($jb) { //this is a test for someone $parameters=array( 'Operation' =>$operation , 'SellerId' =>'A23I0F0MWQH94Z' , // 'Keywords' =>urlencode($search) , // 'SearchIndex' =>$searchindex , //Books for example. // "$searchparameter"=>$searchparameterdata , 'ItemPage' =>$page , //which page? // 'Service' =>'AWSECommerceService' , //this makes it version 4 // 'SubscriptionId' =>$subscriptionid , //is this correct? // 'AWSAccessKeyId' =>$awsaccesskeyid , //is this correct? 'AssociateTag' =>$Aassociates_id[$locale], // 'ResponseGroup' =>'Medium' , //Small, Medium or Large 'ResponseGroup' =>'SellerListing' , //Small, Medium, Large or SellerListing ); } else { $parameters=array( 'Operation' =>$operation , 'Keywords' =>urlencode($search) , 'SearchIndex' =>$searchindex , //Books for example. "$searchparameter"=>$searchparameterdata , 'ItemPage' =>$page , //which page? // 'Service' =>'AWSECommerceService' , //this makes it version 4 // 'SubscriptionId' =>$subscriptionid , //is this correct? // 'AWSAccessKeyId' =>$awsaccesskeyid , //is this correct? 'AssociateTag' =>$Aassociates_id[$locale], 'ResponseGroup' =>'Medium' , //Small, Medium, Large or SellerListing ); } //this will create the filename for the cache file //it should only contain non-static search parameters and not static data for your site $ext=$Aserver[$locale]['ext']; //extension of server, see data.php $file_data=$ext; ksort($parameters); foreach ($parameters as $i=>$d) { $file_data.='&'.$i.'='.$d; } $file=aws_signed_request($ext,$parameters,$public_key,$private_key); //20090804: sign the request if ($show_url) { echo $tab."
\n"; echo $tab."Show_url induced debugging:
\n"; echo $tab."

\n"; echo $tab."Request data:
\n"; echo $tab."$file_data
\n"; echo $tab."

\n"; echo $tab."Asking Amazon's XML interface for URL:
\n"; echo $tab."$file
\n"; echo $tab."


\n"; } //do you want to use caching? $cache_time=3600; //60s*60m=1h, in seconds how long a cache entry may be used //Use 0 for no caching //Amazon requires a maximum of one day for most data, //but unfortunately only one hour for prices, I think. $time0=time(); $Amicrotime['cache read'][0]=getmicrotime(); //time before reading cache $cachedir='cache/'; //directory where to cache things. //make sure the script can make this directory or make it yourself and give it the right permissions so the script can read and write in the directory. //under Unix: chmod a+rw cache //If you don't want the contents of the directory to be accessible via the WWW, put the directory outside of the WWW-pages tree, like in /tmp or a level higher: ../ if (file_exists($cachedir) and is_dir($cachedir)) { //Okay: directory already exists } else { if (mkdir($cachedir)) { echo $tab."cache directory created
\n"; } else die("can't make cache directory"); } if (is_readable($cachedir) && is_writable($cachedir)) { //Okay: directory is readable and writable by the script } else { die("cache directory is not readable and writable"); } if ($jaap) { $cache_time=0; //don't cache } //first we clean out the cache if ($cache_time and $hd=opendir($cachedir)) { while ($fn=readdir($hd)) { if ($time0-filemtime($cachedir.$fn)>=$cache_time) { //is the file too old? if (!($fn=='.' or $fn=='..')) unlink($cachedir.$fn); //remove it } } closedir($hd); } //this is the actual program, it does: //- send the request using fopen() //- read the returned data into an XML string //- convert the XML string into an array //- print the array //$cache_file_name=$cache.md5($file); //determine the name of the cache file for the current request $cache_file_name=$cachedir.$file_data; //determine the name of the cache file for the current request if ($jaap) echo $tab."file_data=$file_data
\n"; //if ($cache_time and //are we caching? // is_readable($cache_file_name) and //file already readable in cache? // $hf=fopen($cache_file_name,'r')) { //can it be opened? // $A=unserialize(fread($hf,filesize($cache_file_name))); // fclose($hf); // $Amicrotime['cache'][1]=getmicrotime(); //time after reading cache //} if ($cache_time and //are we caching? file_exists($cache_file_name) and //file already in cache? should be readable $filecontents=file_get_contents($cache_file_name)) { //file already in cache? //echo $tab."filecontents:
".htmlentities($filecontents)."

\n"; $Amicrotime['cache read'][1]=getmicrotime(); //time after reading cache } else { $Amicrotime['cache read'][1]=getmicrotime(); //time after using cache and requesting AWS $Amicrotime['AWS' ][0]=getmicrotime(); //time after using cache and requesting AWS //if your provider doesn't allow file_get_contents() on foreign files, //uncomment the next lines instead: //20080730: Sorry haven't retested the above code lately //$session=curl_init($file); //curl_setopt($session,CURLOPT_HEADER,false); //curl_setopt($session,CURLOPT_RETURNTRANSFER,true); //$sfile=curl_exec($session); //curl_close($session); if ($filecontents=file_get_contents($file)) { //get the file from Amazon, did we succeed? $Amicrotime['AWS'][1]=getmicrotime(); //time after getting AWS data if ($cache_time) { //are we caching? $Amicrotime['cache write'][0]=getmicrotime(); //time before writing to cache file_put_contents($cache_file_name,$filecontents); //write the cache file $Amicrotime['cache write'][1]=getmicrotime(); //time after writing to cache } } else die(xu("can't get data from Amazon").".\n"); } //debug: want to see the XML? //you can easily use this debugging tool by adding '&show_xml=1' to the URL of this script if ($show_xml) { //print the raw XML for debuggging? echo $tab."showing the xml:
\n"; echo $tab."
\n";
  echo $tab.htmlentities($filecontents);    //print the file
  echo $tab."
\n"; echo $tab."
\n"; } $Amicrotime['XML'][0]=getmicrotime(); //time before XML decoding //decode the XML: if ($A=simplexml_load_string($filecontents)); //decode the XML to an object else die("can't decode the XML data"); //debug: if ($jaap) { echo $tab."
\n"; echo $tab."
\n";
  print_r    ($A);
  echo $tab."
\n"; //echo $tab."
\n"; //echo $tab."
\n";
//var_dump   ($A);
//echo $tab."
\n"; //echo $tab."
\n"; //echo $tab."
\n";
//var_export ($A);
//echo $tab."
\n"; echo $tab."
\n"; print_array($A); echo $tab."
\n"; } $Amicrotime['XML'][1]=getmicrotime(); //time after XML decoding //debug: show the array or object //you can easily use this debugging tool by adding '&show_array=1' to the URL of this script if ($show_array) { //show the array for debugging? print_array($A,$tab); //show the complete array } //show the stuff $Amicrotime['show'][0]=getmicrotime(); //time before showing stuff echo $tab."

".xu('searching for')." '$searchparameterdata'

\n"; //you can change the h2's to h1's //20090827/old code: //if ($e=$error_msg) { // switch ($Aerror[$e]) { // case 'print': // echo $tab."$e
\n"; // break; // default: // echo $tab.xu('Amazon returned the error').': '.$e."
\n"; // echo $tab."
\n"; // echo $tab.xu('please add this error message to the '). // "". // xl('database').".
\n"; // break; // } //} //$jaap=true; //actually show the products: print_products($A,$tab); //print all the products function print_products($A,$tab='') { global $jaap; global $language; global $locale; global $operation; global $page; global $search; global $searchparameter; global $searchparameterdata; switch ($operation) { case 'SellerListingSearch': die("sorry but SellerListingSearch doesn't work yet"); $items =$A['SellerListingSearchResponse']['SellerListings']; $subnode='SellerListing'; break; default: // $items=$A['ItemSearchResponse']['Items']; //old // $subnode='Item'; // break; if ($jaap) { echo $tab."in print_products():
\n"; echo $tab."A:
\n"; print_array($A,$tab=''); } $items =$A ->Items; // $items_sub=$items->Item; $aitems=(array)$items; //it is very strange that this and the next line works and not the line before $items_sub=$aitems['Item']; if ($jaap) { echo $tab."items:
\n"; echo $tab."
\n";
      print_r($items);
      echo $tab."
\n"; echo $tab."items:
\n"; print_array($items,$tab=''); echo $tab."items->Item:
\n"; echo $tab."
\n";
      print_r($items->Item);
      echo $tab."
\n"; echo $tab."items->Item:
\n"; print_array($items->Item,$tab=''); echo $tab."items_sub:
\n"; echo $tab."
\n";
      print_r($items_sub);
      echo $tab."
\n"; echo $tab."items_sub:
\n"; print_array($items_sub,$tab=''); } break; } $npro=$items->TotalResults; $npag=$items->TotalPages; echo $tab."".xu('number of products').": $npro
\n"; echo $tab."".xu('page').' '.($page).' '.xl('of').' '.((int)$npag)."
\n"; echo $tab."

\n"; echo $tab."\n"; echo $tab." \n"; if (is_array($items_sub) and $items_sub[0]) { foreach ($items_sub as $i=>$E) { print_product($E,$tab.' '); } } else { print_product($items_sub,$tab.' '); } echo $tab." \n"; echo $tab."
\n"; //provide links to previous and next page if ($npag>1) { //echo $tab."


\n"; echo $tab.xu('page:')."\n"; echo $tab.make_link_to_page(1,1)."\n"; echo $tab.make_link_to_page(2,2)."\n"; if ($page>=2) { echo $tab.make_link_to_page($page-1,'<')."\n"; } if ($page<$npag) { echo $tab.make_link_to_page($page+1,'>')."\n"; } echo $tab.make_link_to_page($npag,$npag)."\n"; } } //print one Amazon product //version 4 function print_product($E,$tab) { //global $Aassociates_id; //global $dev_token; //global $f_rich; //do you want 15% or 5%? (only for discounted books), 20090624: I don't know if this is still relevant global $jaap; global $locale; global $norserver; if ($E) { if ($jaap) echo $tab."print_product()
\n"; $url=$E->DetailPageURL; if ($jaap) echo $tab."url=$url
\n"; $E2A=(array)$E; $url=$E2A['DetailPageURL']; if ($jaap) echo $tab."url=$url
\n"; if ($jaap) print_array($E2A); //print_array($E); //rebuild the URL if you want 15% instead of 5%: //20090804/wjvg: changed this: // $url=($f_rich /*and $mode=='books' and $locale=='us'*/)?"$norserver/exec/obidos/ASIN/".$E['ASIN'].'/ref=nosim/'.$Aassociates_id[$locale].'?dev-t='.$dev_token:$E['url']; //$url=($f_rich /*and $mode=='books' and $locale=='us'*/)?"$norserver/exec/obidos/ASIN/".$E['ASIN'].'/'.$Aassociates_id[$locale]:$E['url']; echo $tab. "\n"; echo $tab. " \n"; if ($d=$E->MediumImage) { $iu=$d->URL; $ih=$d->Height; $iw=$d->Width; echo $tab. " \n"; } echo $tab. " \n"; echo $tab. " \n"; if ($d=$E->ItemAttributes->Title) { echo $tab. " $d
\n"; } if (is_array($dd=$E->ItemAttributes->Author)) { echo $tab. " ".xl('by').": "; foreach ($dd as $i=>$d) { if ($i) echo ', '; //echo $tab."$d"; } echo "
\n"; } else if ($d=$dd) { echo $tab. " ".xl('by').": $d
\n"; } $dm=$E->ItemAttributes->Publisher; $dr=$E->ItemAttributes->PublicationDate; if ($dm or $dr) { echo $tab. " "; if ($dm) { echo xl('publisher').": $dm"; } if ($dm and $dr) echo ', '; if ($dr) { echo xl('published').": $dr"; } echo "
\n"; } if ($asin=$E->ASIN) { echo $tab. " ASIN: $asin
\n"; } //$da=$E->Reviews->AvgCustomerRating; //not in Medium Set? $da=false; //don't show $ds=$E->SalesRank; if ($da or $ds) { echo $tab. " "; if ($ds) echo xl('sales rank').": $ds"; if ($da and $ds) echo ", "; if ($da) echo $tab.xl('customer rating').": ".(($da-1)*25)."%"; echo "
\n"; } $do=$E->OfferSummary->LowestNewPrice ->FormattedPrice; $du=$E->OfferSummary->LowestUsedPrice->FormattedPrice; if ($do or $du) { echo $tab. " ".xl('price').": "; if ($do) echo "$do (".xl('new').")"; if ($do and $du) echo ", "; if ($du) echo "$du (".xl('used').")"; echo "
\n"; } echo $tab. " \n"; if ($EditorialReviews=$E->EditorialReviews and $EditorialReview=$EditorialReviews->EditorialReview and $Content=$EditorialReview->Content) { echo $tab. " \n"; echo $tab. " $Content\n"; echo $tab. " \n"; } echo $tab. "\n"; } } //make link to other page (next, previous etc.) function make_link_to_page($page,$s) { global $language; global $locale; global $search; global $searchindex; global $searchparameter; global $searchparameterdata; return "
".xu($s).""; } //print an array or object //(for debugging) function print_array($A,$tab='') { if (is_object($A)) { echo $tab."object:
\n"; print_array((array)$A,$tab); } else if (is_array($A)) { // print_r($A); echo $tab."\n"; echo $tab." \n"; // echo $tab." COUNT=".count($A)."\n"; // if (is_object($A)) { // echo $tab." COUNT=".count($A)." - ".$A['0']."\n"; // } foreach ($A as $i=>$d) { echo $tab." \n"; echo $tab." \n"; // print_r($d); if (is_string($d)) { // echo $tab." STRING\n"; // print_r($d); // echo $tab." \n"; echo $tab." \n"; } else if (is_array($d)) { // echo $tab." ARRAY or OBJECT\n"; echo $tab." \n"; } else if (is_object($d)) { // echo $tab." ARRAY or OBJECT\n"; echo $tab." \n"; } else { // echo $tab." ELSE\n"; // print_r($d); // echo $tab." \n"; echo $tab." \n"; } echo $tab." \n"; } echo $tab." \n"; echo $tab."
$i
".htmlentities($d)."
".htmlentities($d)."\n"; print_array($d,$tab.' '); echo $tab." object:\n"; print_array((array)$d,$tab.' '); echo $tab."
".htmlentities($d)."
".htmlentities($d)."
\n"; } else { echo $tab."warning: not-an-array-or-object given to print_array()
\n"; } } function getmicrotime() { list($us,$s)=explode(' ',microtime()); return (float)$us+(float)$s; } if ($f_user_search) { //the next section adds a search box for the users echo $tab. "
\n"; echo $tab. "
\n"; //echo $tab." \n"; //echo $tab." \n"; //echo $tab." Search type
\n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. " \n"; echo $tab. "
".xu('language for page:')."\n"; echo $tab. " \n"; echo $tab. "
".xu('which server:')."\n"; echo $tab. " \n"; echo $tab. "
".xu('operation:')."\n"; echo $tab. " \n"; echo $tab. "
".xu('product category:')."\n"; echo $tab. " \n"; echo $tab. "
".xu('search parameter:')."\n"; echo $tab. " \n"; echo $tab. "
".xu('search string:')."
\n"; echo $tab. " \n"; echo $tab. "
\n"; //end of the search box section } //phpinfo(); $Amicrotime['show' ][1]=getmicrotime(); //time after showing $Amicrotime['total'][1]=getmicrotime(); //time at end //The next part is to show if the script isn't overburdoning your server. (The time waiting for Amazon isn't burdoning your server). You can remove the next part if you like: echo $tab."
\n"; //echo("Time used for time-consuming parts:
\n"); echo $tab."Time used:
\n"; foreach ($Amicrotime as $i=>$d) { //if ($d[1]>$d[0]) { printf($tab."- %.2f s %s
\n",$d[1]-$d[0],$i); //} } echo " \n"; echo "\n"; //end