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 5 using std::cerr; 6 using std::cin; 7 using std::cout; 8 using std::ios; 9 10 #include 11 using std::fstream; 12 13 #include 14 using std::string; 15 16 #include 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 << "
Please login. "; 70 71 // output login form 72 cout << "" 73 << "User Name: " 74 << "Password: " 75 << " New? 76 << " value = "1"/> " 77 << ""; 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 << "This name has already been taken. " 108 << "<a href="">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 << " " << userName << " " << passWord; 118 119 cout << "Your information has been processed." 120 << "<a href="">Start Shopping</a> "; 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 << "Thank you for returning, " << userName << "! " 148 << "<a href="">Start Shopping</a>"; 149 } // end if 150 else // user not authenticated 151 { 152 header(); 153 154 if ( userFound ) // password is incorrect 155 cout << "You have entered an incorrect password. " 156 << "Please try again. " 157 << "<a href="">Back to login</a>"; 158 else // user is not registered 159 cout << "You are not a registered user. " 160 << "<a href="">Register</a>"; 161 } // end else 162 } // end else 163 } // end else 164 165 cout << " "; 166 return 0; 167 } // end main 168 169 // function to output header 170 void header() 171 { 172 cout << "Content-Type: text/html "; // output header 173 174 // output XML declaration and DOCTYPE 175 cout << "" 176 << " 177 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 178 179 // output html element and some of its contents 180 cout << "" 181 << "Login Page; 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= "; 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.
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)
" 83 << "<a href="">Check Out</a>" 84 << ""; 85 return 0; 86 } // end main 87 88 // function to output header information 89 void header() 90 { 91 cout << "Content-Type: text/html "; // output header 92 93 // output XML declaration and DOCTYPE 94 cout << "" 95 << " 96 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 97 98 // output html element and some of its contents 99 cout << "" 100 << "Shop Page"; 101 } // end function header
1 // Fig. 19.22: shop.cpp 2 // Program to display available books. 3 #include 4 using std::cerr; 5 using std::cout; 6 using std::ios; 7 8 #include 9 using std::ifstream; 10 11 #include 12 using std::string; 13 14 #include 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 << " Books available for sale " 45 << ""; 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 << ""; 66 67 // file is still open after reads 68 if ( userData ) 69 { 70 // output form with buy button 71 cout << " "; 77 } // end if 78 79 cout << " "; 80 } // end while 81 82 cout << " |
||||
" << bookString << " | " << yearString 64 << " | " << isbnString << " | " << priceString 65 << " |
72 << "action="/cgi-bin/viewcart.cgi">" 73 << "" 74 << " 75 << isbnString << ""/>" << " 76 << "value="Add to Cart"/> |
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.</a>
<a href="/cgi-bin/login.cgi">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.</a>
<a href="/cgi-bin/login.cgi">[Page 963]</a>
<a href="/cgi-bin/login.cgi">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.</a>
<a href="/cgi-bin/login.cgi">Figure 19.23. CGI script that allows users to view their carts' contents.</a>
<a href="/cgi-bin/login.cgi">(This item is displayed on pages 964 - 967 in the print version) </a>
1 // Fig. 19.23: viewcart.cpp 2 // Program to view books in the shopping cart. 3 #include 4 using std::cerr; 5 using std::cin; 6 using std::cout; 7 using std::ios; 8 9 #include 10 using std::ifstream; 11 12 #include 13 using std::string; 14 15 #include 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= "; 69 } // end if 70 71 cout << "Content-Type: text/html "; // output HTTP header 72 73 // output XML declaration and DOCTYPE 74 cout << "" 75 << " 76 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 77 78 // output html element and some of its contents 79 cout << "" 80 << "Shopping Cart" 81 << " Here is your current order: "; 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 << " "; 90 cout << "<a href="">Back to book list</a> "; 91 cout << "<a href="">Check Out</a>"; 92 cout << " "; 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 << ""; 118 cout << "" 119 << ""; 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 << ""; 155 } // end while 156 157 cout << "
|
<a href="/cgi-bin/login.cgi">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.</a>
<a href="/cgi-bin/login.cgi">[Page 967]</a>
<a href="/cgi-bin/login.cgi">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.</a>
<a href="/cgi-bin/login.cgi">Figure 19.24. Check out program.</a>
<a href="/cgi-bin/login.cgi">(This item is displayed on pages 967 - 968 in the print version) </a>
1 // Fig. 19.24: checkout.cpp 2 // Program to log out of the system. 3 #include 4 using std::cout; 5 6 #include 7 using std::string; 8 9 void writeCookie(); 10 11 int main() 12 { 13 writeCookie(); // write the cookie 14 cout << "Content-Type: text/html "; // output header 15 16 // output XML declaration and DOCTYPE 17 cout << "" 18 << " 19 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 20 21 // output html element and its contents 22 cout << "" 23 << "Checked Out " 24 << " You have checked out " 25 << "You will be billed accordingly To login again, " 26 << "<a href="">click here</a>" 27 << " "; 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= "; 39 } // end writeCookie<a href="/cgi-bin/login.cgi"></a> |
<a href="/cgi-bin/login.cgi">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.</a>
<a href="/cgi-bin/login.cgi">[Page 968]</a>
<a href="/cgi-bin/login.cgi">Figure 19.25. Contents of catalog.txt.</a>
|
<a href="/cgi-bin/login.cgi"> </a>
<a href="/cgi-bin/login.cgi">[Page 969]</a> <a href="/cgi-bin/login.cgi">19 17 Wrap Up</a> |
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography