#!/usr/bin/perl # Name: Selena Sol's Electronic Outlet (HTML Version) # Version: 3.0a # Last Modified: 10-23-96 # Copyright Info: This application was written by Selena Sol # (selena@eff.org, http://www.eff.org/~erict) having been inspired by # countless other Perl authors. Feel free to copy, cite, reference, # sample, borrow, resell or plagiarize the contents. However, if you # don't mind, please let me know where it goes so that I can at least # watch and take part in the development of the memes. Information # wants to be free, support public domain freware. Donations are # appreciated and will be spent on further upgrades and other public # domain scripts. ####################################################################### # Print http Header. # ####################################################################### # First tell Perl to bypass the buffer so that information generated by # the CGI will be sent immediately to the browser. The line $! = 1; does # this. Then, print out the http header so that we will easily be able to # debug and so that the browser will not time us out. $| = 1; print "Content-type: text/html\n\n"; ####################################################################### # Require Libraries. # ####################################################################### # Now let's require some of the supporting files that this script will # take advantage of. The web_store.setup defines many global variables # for this script relative to the local server. cgi-lib.pl is used to # parse incoming form data. cgi-lib.sol is used to manipulate the counter # file. And mail-lib.pl is used to send mail to the store administrator # when someone places an order. require "./html_web_store.setup"; require "$cgi_lib_pl"; require "$cgi_lib_sol"; require "$mail_lib_pl"; ####################################################################### # Gather Form Data. # ####################################################################### # Use cgi-lib.pl to parse the incoming form data and tell cgi-lib to # prepare that information in the associative array %form_data &ReadParse(*form_data); # However, we need to be careful about one possible security hole. Later # in this script, we are going to use a variable called "page" to # communicate which page in our store we want to display to the client. # The danger in this, is that a client might "fake" a request to the # script by editing the page variable in the HTMl or in the encoded URl. # For example, they mught reassign page from, say, vowel.html to # ../../../etc/passwd! As you can imagine, this would end up displaying # your password file to the browser window. Thus, we need to make sure # that only HTML pages can be displayed by the store. # # The following routine simply check to make sure that if the page # variable is not either .htm or .html, it will exit and send a warning. if (($form_data{'page'} =~ /html$/ || $form_data{'page'} =~ /htm$/) || ($form_data{'page'} eq "")) { # Do nothing...things are cool...go on with the script. } else { print "I am sorry, but you may only use this program to view HTML pages. If you absolutely MUST view non-HTML pages within your store, you must modify lines 67-71, but be careful, doing so may make your system vulnerable to hackers. The current value of page is: \"$form_data{'page'}\"

(NOTE: If there is nothing between the quote marks and you are not a hacker, you have not assigned yourself a valid page which means your HTML coding is probably wrong)"; exit; } ####################################################################### # Assign a Shopping Cart. # ####################################################################### # Next, let's clean up our carts directory. There is no need to keep # old carts around after the clients are long gone. So we will grab a # listing of all of the client created shoppping carts in the # Client_carts directory. We will first open the directory which has the # carts, then we will read that directories contents and use grep to grab # every file with the extension .cart. Then we will close the directory. opendir (USER_CARTS, "$cart_directory") || &open_error($cart_directory); @carts = grep(/\.cart/,readdir(USER_CARTS)); closedir (USER_CARTS); # Now, for every cart in the directory... foreach $cart (@carts) { # If it is older than half a day, delete it if (-M "$cart_directory/$cart" > .5) { unlink("$cart_directory/$cart"); } } # Now we can add the new users cart. # If we have not received a shopping cart id number as form data, it means # that the clieent has not yet received a unique shopping cart. # So, assign the client a unique shopping cart file that they will use # while they are browsing the store. First we'll generate a random # (srand + rand) 8 digit (100000000) integer (int) and then add to that # the current process id ($$). We will append the process id to the end of # the integer by using .= instead of = if ($form_data{'cart_id'} eq "") { srand (time|$$); $cart_id = int(rand(10000000)); $cart_id .= ".$$"; # Now create a new cart for the shopper. open (CART, ">$cart_directory/$cart_id.cart") || &CgiDie("I am sorry, I was not able to create the users cart in the assign a shopping cart routine. The value I have for the cart is $cart_directory/$cart_id.cart. Would you please make sure the path and permissions are correct."); } # If there was a shopping cart id number coming in as form data, let us # simply rename the variable to $cart_id so that we have a standardized # variable name. Note, that once the client has recieved their own cart, # that cart number MUST be passed from screen to screen as url encoded # information or as a hidden form variable so that the clkient does not # lose their cart. else { $cart_id = "$form_data{'cart_id'}"; } ####################################################################### # Output Frontpage. # ####################################################################### # Now that they have received a cart, it is time to display to them the # first page of the store. We will assume that the site administrator has # created a frontpage and set that locatioon equal to $frontpage_file in # the store specific setup file (or default). # There are two cases in which we would want to display the frontpage. # firstly, if the user has specifically asked to "return to the frontpage" # and secondly, if no category has been assigned. That is, the main # purpose of the frontpage is to query the client for which category they # are interested in browsing (like which aisle they want to go down). # The main purpose of the frontpage is to present all these options and to # create hyperlinks which will define the categories. if ($form_data{'page'} eq "" || $form_data{'return_to_frontpage'} ne "") { # So, if we have been asked for the frontpage, let's open it up and # display it line by line. open (FRONTPAGE, "$frontpage_file") || &CgiDie ("I am sorry, but I was not able to load $frontpage_file in the Output Frontpage routine. Would you please make sure the path and permissions are correct."); while () { # However, we are going to want to do a couple of things to the page. # Firstly, we are going to need to make sure that the clients unique cart # id gets passed from the frontpage to any successive pages. The way we # do this is by url encoding. We are going to have the user click on a # link that says . # There are two things of note in that line. Firstly, we will be defining # a category in those links...this is essential. Secondly, we will be # adding a half done variable, userid. This userid= is really just a tag # which this script will be looking for. Anytime (/g) it sees that, it # will substitute (s/) occurances of cart_id= with cart_id= the actual cart id # of the user. # Since we do not know ahead of time what the cart id is going to be, we # cannot actually hard code it in to the HTML. Thus, we create the # cart_id= tag so that this script can finish off the job on the fly. # We'll also tag on the current store setup file since we are not passing # it as a hidden variable. s/cart_id=/cart_id=$cart_id/g; print "$_"; } # Close out the frontpage file and quit...it is time to let the client # decide which category she wants to browse. close (FRONTPAGE); exit; } # End of if ($form_data{'page_to_view'} eq "") ####################################################################### # Add to Shopping Cart # ####################################################################### # Once the client has decided to puirchase an item from one of the # categories, they will have added a quantity to the text box and hit # submit. (The displaying category routines are at the tend of this # script) So it is time to add a new item to their cart. if ($form_data{'add_to_cart'} ne "") { # Begin by using the %form_data array given to us by cgi-lib.pl. We'll # take all of the keys of the form_data associative array and drop them in # the @incoming data array. A key is like a variable name whereas a # value is the value associated with that variable name. Since each of # the text boxes which the client could enter quantities were associated # with the database id number of the item that they accompany, (as defined # in the displaying category view at the end of this script), the HTML # should read for the item with # database id number 1234 and for # item 5678. If the client orders 2 of 1234 and 9 of 5678, then # @incoming_data will be a list of 1234 and 5678 such that 1234 is # "associated" with 2 in %form_data and 5678 is associated with 9. @items_ordered = keys (%form_data); # Next we will begin going through the list of incoming items one by one. foreach $item (@items_ordered) { # However, there are some incoming items that we won't care about. # Specifically, we do not care about cart_id, page, or add_to_cart because # these are all administartive values set internally by this script. # They will be coming in as form data...and we will need them for other # things, just not to fill up the user's cart. Similarly, we will not # need to worry about any items which have empty values. If the shopper # did not enter a quantity, then we won't add it to the cart. if ($item ne "cart_id" && $item ne "page" && $item ne "add_to_cart" && $form_data{$item} ne "") { # Then we must separate out the items that have been ordered from the # options which modify those items. if $item begins with the word option, # which we set specifically in the HTML file, we will add (push) that item # to the array (list) called @options if ($item =~ /^option/i) { push (@options, $item); } # On the other hand, if it is not an option, let's add it to the array # @items_ordered_with_options, but let's add both the item and its value. # The value wil be a quantity and the item will be something like # 0001|12.98|The letter A as defined in the HTML file. else { push (@items_ordered_with_options, "$form_data{$item}\|$item\|"); } } #End of if ($item ne "cart_id".... } #End of foreach $item (@items_ordered) # Now go through the array @items_ordered_with_options one item at a time. foreach $item_ordered_with_options (@items_ordered_with_options) { # Clear out a few variables that we are going to use for each item. # $options will be used to keep track of all of the options selected for # any given item. $option_subtotal will be used to determine the total # cost of each option. $option_grand_total will be used to calculate the # total cost of all ordered options. $item_grand_total will be used to # calculate the total cost of the item ordered factoring in quantity and # options. $options = ""; $option_subtotal = ""; $option_grand_total = ""; $item_grand_total = ""; # Now split out the $item_ordered_with_options into it's fields. ($item_quantity, $item_id_number, $item_price, $item_description) = split (/\|/, $item_ordered_with_options); # Then for every option in @options, split up each option into it's # fields. foreach $option (@options) { ($option_marker, $option_number, $option_item_number) = split (/\|/, $option); # Once we have done both splits, we can compare the name of the item with # the name associated with the option. If they are the same, we know that # this is an option which was meant to enhance this item. if ($option_item_number eq "$item_id_number") { # Since we need to apply this option to this item, let's split out the # value associated with the option. And append it to $options. Once we # have gone through all of the options, using .=, we will have one big # string containing all the options so that we can print them out. ($option_name, $option_price) = split (/\|/,$form_data{$option}); $options .= "$option_name $option_price,"; # But we must also calculate the cost changes with options. $unformatted_option_grand_total = $option_grand_total + $option_price; $option_grand_total = sprintf ("%.2f\n", $unformatted_option_grand_total); } } # Take off the last comma in options. Look 6 lines up...you se that a # comma is added to the end of each option...well the last option does not # need that last comma. chop $options; # Now add a space after each comma so the display looks nicer. $options =~ s/,/, /g; # Now use the subroutine counter in cgi-lib.sol sending it the location of # the counter file defined in the setup file. This routine will return # one variable called $item_number which we can use to identify a shopping # cart item absolutely. This must be done so that when we modify and # delete we will know exactly which item to affect. &GetFileLock("$counter_file.lock"); &counter ($counter_file); &ReleaseFileLock("$counter_file.lock"); # Finally, do the last price calculations and append every ordered item # to $cart_row $unformatted_item_grand_total = $item_price + $option_grand_total; $item_grand_total = sprintf ("%.2f\n", $unformatted_item_grand_total); chop $item_grand_total; $cart_row .= "$item_quantity\|$item_id_number\|$item_price\|$item_description\|$options\|$item_grand_total\|$item_number\n"; } # When we are done appending all the items to $cart_row, open the users # shopping cart and add the new items. open (CART, ">>$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart at the end of the Add to Shopping Cart routine. The value I have for the cart is $cart_directory/$form_data{'cart_id'}.cart. Would you please make sure it has a valid path and permissions."); print CART "$cart_row"; close (CART); # Now send the client back to the page from whenced they ordered with the # display_items_for_sale subroutine at the end of this script. &display_items_for_sale; exit; } ####################################################################### # Output View/Modify Cart Screen # ####################################################################### # On the other hand, the user may have already been adding items, realized # she went over budget and decided to reduce the quantities of some of the # items she chose or even delete them altogether from her cart. The first # thing we need to do is send her an HTML form with which she can choose # whether to delte or modify. (or maybe she just wants to view her current # cart items...let's be optimistic!) if ($form_data{'modify_cart'} ne "") { &display_cart_contents; } ####################################################################### # Output Modify Quantity Form # ####################################################################### # If the client has asked to make a quantity modification, we will need to # give her a form so that she can specify the changes she wants made. if ($form_data{'change_quantity'} ne "") { # Output the header as we just did above. # Note: We will use the qq! method of printing as discussed in the Output # Frontpage routine. &page_header("Change Quantity"); print qq!

!; # Build the table headers.. foreach $field (@display_fields) { print qq!\n!; } print qq!\n\n\n!; # Open up the client's cart and begin going through it line by line... open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Output Modify Quantity Form routine. The value I have for the cart is $cart_directory/$form_data{'cart_id'}.cart. Would you please check the path and the permissions."); while () { @cart_fields = split (/\|/, $_); # This time, however, we are going to pop out both the cart specific db # number as well as the store specific db number and then push them back # onto the array once we have assigned the values to our variables. # Make sure to chop off thenewline character for $cart_row_number too # Then grab the quantity while you are at it, but we won't need to # unshift that back into the array. $cart_row_number = pop(@cart_fields); $db_number = pop(@cart_fields); $quantity = shift(@cart_fields); push (@cart_fields, $db_number); push (@cart_fields, $cart_row_number); chop $cart_row_number; # Now begin creating the table based form which the client will be able to # use to submit quantity changes. First, create a textbox so they can # enteer a new quantity. In this case, we'll assign the $cart_row_number # to the name in the input field so that we will later be able to remember # which item was associated with the quantity change. # Note: We will use the qq! method of printing as discussed in the Output # Frontpage routine. print qq!\n!; } else { print qq!\n!; } } # End of foreach $display_number (@display_numbers) print qq!\n!; $unformatted_subtotal = ($quantity*$cart_fields[$price_number]); $subtotal = sprintf ("%.2f\n", $unformatted_subtotal); $unformatted_grand_total = $grand_total + $subtotal; $grand_total = sprintf ("%.2f\n", $unformatted_grand_total); print qq!\n!; print qq!\n!; } # End of while () close (CART); print qq!
New Quantity$fieldQuantitySubtotal
\n!; print qq!\n!; # Then create the table rows and footer as we did above. foreach $display_number (@display_numbers) { if ($cart_fields[$display_number] eq "") { $cart_fields[$display_number] = "
-
"; } if ($display_number eq "$price_number") { print qq!
\$$cart_fields[$display_number]$cart_fields[$display_number]$quantity\$$subtotal

Pre-shipping Grand Total = \$$grand_total

!; exit; } ####################################################################### # Modify Quantity of Items in the Cart # ####################################################################### # Once the client has typed in some quantity changes and submitted the # information, we can make the modifications to the database. if ($form_data{'submit_change_quantity'} ne "") { # First, we will gather the keys as we did for the frontpage generation # far above and we will check to make sure they entered a positive # integer. @incoming_data = keys (%form_data); foreach $key (@incoming_data) { if ($key =~ /[\d]/ && $form_data{$key} =~ /[\D]/) { &bad_order_note; } # Just as we did above, we will create an array (@modify_items) of valid # keys. unless ($key =~ /[\D]/ && $form_data{$key} =~ /[\D]/) { if ($form_data{$key} ne "") { push (@modify_items, $key); } } # End of unless ($key =~ /[\D]/... } # End of foreach $key (@incoming_data) # Now we will open up the client's cart and go through it as usual. open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Modify Quantity of Items in the Cart routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please make sure the path and permissions are correct."); while () { @database_row = split (/\|/, $_); $cart_row_number = pop (@database_row); push (@database_row, $cart_row_number); $old_quantity = shift (@database_row); chop $cart_row_number; # Now, we need to see if the item number submitted as form data is equal # to the number of the current database row. foreach $item (@modify_items) { if ($item eq $cart_row_number) { # If so, we will create the $shopper_row variable and begin creating the # modified row...that is we will replace the old quantity with the # quantity submitted by the client ($form_data{$item}). Recall that # $old_quantity has already been shifted off the array. $shopper_row .= "$form_data{$item}\|"; # Now add the rest of the database row to $shopper_row and set two flag # variables. $quantity_modified will let us know that the current row has # had a quantity modification. $invalid_submission will tell us basically # the same thing but will be used by a differenmt routine below. foreach $field (@database_row) { $quantity_modified = "yes"; $invalid_submission = "no"; $shopper_row .= "$field\|"; } chop $shopper_row; # Get rid of last | } # End of if ($item eq $cart_row_number) } # End of foreach $item (@modify_items) # Now, if we get here and $quantity_modified has not been set to yes, we # know that the above routine was skipped because the item number # submitted from the form was not equal to the curent database id number. # So we know that the current row is not having its quantity changed and # can be added to $shopper_row as is. Remember, we want to add the old # rows as well as the new modified ones... if ($quantity_modified ne "yes") { $shopper_row .= $_; } $quantity_modified = ""; } # End of while () close (CART); # Next, check to make sure that at somewhere along the line we had a valid # submission. If not, send them to the bad_order_note subroutine. if ($invalid_submission ne "no") { &bad_order_note } # Now overwrite the old cart with the new information and send them back # to the last category page they were on. open (CART, ">$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Modify Quantity of Items in the Cart routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please make sure the path and permissions are correct."); print CART "$shopper_row"; close (CART); &display_cart_contents; exit; } ####################################################################### # Output Delete Item Form # ####################################################################### # Perhaps instead, the client asked to delete an item rather than modify # the quantity. if ($form_data{'delete_item'} ne "") { # Print out the usual page and table headers. # Note: We will use the qq! method of printing as discussed in the Output # Frontpage routine. &page_header("Delete Item"); print qq!
!; foreach $field (@display_fields) { print qq!\n!; } print qq!\n\n\n!; # Open up the cart and this time, add a check box instead of a text box so # that the client can specify a delete. Just as we did for modify, assign # the NAME equal to the cart_row_number. open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Output Delete Item Form routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please make sure that the path and permissions are correct."); while () { @cart_fields = split (/\|/, $_); $cart_row_number = pop(@cart_fields); $db_number = pop(@cart_fields); push (@cart_fields, $db_number); push (@cart_fields, $cart_row_number); chop $cart_row_number; $quantity = shift(@cart_fields); print qq!\n!; } else { print qq!\n!; } } # End of foreach $display_number (@display_numbers) print qq!\n!; $unformatted_subtotal = ($quantity*$cart_fields[$price_number]); $subtotal = sprintf ("%.2f\n", $unformatted_subtotal); $unformatted_grand_total = $grand_total + $subtotal; $grand_total = sprintf ("%.2f\n", $unformatted_grand_total); print qq!\n!; print qq!\n!; } # End of while () close (CART); # Add footer... print qq!
Delete Item$fieldQuantitySubtotal
\n!; print qq!\n!; # Display table rows... foreach $display_number (@display_numbers) { if ($cart_fields[$display_number] eq "") { $cart_fields[$display_number] = "
-
"; } if ($display_number eq "$price_number") { print qq!
\$$cart_fields[$display_number]$cart_fields[$display_number]$quantity\$$subtotal

Pre-shipping Grand Total = \$$grand_total

!; exit; } ####################################################################### # Delete Item From Cart # ####################################################################### # Once the client submits some items to delete, we come here. if ($form_data{'submit_deletion'} ne "") { # Again, check for valid entries..this time though we only need to make # sure that we filter out the extra form keys rather than make sure that # we have a positive integer value as well. @incoming_data = keys (%form_data); foreach $key (@incoming_data) { unless ($key =~ /[\D]/) { if ($form_data{$key} ne "") { push (@delete_items, $key); } } # End of unless ($key =~ /[\D]/... } # End of foreach $key (@incoming_data) # Open up the cart and get the $cart_row_number, $db_id_number, and # $old_quantity as we did for modification. open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Delete Item From Cart routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please check the path and permissions."); while () { @database_row = split (/\|/, $_); $cart_row_number = pop (@database_row); $db_id_number = pop (@database_row); push (@database_row, $db_id_number); push (@database_row, $cart_row_number); chop $cart_row_number; $old_quantity = shift (@database_row); # Unlike modification, for deletion all we need to do is check to see if # the current database row matches a submitted item for deletion...if it # does not match add it to $shopper_row. If it is equal, do not...thus, # all the rows will be added except for the ones that should be deleted. $delete_item = ""; foreach $item (@delete_items) { if ($item eq $cart_row_number) { $delete_item = "yes"; } # End of if ($item eq $cart_row_number) } # End of foreach $item (@add_items) if ($delete_item ne "yes") { $shopper_row .= $_; } } # End of while () close (CART); # Overwrite the old cart with the new information and send them back to # the category page. open (CART, ">$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Delete Item From Cart routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please check the path and permissions."); print CART "$shopper_row"; close (CART); &display_cart_contents; exit; } ####################################################################### # Output Order Form # ####################################################################### # Hopefully, the client will fill up there cart and head over to the cash # register. if ($form_data{'order_form'} ne "") { # First, let's print up an order form. To make this easier, I have # created a subdirectory which contains the order form and frontpage HTML # files...this way, it will be easier to modify them to your own needs. # This routine will simply output your predesigned order form, but as we # did for the frontpage, we will insert our hidden variables. open (ORDER_FORM, "$html_directory/$order_form") || &CgiDie ("I am sorry, but I was not able to load the Order form in the Output Order Form routine. The value I have for it is $html_directory/$order_form. Would you please check the path and the permissions."); # Note: We will use the qq! method of printing as discussed in the Output # Frontpage routine. while () { if ($_ =~ /
!; # Print out the current cart contents. foreach $field (@display_fields) { print qq!\n!; } print qq!\n\n\n!; open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was not able to open the user cart in the Output Order Form routine. The value I have for it is $cart_directory/$form_data{'cart_id'}.cart. Would you please check the path and the permissions."); while () { @cart_fields = split (/\|/, $_); $quantity = shift(@cart_fields); foreach $display_number (@display_numbers) { if ($cart_fields[$display_number] eq "") { $cart_fields[$display_number] = "
-
"; } if ($display_number eq "$price_number") { print qq!
\n!; } else { print qq!\n!; } } # End of foreach $display_number (@display_numbers) print qq!\n!; $unformatted_subtotal = ($quantity*$cart_fields[$price_number]); $subtotal = sprintf ("%.2f\n", $unformatted_subtotal); $unformatted_grand_total = $grand_total + $subtotal; $grand_total = sprintf ("%.2f\n", $unformatted_grand_total); print qq!\n!; print qq!\n!; } # End of while () print qq!
$fieldQuantitySubtotal
\$$cart_fields[$display_number]$cart_fields[$display_number]$quantity\$$subtotal

Pre-shipping Grand Total = \$$grand_total

!; close (CART); } # End of if ($_ =~ /) close (ORDER_FORM); exit; } ####################################################################### # Send In Order # ####################################################################### # Finally, we need to send the order to whoever handles order filling. if ($form_data{'send_in_order'} ne "") { # Begin by sending out the header and sorting the incoming form variables. # The reason that we do this is because the keys function will not give us # the form varioables in any speciic order due to hash routines. Thus, by # encoding each form variable in our HTML document with a preceding number # like 01-name or 05-city we give ourselves the ability to sort them in # the order we want them at this point. Take a look at the distribution # HTML. You will see that all of the NAME values are ordered this way. # The number corresponds to its order when all the variables are printed # out. The sort funtion will take all of the unsorted variables in # @variable_names, sort them and then add them to @sorted_variable_names &page_header("Your Order Has Been Sent"); @variable_names = keys (%form_data); @sorted_variable_names = sort (@variable_names); # Now remind the client of what she entered onm the order form...and begin # creating the body of the email message that we wills end to the store # administrator (using $email_body). print qq!

You submitted the following information

!; $email_body .= "Personal Information\n\n"; # Basically print out the form variable and its associated value for every # form field the client submitted...but don't bother printing out # administrative hidden variables used byu this scipt since the user # doesn't care. If you add other hidden variables make sure to escape # them here. We'll also add the list to the $email_body variable. foreach $variable (@sorted_variable_names) { if ($form_data{$variable} ne "" && $variable ne "cart_id" && $variable ne "page" && $variable ne "send_in_order") { print qq! \n!; $email_body .= " $order_form_array{$variable} = $form_data{$variable}\n"; } } # End of foreach $variable (@sorted_variable_names) print qq!
$order_form_array{$variable} $form_data{$variable}
!; # Now output the current cart contents as ordered. No surprises here, we # have done this over and over again above. print qq!

You ordered the following items

!; foreach $field (@display_fields) { print qq!\n!; } print qq!\n\n\n!; # Now we are going to do something a litle bit diferent when it comes to # mailing the store administrator. First open the cart again and begin # reading it line by line. $email_body .= "\nOrder Information\n\n"; open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was unable to open the user cart in the Send In Order routine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Would you check the path and permissions."); while () { @cart_fields = split (/\|/, $_); $quantity = shift(@cart_fields); $cart_quantity = $cart_quantity + $quantity; # The thing is, the store admin doe snot need to have every single # database row included with orders...that would be a pain to read and # would be horrid on formatting...so we are going to aonly include some # essential fields... Firstly, we need to note the quantity of every item. $email_body .= " $quantity"; # Then, for every item that we have set to display in our setup file... foreach $display_number (@display_numbers) { # print the whole row for the client on the web... if ($cart_fields[$display_number] eq "") { $cart_fields[$display_number] = "
-
"; } if ($display_number eq "$price_number") { print qq!
\n!; } else { print qq!\n!; } # But for the store admin, we are going to get another list from the setup # file, @email_numbers. @email_numbers is a sub list of @display_numbers # which includes only those fields that the store admin needs to see. For # example, whereas the client may want to see descirtions, name, price, # item number, size, and a picture...the admin may only want to see item # number, name and quantity. Thus, we will only send the store admin # those fields which shehas set the setup file to give her. BTW, the four # spaces before $cart_fields[$display_number] are just for # formatting...you'll see when you get one of the emails. foreach $display_field (@email_numbers) { if ($display_number eq $display_field) { $email_body .= " $cart_fields[$display_number]"; } } } # End of foreach $display_number (@display_numbers) # Add a new line for every cart item. $email_body .= "\n"; # Include the footer information for the client on the web and calculate # costs. $unformatted_subtotal = ($quantity*$cart_fields[$price_number]); $subtotal = sprintf ("%.2f\n", $unformatted_subtotal); $unformatted_grand_total = $grand_total + $subtotal; $grand_total = sprintf ("%.2f\n", $unformatted_grand_total); print qq! !; } # End of while () #################### # Specific cost calculations for my exammple...not necessary for you. if ($cart_quantity eq "1") { $unformatted_shipping_cost = 4.50; } if ($cart_quantity eq "2") { $unformatted_shipping_cost = 5.50; } if ($cart_quantity ne "2") { $cart_quantity = $cart_quantity - 2; $unformatted_shipping_cost = "8.00 + $cart_quantity"; } ########################## $shipping_cost = sprintf ("%.2f\n", $unformatted_shipping_cost); $unformatted_final_total = $grand_total + $shipping_cost; $final_total = sprintf ("%.2f\n", $unformatted_final_total); # Print up the footer for both the client and admin including total price. print qq!
$fieldQuantitySubtotal
\$$cart_fields[$display_number]$cart_fields[$display_number]$quantity \$$subtotal

Estimated Item Total, Does NOT Include Quanity Discount = \$$grand_total

Estimated Shipping and Handling Charge: \$$shipping_cost

Grand Total, Does NOT Include Quanity Discount or Sales Tax for CA Residents: \$$final_total

!; close (CART); $email_body .= "\nGrand Total = \$$final_total\n"; print "$_"; close (ORDER_FORM); # Use the send_mail routine in mail-lib.pl to send the email to the store # admin including the clients ordering information then get the heck outa # Dodge. # Now strip out the HTML tags in the email body that are added by default # above (ie:
-
) $email_body =~ s/<([^>]|\n)*>//g; &send_mail("$admin_email","$admin_email", "$email_subject", "$email_body"); exit; } ####################################################################### # Display items for Sale Basd on Given Category # ####################################################################### # If we have gotten through all of the if tests above, it means that the # client simply wanted to see a category display...so let's display the # current items within the category selected by the client. We will use # the display_items_for_sale subroutine below else { &display_items_for_sale; exit; } ####################################################################### # display_items_for_sale # ####################################################################### sub display_items_for_sale { open (HTML_FILE, "$html_directory/$form_data{'page'}") || &CgiDie ("I am sorry, but I was unable to open the page with items to display in the display_items_for_sale subroputine. The value I have for the page is $html_directory/$form_data{'page'}. please check the path and permissions."); while () { s/%%cart_id%%/$form_data{'cart_id'}/g; s/%%page%%/$form_data{'page'}/g; print "$_"; } # End of while () close (HTML_FILE); } # bad_order_note is a subroutine that we will use in case the client has # inputted a bad character in one of the input fields. sub bad_order_note { &page_header("Wooopsy"); print qq!

Wooopsy

I'm sorry, it appears that you did not enter a valid numeric quantity (whole numbers greater than zero) for one or more of the items you ordered and I am not allowed to modify your cart unless you do so. Would you try again? Thanks

!; exit; } # page_header just prints out the basic header tags. We pass the routine # one argumnet which should be printed out differentiating pages which use # this routine. sub page_header { local($type_of_page) = @_; print qq! $type_of_page !; } sub display_cart_contents { # First use the page_header subrtoutine at the end of this script to # output an HTML header passing it one parameter relating to how the page # title should be modified. &page_header("View/Modify Cart"); # Now begin to create a table to display the current cart contents. print qq!
!; # Next create the table headers. For every item in our special list of # database items to be displayed, lets create a header cell. foreach $field (@display_fields) { print qq!\n!; } # Now add on a cell for Quanity and one for Subtotal since the client's # cart has those "extra" fields. print qq!\n\n\n!; # Then open the client's cart again and go through it one line at a time. open (CART, "$cart_directory/$form_data{'cart_id'}.cart") || &CgiDie ("I am sorry, but I was not able to open the user cart when executing the display_cart_contents subroutine. The value I have is $cart_directory/$form_data{'cart_id'}.cart. Please check the permissions and path."); while () { @cart_fields = split (/\|/, $_); $cart_id_number = pop (@cart_fields); $quantity = shift(@cart_fields); # Now, we need to fill in the table row for every cart database row. # @display_numbers defined in the dataabse specific setup file will give # us the array numbers associated with the fields that we want displayed # on this table. Then we will get the value of that number from the # cart_fileds array. foreach $display_number (@display_numbers) { if ($cart_fields[$display_number] eq "") { $cart_fields[$display_number] = "
-
"; } if ($display_number eq "$price_number") { print qq!
\n!; } else { print qq!\n!; } } # End of foreach $display_number (@display_numbers) # Then we will need to use the quantity value we shifted earlier to fill # the next table cell, and then, after using another database specific # setup variable, calculate the subtotal for that database row and fill # the final cell and close out the table row and the cart file (once we # have gone all the way through it. $unformatted_subtotal = ($quantity*$cart_fields[$price_number]); $subtotal = sprintf ("%.2f\n", $unformatted_subtotal); $unformatted_grand_total = $grand_total + $subtotal; $grand_total = sprintf ("%.2f\n", $unformatted_grand_total); print qq!!; } # End of while () close (CART); # Finally, print out the footer. print qq!
$fieldQuantitySubtotal
\$$cart_fields[$display_number]$cart_fields[$display_number]$quantity \$$subtotal

Pre-shipping Grand Total Not Including Quantity Discount = \$$grand_total

!; exit; }