757 Solution Overview This is nothing new.The safeString() function is in the utilityfunctions.php file. It simply removes any non-alphanumeric characters from the input string via a regular expression replacement. Because we have covered this before, we have not included it here in the text. The main reason that we need to validate input in this application is that we use the customer’s input to create file names in the cache.We could run into serious problems if we allow customers to include or / in their input. Next we set up the customer’s shopping cart, if she does not already have one: if(!isset($HTTP_SESSION_VARS['cart'])) { session_register('cart'); $HTTP_SESSION_VARS['cart'] = array(); } We have a few last things to do before we can display the information in the top infor- mation bar on the page (see Figure 31.1 for a reminder of what this looks like). A glimpse of the shopping cart is shown in the top bar of every page. It is therefore impor- tant that the cart variable is up to date before this is displayed. // tasks that need to be done before the top bar is shown if($action == 'addtocart') addToCart($HTTP_SESSION_VARS['cart'], $ASIN, $mode); if($action == 'deletefromcart') deleteFromCart($HTTP_SESSION_VARS['cart'], $ASIN); if($action == 'emptycart') $HTTP_SESSION_VARS['cart'] = array(); Here we are adding or deleting items from the cart as necessary before displaying the cart.We will come back to these functions when we discuss the shopping cart and checking out. If you want to look at them now, they are in the file cartfunctions.php. We are leaving them aside for a minute, because we need to understand the interface to Amazon first. Next, we include the file topbar.php. This file simply contains HTML and a style sheet and a single function call to the ShowSmallCart() function (from cartfunctions.php).This displays the small shopping cart summary you can see in the top right-hand corner of the figures.We will come back to this when we discuss the cart functions. Finally, we come to the main event-handling loop. A summary of the possible actions is shown in Table 31.2. Table 31.2 Possible Actions in the Main Event Loop Action Description browsenode Show books in the specified category.This is the default action. detail Show the details of one particular book. 37 525x ch31 1/24/03 3:35 PM Page 757 758 Chapter 31 Connecting to Web Services with XML and SOAP image Show a large version of the book’s cover. search Show the results of a user search. addtocart Add an item to the user’s shopping cart. deletefromcart Delete an item from the shopping cart. emptycart Empty the shopping cart altogether. showcart Show the contents of the cart. As you can see, the first four actions in this table relate to retrieving and displaying infor- mation from Amazon.The second group of four deal with managing the shopping cart. The actions that retrieve data from Amazon all work in a quite similar way.We will consider retrieving data about books in a particular browsenode (category) as an example. Showing Books in a Category The code that is executed when the action is browsenode (view a category) is as fol- lows: showCategories($mode); $category = getCategoryName($browseNode); if(!$category||$category=='Best Selling Books') { echo '<h1>Current Best Sellers</h1>'; } else { echo "<h1>Current Best Sellers in $category</h1>"; } showBrowseNode($browseNode, $page, $mode); The showCategories() function displays the list of selected categories we see near the top of most of the pages.The getCategoryName() function returns the name of the cur- rent category given its browsenode number.The showBrowseNode() function displays a page of books in that category. Let’s begin by considering the showCategories() function.The code for this func- tion is shown in Listing 31.5. Listing 31.5 showCategories() Function from categoryfunctions.php—A List of Categories //display a starting list of popular categories function showCategories($mode) { global $categoryList; Table 31.2 Continued Action Description 37 525x ch31 1/24/03 3:35 PM Page 758 759 Solution Overview echo '<hr /><h2>Selected Categories</h2>'; if($mode == 'books') { asort($categoryList); $categories = count($categoryList); $columns = 4; $rows = ceil($categories/$columns); echo '<table border ="0" cellpadding ="0" cellspacing="0" width ="100%"><tr>'; reset($categoryList); for($col = 0; $col<$columns; $col++) { echo '<td width = "'.(100/$columns).'%" valign = "top"><ul>'; for($row = 0; $row<$rows; $row++) { $category = each($categoryList); if($category) { $browseNode = $category['key']; $name = $category['value']; echo "<li><span class = 'category'><a href = 'index.php?action=browsnode&browseNode=$browseNode'>$name </a></span></li>"; } } echo '</ul></td>'; } echo '</tr></table><hr />'; } } This function uses an array called categoryList, declared in the categoryfunctions.php package, to map browsenode numbers to names.The desired browsenodes are simply hard-coded into this array.This function sorts the array and dis- plays the various categories. The getCategoryName() function that is called next in the main event loop is used to look up the name of the browsenode that we are currently looking at so we can dis- play a heading on the screen such as Current Best Sellers in Business & Investing. It looks this up in the categoryList array mentioned previously. Listing 31.5 Continued 37 525x ch31 1/24/03 3:35 PM Page 759 760 Chapter 31 Connecting to Web Services with XML and SOAP The fun really starts when we get to the showBrowseNode() function.This function is shown in Listing 31.6. Listing 31.6 showBrowseNode() Function from bookdisplayfunctions.php—A List of Categories // For a particular browsenode, display a page of products function showBrowseNode($browseNode, $page, $mode) { $ars = getARS('browse', array('browsenode'=>$browseNode, 'page' => $page, 'mode'=>$mode)); showSummary($ars->products(), $page, $ars->totalResults(), $mode, $browseNode); } This function does exactly two things. First, it calls the getARS() function from cache- functions.php.This function gets and returns an AmazonResultSet object (more on this in a moment).Then it calls the showSummary() function from bookdisplayfunc- tions.php to display the retrieved information. The getARS() function is absolutely key to driving the whole application. If we work our way through the code for the other actions—viewing details, images, and search- ing—we will find that it all comes back to this. Getting an AmazonResultSet Let’s look at that getARS() function in more detail. It is shown in Listing 31.7. Listing 31.7 getARS() Function from cachefunctions.php—A Resultset for a Query // Get an AmazonResultSet either from cache or a live query // If a live query add it to the cache function getARS($type, $parameters) { $cache = cached($type, $parameters); if($cache) // if found in cache { return $cache; } else { $ars = new AmazonResultSet; if($type == 'asin') $ars->ASINSearch(padASIN($parameters['asin']), $parameters['mode']); if($type == 'browse') $ars->browseNodeSearch($parameters['browsenode'], 37 525x ch31 1/24/03 3:35 PM Page 760 761 Solution Overview $parameters['page'], $parameters['mode']); if($type == 'search') $ars->keywordSearch($parameters['search'], $parameters['page'], $parameters['mode']); cache($type, $parameters, $ars); } return $ars; } This function is designed to drive the process of getting data from Amazon. It can do this in two ways: either from the cache, or live from Amazon. Because Amazon requires developers to cache downloaded data, the function first looks for data in the cache.We will discuss the cache in a few pages. If we have not already performed this particular query, the data must be fetched live from Amazon.We do this by creating an instance of the AmazonResultSet class and call- ing the method on it that corresponds to the particular query we want to run.The type of query is determined by the $type parameter. In the category (or browse node) search example, we pass in browse as the value for this parameter—refer to Listing 31.6. If we want to perform a query about one particular book, we should pass in the value asin, and if we want to perform a keyword search, the parameter should be set to search. Each of these parameters invokes a different method on the AmazonResultSet class. The individual item search calls the ASINSearch() method.The category search calls the browseNodeSearch() method.The keyword search calls the keywordSearch() method. Let’s take a closer look at the AmazonResultSet class.The full code for this class is shown in Listing 31.8. Listing 31.8 AmazonResultSet.php—A Class for Handling Amazon Connections <?php require_once('Product.php'); // you can switch between XML/HTTP and SOAP using this constant set in // constants.php if(METHOD=='SOAP') { include_once('nusoap/nusoap.php'); } // This class stores the result of queries // Usually this is 1 or 10 instances of the Product class class AmazonResultSet { Listing 31.7 Continued 37 525x ch31 1/24/03 3:35 PM Page 761 . AmazonResultSet .php A Class for Handling Amazon Connections < ?php require_once('Product .php& apos;); // you can switch between XML/HTTP and SOAP using this constant set in // constants .php if(METHOD=='SOAP') { include_once('nusoap/nusoap .php& apos;); } //. summary you can see in the top right-hand corner of the figures.We will come back to this when we discuss the cart functions. Finally, we come to the main event-handling loop. A summary of the possible. the categoryfunctions .php package, to map browsenode numbers to names.The desired browsenodes are simply hard-coded into this array.This function sorts the array and dis- plays the various categories. The