www.gibmonks.com

Main Page




Previous Page
Next Page

[Page 954 (continued)]

19.16. Case Study: Shopping Cart

Many businesses' Web sites contain shopping-cart applications, which allow customers to buy items conveniently on the Web. The sites record what the consumer wants to purchase and provide an easy, intuitive way to shop online. They do so by using an electronic shopping cart, just as people would use physical shopping carts in retail stores. As users add items to their shopping carts, the sites update the carts' contents. When users "check out," they pay for the items in their shopping carts. To see a real-world electronic shopping cart, we suggest going to the online bookstore Amazon.com (www.amazon.com).

The shopping cart implemented in this section (Figs. 19.2119.24) allows users to purchase books from a fictitious bookstore that sells four books (see Fig. 19.23). This example uses four scripts, two server-side files and cookies.

Figure 19.21. Program that outputs a login page.
(This item is displayed on pages 954 - 959 in the print version)

 1   // Fig. 19.21: login.cpp
 2   // Program to output an XHTML form, verify the
 3   // username and password entered, and add members.
 4   #include <iostream>
 5   using std::cerr;
 6   using std::cin;
 7   using std::cout;
 8   using std::ios;
 9
10   #include <fstream>
11   using std::fstream;
12
13   #include <string>
14   using std::string;
15
16   #include <cstdlib>
17   using std::getenv;
18   using std::atoi;
19   using std::exit;
20
21   void header();
22   void writeCookie();
23
24   int main()
25   {
26      char query[ 1024 ] = "";
27      string dataString = "";
28
29      // strings to store username and password
30      string userName = "";
31      string passWord = "";
32
33      int contentLength = 0;
34      bool newMember = false;
35
36      // data was posted
37      if ( getenv( "CONTENT_LENGTH" ) )
38      {
39         // retrieve query string
40         contentLength = atoi( getenv( "CONTENT_LENGTH" ) );
41         cin.read( query, contentLength );
42         dataString = query;
43
44         // find username location
45         int userLocation = dataString.find( "user=" ) + 5;
46         int endUser = dataString.find( "&" );
47
48         // find password location
49         int passwordLocation = dataString.find( "password=" ) + 9;
50         int endPassword = dataString.find( "&new" );
51
52         if ( endPassword > 0 ) // new membership requested
53         {
54            newMember = true;
55            passWord = dataString.substr(                         
56               passwordLocation, endPassword - passwordLocation );
57         } // end if
58         else // existing member
59            passWord = dataString.substr( passwordLocation );
60
61         userName = dataString.substr(             
62            userLocation, endUser - userLocation );
63      } // end if
64
65      // no data was retrieved
66      if ( dataString == "" )
67      {
68         header();
69         cout << "<p>Please login.</p>";
70
71         // output login form
72         cout << "<form method = \"post\" action = \"/cgi-bin/login.cgi\">"
73            << "<p>User Name: <input type = \"text\" name = \"user\"/><br/>"
74            << "Password: <input type = \"password\" name = \"password\"/>"
75            << "<br/>New? <input type = \"checkbox\" name = \"new\""
76            << " value = \"1\"/></p>"
77            << "<input type = \"submit\" value = \"login\"/></form>";
78      } // end if
79      else // process entered data
80      {
81         string fileUsername = "";
82         string filePassword = "";
83         bool userFound = false;
84    
85         // open user data file for reading and writing        
86         fstream userData( "userdata.txt", ios::in | ios::out);
87    
88         if ( !userData ) // could not open file
89         {
90            cerr << "Could not open database.";
91            exit( 1 );
92         } // end if
93
94         // add new member
95         if ( newMember )
96         {
97            // read username and password from file
98            while ( !userFound && userData >> fileUsername >> filePassword )
99            {
100              if ( userName == fileUsername ) // name is already taken
101                 userFound = true;                                    
102           } // end while
103
104           if ( userFound ) // user name is taken
105           {
106              header();
107              cout << "<p>This name has already been taken.</p>"   
108                 << "<a href=\"/cgi-bin/login.cgi\">Try Again</a>";
109           } // end if
110           else // process data
111           {
112              writeCookie(); // write cookie
113              header();
114
115              // write user data to file                                
116              userData.clear(); // clear eof, allow write at end of file
117              userData << "\n" << userName << "\n" << passWord;         
118
119              cout << "<p>Your information has been processed."            
120                 << "<a href=\"/cgi-bin/shop.cgi\">Start Shopping</a></p>";
121           } // end else
122        } // end if
123        else // search for password if entered
124        {
125           bool authenticated = false;
126
127           // read in user data
128           while ( !userFound && userData >> fileUsername >> filePassword )
129           {
130              // username was found
131              if ( userName == fileUsername )
132              {
133                 userFound = true;
134
135                 // determine whether password is correct     
136                 // and assign bool result to authenticated   
137                 authenticated = ( passWord == filePassword );
138              } // end if
139           } // end while
140
141           // user is authenticated
142           if ( authenticated )
143           {
144              writeCookie();
145              header();
146
147              cout << "<p>Thank you for returning, " << userName << "!</p>"
148                 << "<a href=\"/cgi-bin/shop.cgi\">Start Shopping</a>";    
149           } // end if
150           else // user not authenticated
151           {
152              header();
153
154              if ( userFound ) // password is incorrect
155                 cout << "<p>You have entered an incorrect password. "    
156                    << "Please try again.</p>"                            
157                    << "<a href=\"/cgi-bin/login.cgi\">Back to login</a>";
158              else // user is not registered
159                 cout << "<p>You are not a registered user.</p>"     
160                    << "<a href=\"/cgi-bin/login.cgi\">Register</a>";
161           } // end else
162        } // end else
163     } // end else
164
165     cout << "</body>\n</html>\n";
166     return 0;
167  } // end main
168
169  // function to output header
170  void header()
171  {
172     cout << "Content-Type: text/html\n\n"; // output header
173
174     // output XML declaration and DOCTYPE
175     cout << "<?xml version = \"1.0\"?>"
176        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
177        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
178
179     // output html element and some of its contents
180     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
181        << "<head><title>Login Page</title></head><body>";
182  } // end function header
183
184  // function to write cookie data
185  void writeCookie()
186  {
187     string expires = "Friday, 14-MAY-10 16:00:00 GMT";
188     cout << "Set-Cookie: CART=; expires=" << expires << "; path=\n";
189  } // end function writeCookie

Figure 19.21 shows the first of these scriptsthe login page. This script is the most complex of all the scripts in this section. The first if condition (line 37) determines whether data was posted to the program. The second if condition (line 66) determines whether dataString remains empty (i.e., there was no submitted data to decode or the decoding did not complete successfully). The first time we run this program, the first condition fails and the second condition succeeds, so lines 7277 output an XHTML form to the user, as shown in the first screen capture of Fig. 19.21. When the user fills out the form and clicks the login button, login.cgi is requested againthe request contains posted data this time, so the condition in line 37 evaluates to true and the condition in line 66 evaluates to false.


[Page 959]

[Page 960]

If the user submitted data, program control continues into the else block that begins in line 79, where the script processes the data. Line 86 opens userdata.txtthe file that contains all usernames and passwords for existing members. If the user checked the New checkbox on the Web page to create a new membership, the condition in line 95 evaluates to TRue, and the script attempts to record the user's information in the userdata.txt file on the server. Lines 98102 read through this file, comparing each username with the name entered. If the username already appears in the file, the loop in lines 98102 terminates before reaching the end of the file, and lines 107108 output an appropriate message to the user, and a hyperlink back to the form is provided. If the username entered does not already exist in userdata.txt, line 117 adds the new user information to the file in the format

     Bernard
     blue

Each username and password is separated by a newline character. Lines 119120 provide a hyperlink to the script of Fig. 19.22, which allows users to purchase items.

Figure 19.22. CGI script that allows users to buy a book.
(This item is displayed on pages 961 - 963 in the print version)

 1   // Fig. 19.22: shop.cpp
 2   // Program to display available books.
 3   #include <iostream>
 4   using std::cerr;
 5   using std::cout;
 6   using std::ios;
 7
 8   #include <fstream>
 9   using std::ifstream;
10
11   #include <string>
12   using std::string;
13
14   #include <cstdlib>
15   using std::exit;
16
17   void header();
18
19   int main()
20   {
21      // variables to store product information
22      char book[ 50 ] = "";
23      char year[ 50 ] = "";
24      char isbn[ 50 ] = "";
25      char price[ 50 ] = "";
26    
27      string bookString = "";
28      string yearString = "";
29      string isbnString = "";
30      string priceString = "";
31    
32      ifstream userData( "catalog.txt", ios::in ); // open file for input
33    
34      // file could not be opened
35      if ( !userData )
36      {
37         cerr << "Could not open database.";
38         exit( 1 );
39      } // end if
40    
41      header(); // output header
42    
43      // output available books                                
44      cout << "<center><br/>Books available for sale<br/><br/>"
45         << "<table border = \"1\" cellpadding = \"7\" >";     
46    
47      // file is open
48      while ( userData )
49      {
50         // retrieve data from file
51         userData.getline( book, 50 );
52         bookString = book;
53    
54         userData.getline( year, 50 );
55         yearString = year;
56    
57         userData.getline( isbn, 50 );
58         isbnString = isbn;
59    
60         userData.getline( price, 50 );
61         priceString = price;
62    
63         cout << "<tr><td>" << bookString << "</td><td>" << yearString
64            << "</td><td>" << isbnString << "</td><td>" << priceString
65            << "</td>";
66    
67         // file is still open after reads
68         if ( userData )
69         {
70            // output form with buy button                              
71            cout << "<td><form method=\"post\" "                        
72               << "action=\"/cgi-bin/viewcart.cgi\">"                   
73               << "<input type=\"hidden\" name=\"add\" value=\"true\"/>"
74               << "<input type=\"hidden\" name=\"isbn\" value=\""       
75               << isbnString << "\"/>" << "<input type=\"submit\" "     
76               << "value=\"Add to Cart\"/>\n</form></td>\n";            
77         } // end if
78    
79         cout << "</tr>\n";
80      } // end while
81    
82      cout << "</table></center><br/>"
83         << "<a href=\"/cgi-bin/checkout.cgi\">Check Out</a>"
84         << "</body></html>";
85      return 0;
86   } // end main
87
88   // function to output header information
89   void header()
90   {
91      cout << "Content-Type: text/html\n\n"; // output header
92    
93      // output XML declaration and DOCTYPE
94      cout << "<?xml version = \"1.0\"?>"
95         << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
96         << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
97    
98      // output html element and some of its contents
99      cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
100        << "<head><title>Shop Page</title></head><body>";
101  } // end function header

The last possible scenario for this script is for returning users (lines 123162). This portion of the program executes when the user enters a name and password but does not select the New checkbox (i.e., the else of line 123 is evaluated). In this case, we assume that the user already has a username and password in userdata.txt. Lines 128139 read through userdata.txt in an attempt to locate the username entered. If the username is found (line 131), we determine whether the password entered matches the password stored in the file (line 137). If so, bool variable authenticated is set to true. Otherwise, authenticated remains false. If the user has been authenticated (line 142), line 144 calls function writeCookie to initialize a cookie named CART (line 188), which is used by other scripts to store data indicating which books the user has added to the shopping cart. Note that this cookie replaces any existing cookie of the same name, causing data from prior sessions to be deleted. After creating the cookie, the script outputs a message welcoming the user back to the Web site and providing a link to shop.cgi, where the user can purchase books (lines 147148).

If the user was not authenticated, the program determines why (lines 154160). If the user was found but not authenticated, a message is output indicating that the password is invalid (line 155157). A hyperlink is provided to the login page (<a href="/cgi-bin/login.cgi">), where the user can attempt to login again. If neither the username nor the password was found, an unregistered user has attempted to login. Lines 159160 output a message indicating that the user does not have the proper authorization to access the page and providing a link that allows the user to attempt another login.

Figure 19.22 uses the values in catalog.txt (Fig. 19.25) to output in an XHTML table the items that the user can purchase (lines 4582). The last column for each row includes a button for adding the item to the shopping cart. Lines 6365 output the different values for each book, and lines 7176 output a form containing the submit button for adding each book to the shopping cart. Hidden form fields are specified for each book and its associated information. Note that the resulting XHTML document sent to the client contains several forms, one for each book. However, the user can submit only one form at a time. The name-value pairs of the hidden fields within the submitted form are posted to the viewcart.cgi script.


[Page 963]

When a user purchases a book, the viewcart.cgi script is requested, and the ISBN for the book to be purchased is sent to the script via a hidden form field. Figure 19.23 begins by reading the value of the cookie stored on the user's system (line 35). Any existing cookie data is stored in string cookieString (line 36). The entered ISBN number from the form of Fig. 19.22 is stored in string isbnEntered (line 52). The script then determines whether the cart already contains data (line 61). If not, the cookieString is given the value of the entered ISBN number (line 62). If the cookie already contains data, the entered ISBN is appended to the existing cookie data (line 64). The new book is stored in the CART cookie in lines 6768. Line 84 outputs the cart's contents in a table by calling function displayShoppingCart.

Figure 19.23. CGI script that allows users to view their carts' contents.
(This item is displayed on pages 964 - 967 in the print version)

 1   // Fig. 19.23: viewcart.cpp
 2   // Program to view books in the shopping cart.
 3   #include <iostream>
 4   using std::cerr;
 5   using std::cin;
 6   using std::cout;
 7   using std::ios;
 8
 9   #include <fstream>
10   using std::ifstream;
11
12   #include <string>
13   using std::string;
14
15   #include <cstdlib>
16   using std::getenv;
17   using std::atoi;
18   using std::exit;
19
20   void displayShoppingCart( const string & );
21
22   int main()
23   {
24      char query[ 1024 ] = ""; // variable to store query string
25      string cartData; // variable to hold contents of cart
26    
27      string dataString = "";
28      string cookieString = "";
29      string isbnEntered = "";
30      int contentLength = 0;
31    
32      // retrieve cookie data               
33      if ( getenv( "HTTP_COOKIE" ) )        
34      {                                     
35         cartData = getenv( "HTTP_COOKIE" );
36         cookieString = cartData;           
37      } // end if                           
38    
39      // data was entered
40      if ( getenv( "CONTENT_LENGTH" ) )
41      {
42         contentLength = atoi( getenv( "CONTENT_LENGTH" ) );
43         cin.read( query, contentLength );
44         dataString = query;
45    
46         // find location of isbn value
47         int addLocation = dataString.find( "add=" ) + 4;
48         int endAdd = dataString.find( "&isbn" );
49         int isbnLocation = dataString.find( "isbn=" ) + 5;
50    
51         // retrieve isbn number to add to cart
52         isbnEntered = dataString.substr( isbnLocation );
53    
54         // write cookie
55         string expires = "Friday, 14-MAY-10 16:00:00 GMT";
56         int cartLocation = cookieString.find( "CART=" ) + 5;
57    
58         if ( cartLocation > 4 ) // cookie exists              
59            cookieString = cookieString.substr( cartLocation );
60    
61         if ( cookieString == "" ) // no cookie data exists
62            cookieString = isbnEntered;
63         else // cookie data exists
64            cookieString += "," + isbnEntered;
65    
66         // set cookie                                              
67         cout << "Set-Cookie: CART=" << cookieString << "; expires="
68            << expires << "; path=\n";                              
69      } // end if
70    
71      cout << "Content-Type: text/html\n\n"; // output HTTP header
72    
73      // output XML declaration and DOCTYPE
74      cout << "<?xml version = \"1.0\"?>"
75         << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
76         << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
77    
78      // output html element and some of its contents
79      cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
80         << "<head><title>Shopping Cart</title></head>"
81         << "<body><center><p>Here is your current order:</p>";
82    
83      if ( cookieString != "" ) // cookie data exists
84         displayShoppingCart( cookieString );        
85      else                                           
86         cout << "The shopping cart is empty.";      
87    
88      // output links back to book list and to check out
89      cout << "</center><br/>";
90      cout << "<a href=\"/cgi-bin/shop.cgi\">Back to book list</a><br/>";
91      cout << "<a href=\"/cgi-bin/checkout.cgi\">Check Out</a>";         
92      cout << "</body></html>\n";
93      return 0;
94   } // end main
95
96   // function to display items in shopping cart
97   void displayShoppingCart( const string &cookieRef )
98   {
99      char book[ 50 ] = "";
100     char year[ 50 ] = "";
101     char isbn[ 50 ] = "";
102     char price[ 50 ] = "";
103   
104     string bookString = "";
105     string yearString = "";
106     string isbnString = "";
107     string priceString = "";
108   
109     ifstream userData( "catalog.txt", ios::in ); // open file for input
110   
111     if ( !userData ) // file could not be opened
112     {
113        cerr << "Could not open database.";
114        exit( 1 );
115     } // end if
116   
117     cout << "<table border = 1 cellpadding = 7 >";
118     cout << "<tr><td>Title</td><td>Copyright</td><td>ISBN</td>"
119        << "<td>Price</td><td>Count</td></tr>";
120   
121     // file is open
122     while ( !userData.eof() )
123     {
124        // retrieve book information
125        userData.getline( book, 50 );
126        bookString = book;
127   
128        // retrieve year information
129        userData.getline( year, 50 );
130        yearString = year;
131   
132        // retrieve isbn number
133        userData.getline( isbn, 50 );
134        isbnString = isbn;
135   
136        // retrieve price
137        userData.getline( price, 50 );
138        priceString = price;
139   
140        int match = cookieRef.find( isbnString, 0 );
141        int count = 0;
142   
143        // match has been made
144        while ( match >= 0 && isbnString != "" )
145        {
146           count++;
147           match = cookieRef.find( isbnString, match + 13 );
148        } // end while
149   
150        // output table row with book information
151        if ( count != 0 )
152           cout << "<tr><td>" << bookString << "</td><td>" << yearString
153              << "</td><td>" << isbnString << "</td><td>" << priceString
154              << "</td><td>" << count << "</td></tr>";
155     } // end while
156   
157     cout << "</table>"; // end table
158  } // end function displayShoppingCart

Function displayShoppingCart displays the items in the shopping cart in a table. Line 109 opens the server-side file catalog.txt. If the file opens successfully, lines 122155 get each book's information (including its title, copyright, ISBN and price) from the file. Lines 125138 store these pieces of data in string objects. Lines 140148 count how many times the current ISBN appears in the cookie (i.e., in the shopping cart). If the current book appears in the user's cart, lines 151154 display a table row containing the book's title, copyright, ISBN and price, as well as the number of copies of the book the user has chosen to purchase.


[Page 967]

Figure 19.24 is the page that is displayed when the user chooses to check out (i.e., purchase the books in the shopping cart). This script outputs a message to the user and calls writeCookie (line 13), which effectively erases the current information in the shopping cart.

Figure 19.24. Check out program.
(This item is displayed on pages 967 - 968 in the print version)

 1  // Fig. 19.24: checkout.cpp
 2  // Program to log out of the system.
 3  #include <iostream>
 4  using std::cout;
 5
 6  #include <string>
 7  using std::string;
 8
 9  void writeCookie();
10
11  int main()
12  {
13     writeCookie(); // write the cookie
14     cout << "Content-Type: text/html\n\n"; // output header
15
16     // output XML declaration and DOCTYPE
17     cout << "<?xml version = \"1.0\"?>"
18        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
19        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
20
21     // output html element and its contents
22     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
23        << "<head><title>Checked Out</title></head><body><center>"
24        << "<p>You have checked out<br />"
25        << "You will be billed accordingly<br />To login again, "
26        << "<a href=\"/cgi-bin/login.cgi\">click here</a>"
27        << "</center></body></html>\n";
28     return 0;
29  } // end main
30
31  // function to write cookie
32  void writeCookie()
33  {
34     // string containing expiration date              
35     string expires = "Friday, 14-MAY-10 16:00:00 GMT";
36
37     // set cookie                                                   
38     cout << "Set-Cookie: CART=; expires=" << expires << "; path=\n";
39  } // end writeCookie

Figure 19.25 shows the contents of the catalog.txt file. This file must reside in the same directory as the CGI scripts for this shopping-cart application to work correctly.


[Page 968]

Figure 19.25. Contents of catalog.txt.

 Visual Basic .NET How to Program
 2002
 0-13-029363-6
 $50.00
 C# How to Program
 2002
 0-13-062221-4
 $49.95
 C How to Program 4e
 2004
 0-13-142644-3
 $88.00
 Java How to Program 6e
 2005
 0-13-148398-6
 $88.00



Previous Page
Next Page