The theme of Part VII, "Advanced CGI Applications: Commercial Applications," is commerce on the Web. In this part, we show how to build an array of applications for use on Web sites that enable commerce.
In the April 1996 issue of IEEE Computer, Clifford Neuman of the University of Southern California writes," Network service providers and commercial online services have opened [the Internet] to a much larger user community. The Internet is increasingly becoming a venue for conducting the commerce previously carried out by other means and for offering new commercial online services."
Commerce takes many forms on the Web. To the realtor described in earlier examples (introduced in Chapter 1, "How to Make a Good Site Look Great," and used throughout the book) it is enough to attract users' interest and have them fill out an inquiry form. For someone like Perry and Minica Lopez, the proprietors of Hot, Hot, Hot, it is important that the visitor be able to place an order through the Web site (see Fig. 26.1).
Figure 26.1 : Visitors to Hot, Hot, Hot can order hot sauce through the Web.
Others, like Stu Sjouwerman (pronounced "shower man") at 3AData, want to be able to actually deliver the order through the Net. (Sjouwerman is the author of the best-selling e-book, Making Money on the Internet the Right Way, which is sold through First Virtual's Infohaus (see Fig. 26.2).
Figure 26.2 : Sites on the Infohaus typically send the information when the order is placed.
The remaining chapters in this part give details and sample code to implement a working shopping cart site.
To distinguish shopping from simply completing inquiry forms such as those shown in previous chapters, we define a shopping experience as one in which users can actually place an order and expect the material to be delivered.
Recall from the discussion of HTTP in Chapter 4, "Designing Faster Sites," that HTTP is a stateless protocol. When the server gets a message from the client, it has no way to know if that user is the same user who visited before.
More to the point, if a user sends a message and says, in effect, "I'd like to have that item" and later the user says, "Here's how I'll pay for my order," there is no way built into the protocol for the server to know that these two users are the same person. There are some mechanisms the Webmaster can graft onto HTTP through CGI scripts, however, to add that capability.
The simplest way to deal with maintaining state is to work around it: send in everything related to the order in one message.
This approach has the advantage of simplicity. Most of the CGI
script that processes this form is cousin to formmail.pl,
shown in Chapter 7, "Extending HTML's
Capabilities with CGI." The script takes the fields, checks
for needed data, sends an e-mail message to the site owner, and
sends a thank-you page to the user.
Caution |
There are two disadvantages to this single-form approach. First, users can only buy one item in an order. Second, users must carry the information about what they are buying in their head from the time they leave the page describing the product until they select it on the order form. |
The owners of Nikka Galleria decided that it is unlikely that many visitors will want to select more than one item at a time. They sell high-end fine art. The number of people who purchase two high-end works in one trip is small.
To keep the shopper from having to remember the name of the item when they leave the product page and go to the order form, the order form is actually built dynamically based on the page the shopper is on when they select Order. Suppose a user finds his or her way to the product page for EarthTribe, an original painting by Dempsey Crane, and decides to buy it (see Fig. 26.3). The user selects the Order button and goes to the order form (see Fig. 26.4). But on this version of the order form, instead of having to remember the name of the artwork and pick it off a list, the selected work is preset to EarthTribe.
Figure 26.3 : The user selects the work from the product page.
Figure 26.4 : Now the order form is customized for that product.
The code that implements this technique, orderform.cgi, is given in Listing 26.1.
Listing 26.1 nikkaord.cgi-Customizing an Order Form
to a Product
#!/usr/local/bin/perl require "html.cgi"; # read in the upper half of the form, insert the work, then read in the lower half of the form $FORM_UPPER_HALF = "/users/dse/pages/nikka/Orders/form.top"; $FORM_LOWER_HALF = "/users/dse/pages/nikka/Orders/form.bottom"; if ($ENV{'REQUEST_METHOD'} eq 'GET') { $work = $ENV{'QUERY_STRING'}; $work =~ tr/+/ /; $work =~ s/%([a-fA-F0-9][a-fA-F0-9]0)/pack("C", hex($1))/eg; # Check for illegal metacharacters. if ($work !~ /^[a-zA-Z0-9_\-+ \t\/@%]+$/) { &html_header("Illegal Characters"); print "The work contains illegal \n"; print "characters. Please notify \n"; print "the webmaster: \n"; print "<A HREF=\"mailto:morganm\@dse.com\">morganm\@dse.com</A>\n"; &html_trailer; } else { # start the HTML stream back to the server open (FILE, $FORM_UPPER_HALF) || &die("Unable to open upper half of form"); print "Content-type: text/html\n\n"; while (<FILE>) { print "$_\n"; } close FILE; print "<INPUT TYPE=Hidden NAME=Work VALUE=$work>\n"; # modify the following as attributes change. if ($work eq 'tattooBird') { print "Tattoo Bird, by Dempsey Crane \$4,000\n"; } elsif ($work eq 'tattooTrail') { print "Tattoo Trail, by Dempsey Crane \$2,500\n"; } elsif ($work eq 'tattooEye') { print "Tattoo Eye, by Dempsey Crane \$2,350\n"; } elsif ($work eq 'earthTribe') { print "Earth Tribe, by Dempsey Crane \$4,500\n"; } elsif ($work eq 'snakeDance') { print "Snake Dance, by Dempsey Crane \$2,000\n"; } elsif ($work eq 'ocean') { print "Ocean, by Thomas McLauchlin \$650\n"; } elsif ($work eq 'eveningStroll') { print "Evening Stroll, by Thomas McLauchlin \$135.00\n"; } elsif ($work eq 'prettyDay') { print "Pretty Day, by Thomas McLauchlin \$135.00\n"; } elsif ($work eq 'cafe') { print "Cafe, by Thomas McLauchlin SOLD\n"; } elsif ($work eq 'springGarden') { print "Spring Garden, by Lena Y. Liu \$125.00\n"; } elsif ($work eq 'oleTimeReligion') { print "Ole Time Religion, by Paula Vaughn \$95.00\n"; } elsif ($work eq 'gettysburg') { print "On To Gettysburg, by John Paul Strain \$165.00\n"; } else { print "Unknown work. Please notify webmaster: <A HREF=\"mailto: morganm\@dse.com\">morganm\@dse.com</A>\n"; } open (FILE, $FORM_LOWER_HALF) || &die("Unable to open lower half of form"); while (<FILE>) { print "$_\n"; } close FILE; } }
This technique is best suited for use with a small number of items
that don't change often; otherwise maintenance on this file can
become a burden.
Tip |
Clearly this script could be parameterized so that it reads the entries out of a database, but if the application needs much sophistication, it's time to consider a true shopping cart. |
The defining characteristic of a shopping cart script is that it preserves state throughout the shopping experience. The user enters the site and is given some unique token (often called a cookie.) Each time the user sends a request to the server, the script passes the cookie along so the server knows which client is calling.
Although the word cookie has been adopted by Netscape as
the name of their particular state preservation mechanism, the
word was in general usage for this concept long before Netscape
came on the scene. To preserve the distinction, this book uses
Netscape cookie to refer to Netscape's implementation and
ID to mean a generic implementation.
Note |
The word cookie may be whimsical but it has good roots. The New Hacker's Dictionary (The MIT Press, 1991) defines cookie as "a handle, transaction ID, or other token of agreement between cooperating programs." |
Not every page on a site needs to support shopping, but once users
have entered the shopping section, they must generally remain
there until they have completed their order. The reason for this
restriction is that once they have been issued a unique identifier,
it is up to each page to preserve the ID.
Tip |
If users leave the shopping area and move to a page that does not preserve the ID, they will not be able to remember their ID and find their order later. Two work-arounds to this limitation are given in Chapter 28, "Fully Integrated Shopping Environment." |
The first page of the shopping area needs special handling since the user usually arrives here without an ID. If the only considerations were technical ones, the "front door" to the site could always be designed like the one shown in Figure 26.5.
Figure 26.5 : This approach works well but is not always aesthetically acceptable.
For some sites, it's important to allow users to return to the first page, as shown in Figure 26.6. The associated risk is that users could inadvertantly get a new ID and lose anything they had already placed in the order.
Figure 26.6 : Giving users access to two or more ID-producing paths is risky.
One solution is to make sure the routine that issues new IDs does not issue an ID if one is already present. Another solution is to give users more control and expect them to choose the right path, as shown in Figure 26.7.
Figure 26.7 : One solution is to give the user explicit control.
Each of these solutions has its place. The Webmaster must trade off the strengths and weaknesses of each with commercial and aesthetic needs. Don't forget to consider the techniques discussed in Chapter 28, "Fully Integrated Shopping Environment," when you make a descision.
Remember from Chapter 9, "Making a User's Life Simpler with Multipart Forms," the four common techniques for maintaining state are
The first three techniques are used in the shopping cart script described in Chapter 27, "Multipage Shopping Environment." The last technique, the use of Netscape cookies, is illustrated in Chapter 28, "Fully Integrated Shopping Environment."
The information associated with each item in the order should be collected when users put the item into their shopping cart. In the simplest case, the only information to collect is "I want it."
For example, the Dominick's Party Center site at http://www.dominicksfoodlink. com/ (see Fig. 26.8) lists several hundred items that can be added to a party platter. Users need only select Order and a single instance of the item is added to their order. (They can change the quantity later.)
Figure 26.8 : At Dominick's Party Center, users just select the item to add it to the order.
Bob's Cycle Supply (http://www.bobscycle.com/bobscycle/index.html-see Fig. 26.9), uses a variation of the same shopping cart script but collects several options when taking the order. For example, users can select Axo RC3 Boots in five different color schemes and seven sizes. The scripts that implement this site are shown in Chapter 27, "Multipage Shopping Environment."
As the user moves through the site, selecting items and putting them into the shopping cart, the accumulating order is built up from information stored about each item and put on the server's hard disk. There are four ways to store product information and three ways to store cart information on disk.
Product information can be stored
Storing product information inline has two advantages. First, it increases the likelihood that the information will match information presented on the page because the two elements are maintained together. Second, this method is efficient and easy to code because all the information about the product comes in with the request to add it to the order.
A flat ASCII file of the product data is often readily available from the site owner's existing software. Flat ASCII files should be kept sorted to maintain some semblence of efficiency. Since they are usually maintained separately from the HTML pages, there is always a risk that the price or description in the file will not match the same information on the page.
DBM files are much more efficient than sorted ASCII files, but they still suffer from the potential of drifting out of sync with the HTML page.
Unless the number of items is large, it's hard to justify the expense or complexity of a DBMS. When a DBMS is justified, it's usually not feasible to prepare a product page or catalog entry for every item, so the HTML pages are built dynamically from the database. The combination of a relational database management system (RDBMS) for product information and a dynamically built catalog page can be quite effective when the number of items is high (see Fig. 26.10).
Figure 26.10 : A large online catalog can be built dynamically from a database.
There are three places to accumulate order information:
The tradeoffs for orders are different from those of product information. Since orders typically do not have to be searched, there is little penalty in storing an order in an ASCII file and less benefit to storing it in a more efficient structure such as a DBM. In a UNIX environment, storing order information in a flat ASCII file has the additional advantage of allowing the maintainer to use conventional UNIX tools such as grep, sed, awk, and Perl.
Unless a high-end DBMS is already present for some other reason, it's hard to justify using a DBMS to store order information.
The example used in Chapter 27, "Multipage Shopping Environment," shows the product information stored inline with the HTML and the order information stored in a flat file.
Users will want to look at the contents of the shopping cart from time to time. They will want to see the total cost of the order, including any additional charges such as shipping and handling or insurance that can be displayed at this point.
Users may also want to change the quantity of an item ordered (including reducing that quantity to zero). Figure 26.11 shows a typical review page.
Checkout is the process by which users supply the site owner with information about where to ship the order and how they will pay for the merchandise. Since users will want to review the order before checking out, it's customary to make the checkout link available only from the review page. (Refer to Fig. 26.11 earlier in this chapter for an example.)
The ordering process is largely driven by the site owner's business model. If the site owner is willing to accept payment through a large number of mechanisms, it is often best to separate the checkout process into two stages:
Figure 26.12 shows how this technique looks in practice.
Chapter 25, "Getting Paid: Taking Orders over the Internet," describes a variety of payment options.
Not only is HTTP stateless, it is effectively connectionless. Users make a connection, send a request, get a reply, and end the connection. If they want something else, they have to make a new connection.
This design means that if users get part of the way into the shopping process and then quit, there is no perfect way for the server to know that they have gone and certainly no way to know when (or even if) they are coming back.
The most common technique for cleaning up after users is to "expire" the ID and delete the associated cart after a certain period of time, such as a day. Whereas some users may lose a modem connection and want to resume, few users are likely come come back 24 hours later and expect to find their shopping cart intact.
Details on how to expire an ID and remove the cart are given in the code in Chapter 27, "Multipage Shopping Environment."
This chapter
Chapter 27, "Multipage Shopping Environment," shows code to implement these functions that can be used with all browsers. Chapter 28, "Fully Integrated Shopping Environment," shows simpler code to do the same tasks with the most common browsers.
Chapter 25, "Getting Paid: Taking
Orders over the Internet," outlines several ways of getting
paid. Chapter 29, "Fulfillment,"
shows how to tell the fulfillment house to ship the items for
the order.
Note |
The CD that accompanies this book contains an actual Shopping Cart Site. |