- <?php
- /**
- * This file contains the class used to query AWS.
- *
- * This is the only file that should be included when adding amazOOP to a PHP script.
- *
- * @author Mauricio Diaz <madd0@users.sourceforge.net>
- * @copyright 2004 (c) Mauricio Diaz Orlich
- * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
- * @version 0.3
- *
- * @package amazOOP
- */
-
- /**
- * For security, only this file should be included in your scripts.
- * @access private
- */
- define('_AMAZOOP', true);
-
- $core_path = dirname(__FILE__) . '/';
-
- if(!is_dir($core_path))
- $core_path = './';
- elseif($core_path && !preg_match('/\/$/', $core_path))
- $core_path .= '/';
-
- $allowsettimelimit = function_exists('set_time_limit');
- $allowgetimagesize = function_exists('getimagesize');
-
- define('CORE_PATH', $core_path);
-
- /**
- * By inserting this document, all required functions as well as user preferences
- * from other files (e.g. {@link userdata.inc.php}) are included to be used here.
- * @access private
- */
- require_once(CORE_PATH . "aq.lib.php");
-
- /**
- * The AmazonQuery class is the software's main class.
- *
- * It is through this class that amazOOP connects to
- * {@link http://www.amazon.com/gp/browse.html/?node=3434641 Amazon Web Services} to obtain product
- * information, make searches, etc. This class is also in charge of creating objects
- * out of {@link http://www.amazon.com/gp/browse.html/?node=3434641 AWS} responses
- * and handles the cache.
- *
- * An {@link AmazonQuery} object can be used for {@tutorial manual.isbn.pkg lite} searches, using
- * {@link liteQuery()}, {@tutorial manual.asin.pkg heavy} searches, using {@link heavyQuery()}, or
- * queries to a {@tutorial manual.cart.pkg Remote Shopping Cart}, using one of the functions for this
- * purpose ({@link newCart()}, {@link addToCart()}, {@link modifyCart}, {@link removeFromCart()},
- * {@link clearCart()} and {@link getCart()}).
- *
- * @author Mauricio Diaz <madd0@users.sourceforge.net>
- * @copyright 2004 (c) Mauricio Diaz Orlich
- * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
- * @version 0.3
- *
- * @package amazOOP
- */
- class AmazonQuery{
-
- /**
- * Creates a new object ready to query {@link http://www.amazon.com/gp/browse.html/?node=3434641 AWS}.
- *
- * An {@link AmazonQuery} object can be used for {@tutorial manual.isbn.pkg lite} searches, using
- * {@link liteQuery()}, {@tutorial manual.asin.pkg heavy} searches, using {@link heavyQuery()}, or
- * queries to a {@tutorial manual.cart.pkg Remote Shopping Cart}, using one of the functions for this
- * purpose ({@link newCart()}, {@link addToCart()}, {@link modifyCart}, {@link removeFromCart()},
- * {@link clearCart()} and {@link getCart()}).
- *
- * @return AmazonQuery
- */
- function AmazonQuery(){
-
- }
-
- /**
- * Queries an {@tutorial advanced.categories.pkg amazOOP category} for all its products.
- *
- * <b>Example:</b>
- * <code>
- * $books = $aq->getCategory("books", "uk");
- *
- * for($i = 1; $book = $books->getDetails($i); $i++){
- * echo $book->getProductName() . "<br>";
- *
- * echo $book->getAuthors(2) . "<br>";
- * }
- * </code>
- *
- * @param string $category the category you want to search. Read {@tutorial advanced.categories.pkg}
- * amazOOP category} to learn all about amazOOP categories and how to customize them.
- *
- * @param string $locale determines what Amazon site should be queried. Valid values are:
- * - "us": queries the Amazon.com catalog
- * - "uk": queries the Amazon.co.uk catalog
- * - "jp": queries the Amazon.co.jp catalog
- * - "de": queries the Amazon.de catalog
- *
- * @param string $type "lite" or "heavy", determines how much information you
- * want from AWS.
- * For more information on what type of information each type of request returns, take a look
- * at {@link LiteDetails} and {@link HeavyDetails}.
- *
- * @param integer $page indicates the page of results you want. Each page contains 10 results.
- *
- * @param string $sort indicates what parameter determines the sorting of results. Available sort
- * types are described in document {@tutorial manual.sort.pkg}.
- *
- * @return ProductInfo a {@link ProductInfo} object containing zero or more results returned by AWS.
- *
- * @see ProductInfo
- *
- * @tutorial advanced.categories.pkg
- * @tutorial manual.sort.pkg
- * @tutorial manual.search.pkg
- *
- */
- function getCategory($category = "books", $locale = "us", $type = "lite", $page = 1, $sort = "Bestselling"){
- // Obtain the node number based on the specified $category
- $node = getBrowseNode($locale, $category);
-
- // Query AWS
- return $this->query($node, "BrowseNode", $category, $locale, $type, $page, $sort);
- }
-
- /**
- * Queries an AWS Browse Node, that has not been specified as an {@tutorial advanced.categories.pkg amazOOP category}
- * for all its products.
- *
- * @param integer $bn the browse node you want to search.
- * Read the {@tutorial advanced.browsenodes.pkg tutorial on Browse Nodes} to learn all about AWS
- * browse nodes.
- *
- * @param string $mode when requesting products from a browse node, you have to specify a "mode". You should
- * read the {@tutorial advanced.browsenodes.pkg tutorial on Browse Nodes} to learn more about modes.
- *
- * @param string $locale determines what Amazon site should be queried. Valid locales are:
- * - "us": queries the Amazon.com catalog
- * - "uk": queries the Amazon.co.uk catalog
- * - "jp": queries the Amazon.co.jp catalog
- * - "de": queries the Amazon.de catalog
- *
- * @param string $type "lite" or "heavy", determines how much information you want from AWS.
- * For more information on what type of information each type of request returns, take a look
- * at {@link LiteDetails} and {@link HeavyDetails}.
- *
- * @param integer $page indicates the page of results you want. Each page contains 10 results.
- *
- * @param string $sort indicates what parameter determines the sorting of results. Available sort
- * types are described in document {@tutorial manual.sort.pkg}.
- *
- * @return ProductInfo a {@link ProductInfo} object containing zero or more results returned by AWS.
- *
- * @see ProductInfo
- *
- * @tutorial advanced.browsenodes.pkg
- * @tutorial advanced.categories.pkg
- * @tutorial manual.sort.pkg
- * @tutorial manual.search.pkg
- */
- function getBrowseNode($bn, $mode, $locale = "us", $type = "lite", $page = 1, $sort = "Bestselling"){
- // Query AWS
- return $this->query($bn, "BrowseNode", $mode, $locale, $type, $page, $sort);
- }
-
- /**
- * Queries AWS as instructed.
- *
- * This is the "low-level" method used to query AWS. Methods such as {@link getCategory()},
- * {@link getBrowseNode()}, {@link liteQuery()}, or {@link heavyQuery()}, all call this method.
- * As a matter of fact, you should rather use one of the aforementioned methods unless you feel
- * quite confortable with amazOOP.
- *
- * @param string $keywords the use of this paramater may vary depending of the type of search
- * you are making: for a BrowseNode search, it would refer to the desired BrowseNode, in the
- * case of an ASIN serach, it would refer to the desired ASIN, and so on...
- *
- * @param string $searchType one of the search types offered by AWS. Refer to the document
- * {@tutorial manual.search.pkg} for a list of valid search types.
- *
- * @param string $mode one of the modes proposed by AWS. Read the document
- * {@tutorial advanced.browsenodes.pkg} for an explanation of modes.
- *
- * @param string $locale determines what Amazon site should be queried. Valid locales are:
- * - "us": queries the Amazon.com catalog
- * - "uk": queries the Amazon.co.uk catalog
- * - "jp": queries the Amazon.co.jp catalog
- * - "de": queries the Amazon.de catalog
- *
- * @param string $type "lite" or "heavy", determines how much information you want from AWS.
- *
- * @param integer $page indicates the page of results you want. Each page contains 10 results.
- *
- * @param string $sort indicates what parameter determines the sorting of results. Available sort
- * types are described in document {@tutorial manual.sort.pkg}.
- *
- * @return mixed This function can return one of the following three types, depending on the query
- * made:
- * - {@link ProductInfo}: this is returned by most types of queries. This object contains zero
- * or more {@link LiteDetails} or {@link HeavyDetails} objects, depending on the $type requested. For more
- * information on what types of queries return {@link ProductInfo} objects, read the tutorial
- * {@tutorial manual.search.pkg}.
- * - {@link BlendedSearch}: only Blended searches return this type of object. Each {@link BlendedSearch}
- * object contains zero or more {@link ProductInfo} objects. For more information about Blended searches
- * read the tutorial {@tutorial manual.search.pkg}.
- * - {@link ShoppingCart}: returned when interacting with a Remote Shopping Cart. Read the tutorial
- * {@tutorial manual.cart.pkg} for more information about Remote Shoppng Carts.
- *
- * @see ProductInfo
- * @see BlendedSearch
- * @see ShoppingCart
- *
- * @tutorial manual.search.pkg
- * @tutorial manual.sort.pkg
- * @tutorial advanced.browsenodes.pkg
- * @tutorial advanced.categories.pkg
- */
- function query($keywords, $searchType, $mode = "books", $locale = "us", $type = "lite", $page = 1, $sort = "Bestselling"){
- global $_AMAZOOP_SEARCH_TYPES, $_AMAZOOP_SORTING, $_AMAZOOP_SITES;
-
- $start_time = explode(" ", microtime());
- $start_time = $start_time[1] + $start_time[0];
-
- $cached = false;
- $cacheDate = "day";
-
- // If someone sent blank strings as parameters, recover default values
- if($mode == "")
- $mode = "books";
- if($type == "")
- $type = "lite";
- if($page == "")
- $page = 1;
- if($sort == "")
- $sort = "Bestselling";
- if($locale == "")
- $locale = "us";
-
- // If there's no information about available sorting types for this mode
- // use default type (i.e. Bestselling), otherwise use specified type
- //-if(!isset($modes[$locale][$mode]))
- if(!getMode($locale, $mode))
- $sortType = "+salesrank";
- else{
- //-if(!isset($sorting[$modes[$locale][$mode]]) || !isset($sorting[$modes[$locale][$mode]][$sort])){
- if(!isset($_AMAZOOP_SORTING[getMode($locale, $mode)]) || !isset($_AMAZOOP_SORTING[getMode($locale, $mode)][$sort])){
- if(isset($_AMAZOOP_SORTING['all'][$sort]))
- $sortType = $_AMAZOOP_SORTING['all'][$sort];
- else
- $sortType = "+salesrank";
- }
- else
- $sortType = $_AMAZOOP_SORTING[getMode($locale, $mode)][$sort];
- }
-
- // build a request to send to AWS using provided data
- $request = $_AMAZOOP_SITES[$locale];
- $request .= "&t=" . getAssociateID($locale);
- $request .= "&dev-t=" . _AMAZOOP_DEV_TOKEN;
- $request .= "&" . $_AMAZOOP_SEARCH_TYPES[$searchType] ."=";
- $request .= rawurlencode($keywords);
- $request .= "&type=" . $type;
- $request .= "&sort=" . $sortType;
- if($mode != "all"){
- if($this->getRequestMode($mode, $searchType, $locale))
- $request .= $this->getRequestMode($mode, $searchType, $locale);
- else
- $request .= "&mode=$mode";
- }
- $request .= "&page=" . $page;
- //$request .= "&offer=All";
- //$request .= "&variations=yes";
-
- // If this query exists in cache, use the cached version
- if($cachedResult = $this->verifyQueryInCache(rawurlencode($keywords) . "," . $_AMAZOOP_SEARCH_TYPES[$searchType] . "," . $mode . "," . $type . "," . $page . "," . $sortType . "," . $locale)){
- //echo "I got it in cache<br>";
- $result = $cachedResult;
- $cached = true;
- }
- // Otherwise,
- else{
- // Create a new AmazonParser to parse AWS info
- $amazonParser = new AmazonParser();
-
- // Parse request and obtain new object based on AWS response
- $result = $amazonParser->parse($request, $type);
-
- unset($amazonParser);
- }
-
- // If for some reason parsing failed, try again...
- //while(!is_object($result))
- // $result = $amazonParser->parse($request, $type);
- if(!$result || !is_object($result)){
- $error = "Amazon did not return data when queried for: ";
- $error .= $request;
- $error .= "; I will try again";
- trigger_error($error);
- sleep(1);
- $amazonParser = new AmazonParser();
- $result = $amazonParser->parse($request, $type);
- }
- else if(isset($result->errorMsg) && $result->errorMsg == "We%20encountered%20an%20error%20processing%20your%20request.%20Please%20retry."){
- $error = "Data was obtained from Amazon, but contained an error: ";
- $error .= rawurldecode($result->errorMsg);
- $error .= "; request was: " . $request;
- if(method_exists($result, 'requestArgument'))
- $error .= "; and Request ID was: " . rawurldecode($result->requestArgument('RequestId'));
- trigger_error($error);
- sleep(1);
- $amazonParser = new AmazonParser();
- $result = $amazonParser->parse($request, $type);
- }
-
- if(!$result || !is_object($result) ||
- (isset($result->errorMsg) && $result->errorMsg == "We%20encountered%20an%20error%20processing%20your%20request.%20Please%20retry.")){
- trigger_error("Nothing was obtained from Amazon, will try to use cached data");
- if($temp = $this->verifyQueryInCache(rawurlencode($keywords) . "," . $_AMAZOOP_SEARCH_TYPES[$searchType] . "," . $mode . "," . $type . "," . $page . "," . $sortType . "," . $locale, 'week')){
- $result = $temp;
- $cached = true;
- $cacheDate = 'week';
- }
- }
- else{
- $cacheDate = 'hour';
- // Cache the new result you got
- if(!$cached){
- $signature = rawurlencode($keywords) . "," . $_AMAZOOP_SEARCH_TYPES[$searchType] . "," . $mode . "," . $type . "," . $page . "," . $sortType . "," . $locale;
- $this->makeFile($result, $signature);
- }
- }
-
- $this->removeOldEntries(getAmazoopConfig('cache_directory'), $cacheDate);
-
-
- $log = array();
- if($cached)
- $log[] = "From cache: " . $request;
- else
- $log[] = "Requested: " . $request;
- if($result->requestArgument('REQUESTID'))
- $log[] = "Request ID: " . trim($result->requestArgument('REQUESTID'));
- $log[] = "Remote IP: " . $_SERVER["REMOTE_ADDR"];
- if(isset($_SERVER["HTTP_USER_AGENT"]))
- $log[] = "User Agent: " . $_SERVER["HTTP_USER_AGENT"];
-
- $end_time = explode (" ", microtime());
- $end_time = $end_time[1] + $end_time[0];
-
- $log[] = "Query completed in: " . number_format (1000*($end_time - $start_time), 2) . " milliseconds";
- logRequest($log);
-
- // Done! Return the object containing AWS result
- return $result;
- }
-
- /**
- * Makes a "lite" request to AWS.
- *
- * Products obtained from a lite request are stored in objects of type {@link LiteDetails}, and
- * can contain all the attributes defined in this kind of objects, athough this is not necessarily
- * the case.
- *
- * Although this function can return {@link ProductInfo} or {@link BlendedSearch} objects
- * based on the kind of search you are doing, these objects will only contain {@link LiteDetails}
- * objects, and in no case {@link HeavyDetails} objects.
- *
- * @param string $keywords the use of this paramater may vary depending of the type of search
- * you are making: for a BrowseNode search, it would refer to the desired BrowseNode, in the
- * case of an ASIN serach, it would refer to the desired ASIN, and so on...
- *
- * @param string $searchType one of the search types offered by AWS. Refer to the document
- * {@tutorial manual.search.pkg} for a list of valid search types.
- *
- * @param string $mode an amazOOP category. To learn more about amazOOP categories read the tutorial
- * {@tutorial advanced.categories.pkg}.
- *
- * @param string $locale determines what Amazon site should be queried. Valid locales are:
- * - "us": queries the Amazon.com catalog
- * - "uk": queries the Amazon.co.uk catalog
- * - "jp": queries the Amazon.co.jp catalog
- * - "de": queries the Amazon.de catalog
- *
- * @param integer $page indicates the page of results you want. Each page contains 10 results.
- *
- * @param string $sort indicates what parameter determines the sorting of results. Available sort
- * types are described in document {@tutorial manual.sort.pkg}.
- *
- * @return mixed This function can return one of the following two types, depending on the query
- * made:
- * - {@link ProductInfo}: this is returned by most types of queries. This object contains zero
- * or more {@link LiteDetails} objects. For more information on what types of queries return
- * {@link ProductInfo} objects, read the tutorial {@tutorial manual.search.pkg}.
- *
- * - {@link BlendedSearch}: only Blended searches return this type of object. Each {@link BlendedSearch}
- * object contains zero or more {@link ProductInfo} objects. For more information about Blended searches
- * read the tutorial {@tutorial manual.search.pkg}.
- *
- * @see ProductInfo
- * @see BlendedSearch
- * @see ShoppingCart
- *
- * @tutorial manual.isbn.pkg
- * @tutorial manual.search.pkg
- * @tutorial manual.sort.pkg
- * @tutorial advanced.browsenodes.pkg
- * @tutorial advanced.categories.pkg
- */
- function liteQuery($keywords, $searchType, $mode = "books", $locale = "us", $page = 1, $sort = "Bestselling"){
- return $this->query($keywords, $searchType, $mode, $locale, "lite", $page, $sort);
- }
-
- /**
- * Makes a "heavy" request to AWS.
- *
- * Products obtained from a heavy request are stored in objects of type {@link HeavyDetails}, and
- * can contain all the attributes defined in this kind of objects, athough this is not necessarily
- * the case.
- *
- * Although this function can return {@link ProductInfo} or {@link BlendedSearch} objects
- * based on the kind of search you are doing, these objects will only contain {@link HeavyDetails}
- * objects, and in no case {@link LiteDetails} objects.
- *
- * @param string $keywords the use of this paramater may vary depending of the type of search
- * you are making: for a BrowseNode search, it would refer to the desired BrowseNode, in the
- * case of an ASIN serach, it would refer to the desired ASIN, and so on...
- *
- * @param string $searchType one of the search types offered by AWS. Refer to the document
- * {@tutorial manual.search.pkg} for a list of valid search types.
- *
- * @param string $mode an amazOOP category. To learn more about amazOOP categories read the tutorial
- * {@tutorial advanced.categories.pkg}.
- *
- * @param string $locale determines what Amazon site should be queried. Valid locales are:
- * - "us": queries the Amazon.com catalog
- * - "uk": queries the Amazon.co.uk catalog
- * - "jp": queries the Amazon.co.jp catalog
- * - "de": queries the Amazon.de catalog
- *
- * @param integer $page indicates the page of results you want. Each page contains 10 results.
- *
- * @param string $sort indicates what parameter determines the sorting of results. Available sort
- * types are described in document {@tutorial manual.sort.pkg}.
- *
- * @return mixed This function can return one of the following two types, depending on the query
- * made:
- * - {@link ProductInfo}: this is returned by most types of queries. This object contains zero
- * or more {@link HeavyDetails} objects. For more information on what types of queries return
- * {@link ProductInfo} objects, read the tutorial {@tutorial manual.search.pkg}.
- *
- * - {@link BlendedSearch}: only Blended searches return this type of object. Each {@link BlendedSearch}
- * object contains zero or more {@link ProductInfo} objects. For more information about Blended searches
- * read the tutorial {@tutorial manual.search.pkg}.
- *
- * @see ProductInfo
- * @see BlendedSearch
- * @see ShoppingCart
- *
- * @tutorial manual.asin.pkg
- * @tutorial manual.search.pkg
- * @tutorial manual.sort.pkg
- * @tutorial advanced.browsenodes.pkg
- * @tutorial advanced.categories.pkg
- */
- function heavyQuery($keywords, $searchType, $mode = "books", $locale = "us", $page = 1, $sort = "Bestselling"){
- return $this->query($keywords, $searchType, $mode, $locale, "heavy", $page, $sort);
- }
-
-
- /**
- * Generates an RSS 2.0 feed for a Browse Node from Amazon.
- *
- * You should read the tutorial
- *
- * <b>WARNING!!!</b> This is an experimental feature. Use it, tweak it, and send feedback!!!
- *
- * @param string $browseNode a browse node from Amazon. Not all Amazon browse nodes will return
- * information. Take a look at
- * {@link http://www.amazon.com/gp/browse.html/ref=sc_bb_l_0/?%5Fencoding=UTF8&node=3434651&no=3435361&me=A36L942TSJ2AJA#browse this document}
- * for more info
- * @param string $mode one of the modes proposed by AWS. The names were simplified, an array in
- * {@link config.inc.php} holds the associations.
- * @param string $locale determines what Amazon site should be queried. {@link config.inc.php}
- * contains an array of available locales.
- *
- * @return string The XML document containing the RSS feed.
- *
- * @link http://www.amazon.com/gp/aws/landing.html AWS SDK
- * @link http://backend.userland.com/rss RSS 2.0
- *
- * @modified 2004-05-21 10:04
- */
- function rssFeed($browseNode, $mode = "books", $locale = "us", $page = 1){
- global $_AMAZOOP_RSS, $_AMAZOOP_SEARCH_TYPES;
-
- $searchType = "BrowseNode";
- $type = "heavy";
- $sortType = "+salesrank";
-
- $signature = $browseNode . "," . $_AMAZOOP_SEARCH_TYPES[$searchType] . "," . $mode . "," . $type . "," . $page . "," . $sortType . "," . $locale . ",rss";
- $cached = false;
- $xml = "";
-
- if($cachedResult = $this->verifyQueryInCache($signature, "day", true)){
- $xml = $cachedResult;
- $cached = true;
- }
- else{
- $itemTag = false;
- $item = array();
- $res = array();
-
- $exten = array( "us" => "com",
- "uk" => "co.uk",
- "de" => "de",
- "fr" => "fr",
- "jp" => "co.jp");
-
- $amazonURL = "http://www.amazon." . $exten[$locale] . "/exec/obidos/tg/browse/-/". $browseNode;
-
- $amazonTitle = "";
- $append = false;
-
- $ifp = fopen($amazonURL, 'r');
-
- while($line = fgets($ifp)){
- if(!(strpos($line, "<title>") === false))
- $append = true;
-
- if($append)
- $amazonTitle .= trim($line);
-
- if(!(strpos($line, "</title>") === false))
- break;
- }
- fclose($ifp);
-
- $amazonTitle = preg_replace("/.*\<title\>/", "", $amazonTitle);
- $amazonTitle = preg_replace("/\<\/title\>.*/", "", $amazonTitle);
- $amazonTitle = htmlentities($amazonTitle);
-
- if($locale == "jp")
- $amazonTitle = explode("co.jp", $amazonTitle);
- else
- $amazonTitle = explode(":", $amazonTitle);
-
- $amazonTitle[1] = explode("/", $amazonTitle[1]);
-
- $feedTitle = "";
- for($i = 0; $i < sizeof($amazonTitle[1]); $i++){
- $feedTitle .= $amazonTitle[1][$i];
- if($i < sizeof($amazonTitle[1]) - 1)
- $feedTitle .= " > ";
- }
-
- $_AMAZOOP_RSS['title'] .= "Bestselling " . $feedTitle;
- $_AMAZOOP_RSS['description'] .= "Bestselling " . $feedTitle . " provided by The Madd0 Mall in association with " . $amazonTitle[0];
-
- //$result = $this->query($browseNode, $searchType, $mode, $locale, $type);
- $result = $this->getBrowseNode($browseNode, $mode, $locale, $type);
-
- $fp = fopen(getAmazoopConfig('XML_template'), 'r');
-
- while($line = fgets($fp)){
- if(preg_match("/%.*%/", $line)){
- $tag = trim(preg_replace("/(%)(.*)(%)/e", "handleTag('$2', \$locale)", $line));
- if($tag != "stop" && $tag != "resume" && !$itemTag){
- $res[] = $tag;
- }
- else if($tag == "stop")
- $itemTag = !$itemTag;
- else if($tag == "resume"){
- $itemTag = !$itemTag;
- $i = 0;
- while($details = $result->getDetails($i)){
- foreach($item as $itemTemplate){
- if(preg_match("/%.*%/", $itemTemplate)){
- $tag = trim(preg_replace("/(%)(.*)(%)/e", "handleTag('$2', \$locale, \$details)", $itemTemplate));
- $res[] = $tag;
- }
- else
- $res[] = trim($itemTemplate);
- }
- $i++;
- }
- }
- else{
- $item[] = $line;
- }
- }
- else if(!$itemTag)
- $res[] = trim($line);
- else
- $item[] = $line;
- }
-
- fclose($fp);
-
- foreach($res as $line)
- $xml .= $line . "\n";
-
- $this->makeFile($xml, $signature, true);
- }
-
- $this->removeOldEntries(getAmazoopConfig('cache_directory'), 'day');
-
- $log = array();
- if($cached)
- $log[0] = "From cache: ";
- else
- $log[0] = "Requested: ";
- $log[0] .= $signature;
- //$log[1] = "Request ID: " . trim($result->request->args['REQUESTID']);
- logRequest($log);
-
- return $xml;
- }
-
-
-
- /**
- *
- * Checks whether the query that is about to be made already exists in the cache.
- * If the file exists, it checks whether it is necessary to refresh it or not based
- * on the {@link $cacheRefreshTime} specified in {@link config.inc.php}.
- * If the query has been made but needs to be refreshed, the file is deleted.
- *
- * @param string $query a string automatically generated by AmazonQuery with the
- * necessary information to verify whether a query has already been made.
- * @param string $expDate the time after which the stored information expires.
- * Possible values are "hour", "day", "week", "month"
- * @param boolean $rss indicates whether the file stored is an RSS feed
- *
- * @return ProductInfo|BlendedSearch|booleanThis function returns the cached object
- * or false if the query is not cached or needs to be refreshed.
- *
- * @see config.inc.php
- *
- * @access private
- */
- function verifyQueryInCache($query, $expDate = "hour", $rss = false){
- /**
- * These are times you can choose from to keep information in the cache.
- * According to AWS license some information can be stored up to 3 months,
- * but pricing and availability has to be refreshed hourly. Since to get
- * this information you have to get it all anyway, it's better to refresh
- * the whole thing hourly.
- */
- $cacheRefreshTime = array('hour' => 3600,
- 'day' => 86400,
- 'week' => 604800,
- 'month' => 18144000);
-
- $cacheDir = getAmazoopConfig('cache_directory');
-
- if(getAmazoopConfig('file_separator') == "windows")
- $fileSeparator = "\\";
- else
- $fileSeparator = "/";
-
- if(!$rss)
- $ext = ".aoc";
- else
- $ext = ".arc";
-
- // Generates the file name
- $fileName = $cacheDir . $fileSeparator . md5($query) . $ext;
-
- // Checks whether the file exists (i.e. the query has been made)
- if(file_exists($fileName)){
- // If the query has been made it checks whether it is still valid
- if(time() - filectime($fileName) <= $cacheRefreshTime[$expDate]){
- // If it is, it opens the file
- $fp = fopen($fileName, "r");
- // Gets the object's size
- $size = (int)fread($fp,5);
- // Goes to the end of the object
- fseek($fp, $size, SEEK_CUR);
- // Reads the query that was stored with the object
- $cacheQuery = fread($fp, 1024);
-
- // Checks whether it corresponds to the query you are making
- if($query == $cacheQuery){
- // If it does, it reads the object
- fseek($fp, 5);
- $object = fread($fp, $size);
- // Closes the file
- fclose($fp);
- // And returns the object
- if(!$rss)
- return unserialize($object);
- else
- return $object;
- }
- else{
- // If it doesn't, it closes the file
- fclose($fp);
- // It deletes it
- unlink($fileName);
- }
- }
- else{
- // If the file is no longer valid it is deleted
- unlink($fileName);
- }
- }
-
- // False is returned, i.e. the query was not cached or was no longer valid
- return false;
- }
-
- /**
- * Removes files from cache that are older than {@link $cacheRefreshTime}
- *
- * @param string $dirPath directory where files should be looked for
- * @param string $expDate the time after which the stored information expires.
- * Possible values are "hour", "day", "week", "month"
- * @param string $ext the extention of the files that should be checked
- *
- * @access private
- */
- function removeOldEntries($dirPath, $expDate = 'hour', $ext = ".aoc"){
- $cacheRefreshTime = array('hour' => 3600,
- 'day' => 86400,
- 'week' => 604800,
- 'month' => 18144000);
-
- if(getAmazoopConfig('file_separator') == "windows")
- $fileSeparator = "\\";
- else
- $fileSeparator = "/";
-
- $dir = opendir($dirPath) or
- die ("Could not open directory \"" . $dirPath . "\"");
- while ($file = readdir($dir))
- if ($file != "." && $file != ".." && strstr($file, $ext)){
- $completePath = $dirPath . $fileSeparator . trim($file);
- if(file_exists($completePath) &&
- (time() - filectime($completePath) > $cacheRefreshTime[$expDate]))
- unlink($completePath);
- }
- closedir($dir);
- }
-
- /**
- * Creates a file as follows:
- * - 5 bytes containing the size of the serialized object
- * - the serialized object
- * - the query made to AWS.
- *
- * @param object $object the object to be stored
- * @param string $query a string automatically generated by AmazonQuery with the necessary information
- * to verify whether a query has already been made.
- * @param boolean $rss indicates whether the file stored is an RSS feed
- *
- * @access private
- */
- function makeFile($object, $query, $rss = false){
-
- $cacheDir = getAmazoopConfig('cache_directory');
-
- if(getAmazoopConfig('file_separator') == "windows")
- $fileSeparator = "\\";
- else
- $fileSeparator = "/";
-
- if(!$rss)
- $ext = ".aoc";
- else
- $ext = ".arc";
-
- // Creates the file's name by hashing the query
- $fileName = $cacheDir . $fileSeparator . md5($query) . $ext;
-
- // Creates the new file
- $fp = fopen($fileName, "w");
-
- if(!$rss)
- // Seralizes the object
- $string = serialize($object);
- else
- $string = $object;
- // Obtains it size long of 5 bytes
- $size = $this->make5Bytes(strlen($string));
- // Writes the size
- fwrite($fp, $size);
- // Writes the object
- fwrite($fp, $string);
- // Writes th query
- fwrite($fp, $query);
- // Closes the file
- fclose($fp);
- }
-
- /**
- * Adds 0s to the left of $number to make it 5 bytes long
- *
- * @param integer $number the number to be treated
- *
- * @return string A number with enough 0 to the left to make it 5 bytes long.
- *
- * @access private
- */
- function make5Bytes($number){
- if($number < 10)
- $number = "0000" . $number;
- else if($number < 100)
- $number = "000" . $number;
- else if($number < 1000)
- $number = "00" . $number;
- else if($number < 10000)
- $number = "0" . $number;
- else
- $number = "". $number;
-
- return $number;
- }
-
- /**
- * Depending on the type of search made, a mode may be needed. Also, certain searches
- * don't make sense with certain nodes (e.g. search for an Actor in books) and modes
- * have different names in different locales.
- *
- * This function verifies that the requested amazOOP node makes sense with the requested search
- * type and converts it to a proper AWS node.
- *
- * @param string $currMode the requested mode
- * @param string $searchType the requested search
- * @param string $locale the locale used
- *
- * @return string The string tobe appended to the AWS request containing a mode that makes sense
- * with the search type used.
- *
- * @link http://www.amazon.com/gp/aws/landing.html AWS SDK
- * @see config.inc.php
- *
- * @access private
- */
- function getRequestMode($currMode, $searchType, $locale){
- // Changes the amazOOP mode into an AWS mode
- if(!($currMode = getMode($locale, $currMode)))
- return false;
-
- // These search types don't need a mode
- if($searchType == "ASIN" || $searchType == "ISBN"
- || $searchType == "Blended"
- || $searchType == "Power")
- // So blank is returned
- return "";
-
- // These search types make sense with any mode
- else if($searchType == "BrowseNode" || $searchType == "Keywords"
- || $searchType == "Similarity")
- // So it is assumed that the original mode is alright
- return "&mode=" . $currMode;
-
- // These search type only make sense when looking for books
- else if($searchType == "Author" || $searchType == "Publisher"){
- if(strpos($currMode, "books") === false)
- // So if a movie mode was not selected, the default value is returned
- return "&mode=books";
- else
- // Otherwise return what was requested
- return "&mode=" . $currMode;
- }
-
- // These search types only make sense when lookin for movies
- else if($searchType == "Actor" || $searchType == "Director"){
- if(strpos($currMode, "dvd") === false &&
- strpos($currMode, "vhs") === false &&
- strpos($currMode, "video") === false)
- // So if a movie mode was not selected, the default value is returned
- return "&mode=dvd";
- else
- // Otherwise return what was requested
- return "&mode=" . $currMode;
- }
-
- // These serach types only make sense when looking in music
- else if($searchType == "Artist" || $searchType == "UPC"){
- if(strpos($currMode, "music") === false &&
- strpos($currMode, "classical") === false)
- // So if a music mode was not selected, the default value is returned
- return "&mode=music";
- else
- // Otherwise return what was requested
- return "&mode=" . $currMode;
- }
-
- // These seach type only makes sense in certain modes
- else if($searchType == "Manufacturer"){
- if(strpos($currMode, "ce") === false &&
- strpos($currMode, "electronics") === false &&
- strpos($currMode, "kitchen") === false &&
- strpos($currMode, "videogames") === false &&
- strpos($currMode, "software") === false &&
- strpos($currMode, "photo") === false &&
- strpos($currMode, "pc-hardware") === false)
- // If none of them is selected, the default value is returned
- return "&mode=electronics";
- else
- // Otherwise return what was requested
- return "&mode=" . $currMode;
- }
-
- }
-
- /**
- * A variant of {@link query()} used specifically to query a
- * {@tutorial manual.cart.pkg Remote Shopping Cart}.
- *
- * Like {@link query()}, this is a "low-level" function, therefore most users will prefer to
- * use the {@tutorial manual.cart.pkg Remote Shopping Cart} with {@link newCart()},
- * {@link addToCart()}, {@link modifyCart}, {@link removeFromCart()}, {@link clearCart()}
- * and {@link getCart()}.
- *
- * @param string $action The action you want to perform with a Shopping Cart. Valid values are:
- * - "add": adds items to a shopping cart, or creates a new shopping cart if none is provided
- * - "modify": modifies the quantity of an item in the shopping cart
- * - "remove": removes an item from the shopping cart
- * - "clear": clears a shopping cart
- * - "get": retrieves the items from a shopping cart
- *
- * @param array $items This can be a simple or a bi-dimensional array. It is simple if you want to
- * remove items from a shopping cart, in which case this is simply an array of Item IDs. But it is
- * a bi-dimensional array if you want to add or modify items in a shopping cart. In this case each
- * item of the array is another array containing an ASIN (if you are adding a product), or an Item ID
- * (if you are modifying the cart), and the desired quantity of this product.
- *
- * @param string $locale The Amazon site in which the cart is stored.
- *
- * @param string $cartID The Cart ID is the unique identifier for a given shopping cart.
- *
- * @param string $HMAC The HMAC is a security token that must be passed back to Amazon Web Services
- * for using an existing cart. This token is uniquely associated with each cart.
- *
- * @param boolean $similar If this parameter is set to "true" (default) the {@link ShoppingCart}
- * Shopping Cart} will contain a list of ASINs related to the objects it contains.
- *
- * @return ShoppingCart Unlike {@link query()}, this function only returns objects of type {@link }
- * ShoppingCart}. Read the tutorial {@tutorial manual.cart.pkg} for more information about
- * Remote Shoppng Carts.
- *
- * @see ShoppingCart
- *
- * @tutorial manual.cart.pkg
- */
- function queryRemoteShoppingCart($action = "get", $items = "", $locale = "us", $cartID = "", $HMAC = "", $similar = true){
- global $_AMAZOOP_SEARCH_TYPES, $_AMAZOOP_SITES;
-
- $start_time = explode(" ", microtime());
- $start_time = $start_time[1] + $start_time[0];
-
- // build a request to send to AWS using provided data
- $request = $_AMAZOOP_SITES[$locale];
- $request .= "&t=" . getAssociateID($locale);
- $request .= "&dev-t=" . _AMAZOOP_DEV_TOKEN;
- $request .= "&ShoppingCart=" . $action;
-
- if($action == "add"){
- foreach($items as $item)
- $request .= "&Asin." . $item[0] . "=" . $item[1];
- }
- elseif($action == "modify"){
- foreach($items as $item)
- $request .= "&Item." . $item[0] . "=" . $item[1];
- }
- elseif($action == "remove"){
- foreach($items as $item)
- $request .= "&Item." . $item;
- }
-
- if($action != "add" && ($cartID == "" || $HMAC == "")){
- $error = "You MUST specify a CartID AND a HMAC for any action other than \"add\"";
- $error .= "; You tried to \"" . $action . "\"";
- trigger_error($error);
- return false;
- }
-
- if($cartID != "")
- $request .= "&CartId=" . $cartID;
- if($HMAC != "")
- $request .= "&Hmac=" . $HMAC;
-
- if($similar)
- $request .= "&sims=true";
-
- // Create a new AmazonParser to parse AWS info
- $amazonParser = new AmazonParser();
-
- // Parse request and obtain new object based on AWS response
- $result = $amazonParser->parse($request);
-
- unset($amazonParser);
-
-
- // If for some reason parsing failed, try again...
- //while(!is_object($result))
- // $result = $amazonParser->parse($request, $type);
- if(!$result || !is_object($result)){
- $error = "Amazon did not return data when queried for: ";
- $error .= $request;
- $error .= "; I will try again";
- trigger_error($error);
- sleep(1);
- $amazonParser = new AmazonParser();
- $result = $amazonParser->parse($request);
- }
- elseif($result->getErrorMessage()){
- $error = "Data was obtained from Amazon, but contained an error: ";
- $error .= $result->getErrorMessage();
- $error .= "; request was: " . $request . "; and Request ID was: " . rawurldecode($result->requestArgument('REQUESTID'));
- trigger_error($error);
- sleep(1);
- $amazonParser = new AmazonParser();
- $result = $amazonParser->parse($request);
- }
-
- $log = array();
- $log[] = "Requested: " . $request;
- if($result)
- $log[] = "Request ID: " . trim($result->requestArgument('RequestId'));
- $log[] = "Remote IP: " . $_SERVER["REMOTE_ADDR"];
- if(isset($_SERVER["HTTP_USER_AGENT"]))
- $log[] = "User Agent: " . $_SERVER["HTTP_USER_AGENT"];
-
- $end_time = explode (" ", microtime());
- $end_time = $end_time[1] + $end_time[0];
-
- $log[] = "Query completed in: " . number_format (1000*($end_time - $start_time), 2) . " milliseconds";
- logRequest($log);
-
- // Done! Return the object containing AWS result
- return $result;
- }
-
- /**
- * Add an item, or a list of items to an new {@link manual.cart.pkg Remote Shopping Cart}.
- *
- * This function is used to add items to an <i>new</i> Remote Shopping Cart. To add items to an
- * existing shopping cart take a look at {@link addToCart()}.
- *
- * You must recover the new cart's ID and HMAC by using methods {@link ShoppingCart::getCartID()}
- * getCartID()} and {@link ShoppingCart::getHMAC() getHMAC()}, in order to modify it using functions
- * {@link addToCart()}, {@link modifyCart}, {@link removeFromCart()}, {@link clearCart()}
- * and {@link getCart()}.
- *
- * <b>Example:</b>
- * <code>
- * $items = array();
- * $items[] = array("B00005JMEW", 1);
- * $items[] = array("1932273271", 2);
- *
- * $cart = $aq->newCart($items, "jp");
- * </code>
- *
- * @param array $items Each element of this array is another array containing the ASIN of the
- * product you wish to add to the cart in position 0, and the quantity in position 1.
- * As of the writing of this document, only US shopping carts support multiple items.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart A new shopping cart containing the items added.
- */
- function newCart($items, $locale = "us", $similar = true){
- return $this->queryRemoteShoppingCart("add", $items, $locale, "", "", $similar);
- }
-
- /**
- * Add an item, or a list of items to an existing {@link manual.cart.pkg Remote Shopping Cart}.
- *
- * This function is used to add items to an <i>existing</i> Remote Shopping Cart. To create a new
- * shopping cart take a look at {@link newCart()}.
- *
- * If you do not provide the $cartID and $HMAC parameters, or if these are
- * equal to a blank string, this function behaves exactly like {@link newCart()}.
- *
- * <b>Example:</b>
- * <code>
- * $items = array();
- * $items[] = array("B00005JMEW", 1);
- * $items[] = array("1932273271", 2);
- *
- * $cart = $aq->addToCart($items, "us", $_SESSION['cartID'], $_SESSION['HMAC']);
- * </code>
- *
- * @param array $items Each element of this array is another array containing the ASIN of the
- * product you wish to add to the cart in position 0, and the quantity in position 1.
- * As of the writing of this document, only US shopping carts support multiple items.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param string $cartID The unique ID of the cart you whish to add items to. You can find the
- * cart ID of a {@link ShoppingCart} object using its {@link ShoppingCart::getCartID() getCartID()} method.
- *
- * @param string $HMAC A unique code associated to a Remote Shopping Cart.You can find the
- * HMAC of a {@link ShoppingCart} object using its {@link ShoppingCart::getHMAC() getHMAC()} method.
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart A shopping cart containing the items added, plus any other items already
- * in it.
- */
- function addToCart($items, $locale = "us", $cartID = "", $HMAC = "", $similar = true){
- return $this->queryRemoteShoppingCart("add", $items, $locale, $cartID, $HMAC, $similar);
- }
-
- /**
- * Modifies the quantities of items in an existing {@link manual.cart.pkg Remote Shopping Cart}.
- *
- * This function is used to modify the quantities of items you have <i>already added</i> to a
- * Remote Shopping Cart. To create a add new items to a cart take a look at {@link addToCart()}.
- *
- * You must provide an array of items to be modified. This array must contain Item IDs of products
- * already in the shopping cart, associated with their new quantities.
- *
- * <b>Example:</b>
- * <code>
- * $noOfModItems = $_POST['noOfItems'];
- * $items = array();
- *
- * for($i = 0; $i < $noOfModItems; $i++)
- * $items[] = array($_POST['itemID'.$i], $_POST['qty'.$i]);
- *
- * $cart = $aq->modifyCart($items, "us", $_POST['cartID'], $_POST['HMAC']);
- * </code>
- *
- * @param array $items Each element of this array is another array containing the Item ID of a
- * product in the cart in position 0, and the new quantity in position 1.
- * As of the writing of this document, only US shopping carts support multiple items.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param string $cartID The unique ID of the cart you whish to add items to. You can find the
- * cart ID of a {@link ShoppingCart} object using its {@link ShoppingCart::getCartID() getCartID()} method.
- *
- * @param string $HMAC A unique code associated to a Remote Shopping Cart.You can find the
- * HMAC of a {@link ShoppingCart} object using its {@link ShoppingCart::getHMAC() getHMAC()} method.
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart A shopping cart containing the modified items, plus any other items already
- * in it.
- */
- function modifyCart($items, $locale = "us", $cartID = "", $HMAC = "", $similar = true){
- return $this->queryRemoteShoppingCart("modify", $items, $locale, $cartID, $HMAC, $similar);
- }
-
- /**
- * Removes items from an existing {@link manual.cart.pkg Remote Shopping Cart}.
- *
- * You must provide an array of items to be removed. This array must contain Item IDs of the products
- * you wish to remove from the shopping cart.
- *
- * <b>Example:</b>
- * <code>
- * $items = array();
- *
- * for($i = 0; $i < $_POST['noOfItems']; $i++)
- * $items[] = $_POST['itemID'.$i];
- *
- * $cart = $aq->removeFromCart($items, "us", $_POST['cartID'], $_POST['HMAC']);
- * </code>
- *
- * @param array $items Each element of this array is an Item ID of a
- * product in the cart.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param string $cartID The unique ID of the cart you whish to add items to. You can find the
- * cart ID of a {@link ShoppingCart} object using its {@link ShoppingCart::getCartID() getCartID()} method.
- *
- * @param string $HMAC A unique code associated to a Remote Shopping Cart.You can find the
- * HMAC of a {@link ShoppingCart} object using its {@link ShoppingCart::getHMAC() getHMAC()} method.
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart A shopping cart without the removed items.
- */
- function removeFromCart($items, $locale = "us", $cartID = "", $HMAC = "", $similar = true){
- return $this->queryRemoteShoppingCart("remove", $items, $locale, $cartID, $HMAC, $similar);
- }
-
- /**
- * Retrieve the contents of an existing {@link manual.cart.pkg Remote Shopping Cart}.
- *
- * This function is used to retrieve an <i>existing</i> Remote Shopping Cart. Note that every other
- * action ({@link newCart() new}, {@link addToCart() add}, {@link modifyCart() modify}, {@link }
- * removeFromCart() remove} and {@link clearCart() clear}) will also return the contents from the
- * cart, therefore you only need to use this function if you want to retrieve a cart without mofifying it.
- *
- * <b>Example:</b>
- * <code>
- * $cart = $aq->getCart($_COOKIE['cartID'], $_COOKIE['HMAC'], "de");
- * </code>
- *
- * @param string $cartID The unique ID of the cart you whish to add items to. You can find the
- * cart ID of a {@link ShoppingCart} object using its {@link ShoppingCart::getCartID() getCartID()} method.
- *
- * @param string $HMAC A unique code associated to a Remote Shopping Cart.You can find the
- * HMAC of a {@link ShoppingCart} object using its {@link ShoppingCart::getHMAC() getHMAC()} method.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart A the contents of the requested shopping cart.
- */
- function getCart($cartID, $HMAC, $locale = "us", $similar = true){
- return $this->queryRemoteShoppingCart("get", "", $locale, $cartID, $HMAC, $similar);
- }
-
- /**
- * Clears a {@tutorial manual.cart.pkg Remote Shopping Cart}.
- *
- * @param string $cartID The unique identifier of the cart you want to clear.
- *
- * @param string $HMAC A unique code associated to the cart ID.
- *
- * @param string $locale The locale where the Remote Shopping Cart is stored. Valid values
- * are:
- * - "us"
- * - "uk"
- * - "de"
- * - "jp"
- *
- * @param boolean $similar If set to "true", the {@link ShoppingCart} object returned will contain
- * a list of ASINs related to the contents of the cart.
- *
- * @return ShoppingCart An empty shopping cart.
- */
- function clearCart($cartID, $HMAC, $locale = "us", $similar = true){
- return $this->queryRemoteShoppingCart("clear", "", $locale, $cartID, $HMAC, $similar);
- }
- }
- ?>