|
Server : Apache/2.4.62 System : FreeBSD fbsdweb2.web.rcn.net 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64 User : www ( 80) PHP Version : 8.3.8 Disable Function : NONE Directory : /domains/thomasjolly1/cgi-bin/ |
Upload File : |
# For the most part, web_store_html_lib.pl contains all
# of the customizable HTML aspects of this application.
# If you want to change the look and feel of the Web Store
# installation, it is most likely that you will have to
# make changes to this file.
#
# Usually, this is as simple as cutting and
# pasting some of your template HTML in place of our
# default code. However, there are a few things that you
# should know about before you start doing it.
#
# Firstly. as always, make a backup of the original file
# before you start doing anything. Also, when you make
# changes, do it in a series of small changes. Make
# many small changes, running the script each time. That
# way you won't make so many changes that you won't
# know at which point you made your error.
#
# Secondly, this library uses the "qq" function liberally.
# That means that you need to be aware of what the
# delimiter is in every bit of HTMLcode displayed. For
# the most part, we use the standard "qq!" and "qq~" when
# we are going to display a long bit of HTML code. the qq
# function will change the delimiter of a print string
# from double quote marks (") to whatever follows the
# "qq". This is done to allow double quote marks to be
# included in strings to be printed without using the
# backslash (\) character, which is very common
# in HTML. (How else would Perl know that the double quote
# marks in the string to be printed are supposed to be
# "part" of the string to be printed and not actually the
# "end" of the string to be printed? Recall that we use
# the double quote marks to delineate the beginning and
# the ending of a text string to be printed.
#
# Thus,
#
# print "She said \"hi\"";
#
# would become
#
# print qq!She said "Hi"!;
#
# Notice that in the first case, we had to escape the
# double quote marks in order to use the double quote
# marks as string delimiters. Since we use a lot of
# double quote marks in our HTML, it is easier to just
# change the delimiter to the bang (!) sign or the tilde
# (~) sign.
#
# However, though the qq method does solve the problem of
# embedded double quotes, it does not solve the problem of
# Perl special characters. If you wish to include a
# dollar sign ($) or an at sign (@) you will need to
# escape them with a backslash (\). Thus, to display
#
# send all $$$ to [email protected]
#
# you must use backslashes as follows
#
# send all \$\$\$ to selena\@eff.org
#
# The reason for this is that the dollar and at signs have
# special meanings to perl other than to denote price or
# an email address; specifically, to name scalar variables
# and list arrays.
#
# If you are getting a documnet contains no data error, it
# is a good bet you forgot to escape a Perl special
# character in this file.
#
# A fourth thing to keep in mind is that we have included
# some variables within the default displays. For
# example, in product_page_header below, we use both
# $page_title as well as $hidden_fields within the HTML.
# You probably want to leave these the way they are and
# write your own template HTML "around" them. If
# you delete them, make sure to keep a log of the changes
# you made so that you can use them if you want them
# later.
#
# Finally, a quick note about library syntax is in
# order since it will help you understand what is
# happening.
#
# There are three types of algorithms that you will be
# faced with in the Web Store:
#
# Individual algorithms
# Application Specific Subroutines
# Inter-Application Libraries
#
# Individual Algorithms
#
# Algorithms are merely pieces of code that perform some
# sort of action in a specific way. For example, an
# algorithm that adds two numbers, can be
# expressed as
#
# x + y.
#
# However, its usage is very specific. To add 31,289
# and 23,990, you would use the following Perl code:
#
# $sum = 31289 + 23990;
#
# This is a pretty simple routine. But it is also pretty
# specific to just one case. Programs typically consist
# of many routines like this put together. However, there
# comes a time when you will want to make the routine
# generic so that you can call it over and over again in
# other parts of the program without having to rewrite the
# routine. This is where application-specific subroutines
# come in.
#
# Application Specific Subroutines
#
# Routines that are general enough that they are used
# several times in the same application should usually be
# placed in a subroutine. A subroutine encapsulates an
# algorithm so that other parts of the program can refer
# to it by its subroutine name. Consider the addition
# algorithm from above.
#
# What if we needed to add various numbers several times
# through our program, but did not want to create a
# separate piece of code for each instance of addition?
# If the algorithm were four or five lines long, it
# would be a drag to type the similar lines over and over
# again. Even worse, if you ended up changing the logic of
# the algorithm you would have to hunt down every
# occurrence of the algorithm and change each one.
# Maintaining a program like this could become a nightmare
# since many errors could arise from forgetting to change
# one of the lines of code in any of the duplicate
# routines, or changing one of them incorrectly.
#
# When faced with such a circumstance, a programer can
# create a "subroutine" within the application which can
# be used again and again by other parts of
# the program. web_store.cgi uses subroutines liberally.
# In fact, 90% of the program is actually contained in one
# subroutine or another.
#
# In order to create and use subroutines in Perl, we need
# three things: a subroutine reference, a subroutine
# identifier, and a parameter list of variables to pass to
# the subroutine.
#
# [NOTE] Subroutine definitions can be placed anywhere in
# the script even if the call to that subroutine appears
# earlier in the program. This is because Perl first goes
# through the entire script and compiles references
# to all subroutines before it actually starts running the
# script. Although the subroutines may be placed anywhere
# in the program, their definitions are usually placed at
# the end of the script since it makes the main code
# easier to find and read.
#
# In order to use a subroutine, the ampersand (&) symbol
# precedes the name of the routine. This tells Perl to
# look for the subroutine in the program and call it. For
# example, "&AddNumbers" would direct Perl to execute the
# AddNumbers subroutine.
#
# However, we will also need to be able to send the
# subroutine some information. Specifically, we will need
# to send the subroutine parameters which it will use to
# customize it's output. If we want to get the sum of
# two and three, for example, we can pass two and three to
# the subroutine using the following format:
#
# &AddNumbers(2,3);
#
# As we mentioned above, the ampersand marker tells Perl
# to actually look for the subroutine in the program in
# order to call it.
#
# The definition of the subroutine itself is marked off in
# the program using a "sub" marker and the code belonging
# to the routine is delimited with curly brackets ({}).
# The following example shows what the AddNumber
# subroutine definition would look like:
#
# sub AddNumbers
# {
# local($first_number, $second_number) = @_;
# print $first_number + $second_number;
# }
#
# Note the third line above. We use the "local" keyword to
# make sure that the $first_number and $second_number
# variables will be considered local to only that
# subroutine. That is, the subroutine will not affect any
# other variables that may be called $first_number or
# $second_number in other subroutines within the program.
#
# Also, in Perl, @_ is a special name for the list of
# parameters that have been passed to the function.
# $first_number is set equal to the first parameter and
# $second_number is set equal to the second parameter in
# the @_ list of parameters. If the routine is called by
# "&AddNumbers(2,3)", 2 and 3 will be assigned to
# $first_number and $second_number respectively.
#
# [NOTE] It is important to use local variables within
# subroutines so that they do not overwrite variables used
# by the main script. In complex scripts which use dozens
# of variables, you may easily forget which variables you
# are using. Using local variables assures that if you do
# end up using the same name for a variable; you keep them
# separated. Whenever you want to add numbers, you can
# simply use the subroutine call &AddNumbers(x,y) instead
# of writing out each addition individually. As an
# added bonus, if you need to change the logic of the
# addition algorithm, you need only change it in the
# subroutine.
#
# Inter-Application Libraries
#
# Good design does not stop with the mere use of
# subroutines though. Often, several different scripts
# will incorporate the use of similar routines into their
# design. Or similar or customizable subroutines will be
# broken out for easy access or modification (as in the
# case of web_store_html_lib.pl ). In this case, it makes
# sense to remove the common routines from the programs
# and place them in a separate file of routines.
#
# This file can then be loaded as a library of subroutines
# into each program as needed.
#
# For example, most CGI applications will need a form
# gathering/parsing routine, a template for sending out
# the HTTP header, and perhaps one to
# generate template HTML code such as:
#
# <HTML><HEAD><TITLE>My Script Title</TITLE></HEAD>
#
# In this case, we use library files and "require" them
# from the main script. A library file in Perl is simply
# a text file containing subroutines that are shared in
# common by several different Perl scripts.
#
# [NOTE] In addition to all the normal Perl code for
# subroutines, a Perl library must end with a "1;" on
# the last line. This is because the REQUIRE command
# evaluates the script when it reads in the library
# routines. The last "1;" makes the script itself evaluate
# to TRUE. In other words, a return value of 1 in the Perl
# library means the library was read in successfully by
# the main Perl script.
#
# In order for these library files to be usable by the
# script, the permissions must be set on the library file
# to make it readable, and the script must be in the Perl
# library path or its location must be explicitly
# referenced with its directory path location. For
# example, if we wanted to load Steven Brenner's
# "cgi-lib.pl" library into our script and "cgi-lib.pl"
# was located in the same directory as the script calling
# it or was in a directory included in the @INC array, we
# would use the following:
#
# require "cgi-lib.pl";
#
# When this is done, every subroutine in cgi-lib.pl
# becomes accessible to the main script as if it were
# actually written into the script's code. Thus we can
# simply reference a subroutine contained in cgi-lib.pl as
# we would any other subroutine in the main program.
#
# [NOTE] Library files need to be readable by the script
# that requires them. If your server is running as
# "Nobody" in reference to Chapter one on setting up
# script permissions, you may need to make the library
# files readable by the world.
#
# Well, that was mouthful. But now you are ready to go
# and play havoc with the HTML in this file. Don't forget
# to make a backup but feel free to experiment. The store
# distributed by default is kept bland on purpose. By
# reminaing simple, it makes customizing the interface
# easier for more people. It is your job to turn
# the default interface into your own unique store.
#
# If you would like to see how others have customized the
# interface, check out Selena Sol's Script Archive. There
# you can explore the "Web Store Scripts in Action"
# section to look at the dozens of existing and
# functioning versions.
#######################################################################
# product_page_header Subroutine #
#######################################################################
# product_page_header is used to display the shared
# HTML header used for database-based product pages. It
# takes one argument, $page_title, which will be used to
# fill the data between the <TITLE> and </TITLE>.
# Typically, this value is determined by
# $sc_product_display_title in web_store.setup.
#
# The subroutine is called with the following syntax:
#
# &product_page_header("Desired Title");
sub product_page_header
{
# First, the script assigns the incoming argument to the
# local variable $page_title
local ($page_title) = @_;
# Then, it assigns the text of all of the hidden fields
# that may need to be passed as state information to
# $hidden_fields using the make_hidden_fields subroutine
# which will be discussed later.
local ($hidden_fields) = &make_hidden_fields;
# Next, the HTML code is sent to the browser including the
# page title and the hidden fields dynamically inserted.
print qq~
<HTML>
<HEAD>
<TITLE>$page_title - $form_data{'product'}</TITLE>
</HEAD>
<BODY BGCOLOR = "FFFFFF" link="#339900" vlink="#339900" alink="#339900">
<FORM METHOD = "post" ACTION = "$sc_main_script_url">
$hidden_fields
~;
&StoreHeader;
# Next, we will grab $sc_product_display_header which is a
# preformatted string defined in web_store.setup and use
# printf to put the entire contents of
# @sc_db_display_fields in place of the format tags (%s).
# The function of this will be to display the header
# categories which products will follow.
#
# Consider the following example from web_store.setup.db:
# $sc_product_display_header = qq!
#
# <TABLE BORDER = "0">
# <TR>
# <TH>Quantity</TH>
# <TH>%s</TH>
# <TH>%s</TH>
# </TR>
# <TR>
# <TD COLSPAN = "3"><HR></TD>
# </TR>!;
#
# @sc_db_display_fields = ("Image (If appropriate)",
# "Description");
#
# In this case, the strings "Image (If appropriate)" and
# "Description" will be substituted by the printf
# function for the two %s's in the TABLE header defined in
# $sc_product_display_header.
printf($sc_product_display_header,
@sc_db_display_fields);
}
#######################################################################
# product_page_footer Subroutine #
#######################################################################
# product_page_footer is used to generate the HTML page
# footer for database-based product pages. It takes two
# arguments, $db_status and $total_rows_returned and is
# called with the following syntax:
#
# &product_page_footer($status,$total_row_count);
sub product_page_footer
{
# $db_status gives us the status returned from the database
# search engine and $total_rows_returned gives us the
# actual number of rows returned. $warn_message which
# is first initialized, will be used to generate a warning
# that the user should narrow their search in case
# too many rows were returned.
local($db_status, $total_rows_returned) = @_;
local($warn_message);
$warn_message = "";
# If the database returned a status, the script checks to
# see if it was like the string "max.*row.*exceed". If
# so, it lets the user know that they need to narrow their
# search.
if ($db_status ne "")
{
if ($db_status =~ /max.*row.*exceed.*/i)
{
$warn_message = qq!
<CENTER>
<BLOCKQUOTE>
Your query returned $total_rows_returned. This is more than
the maximum we allow ($sc_db_max_rows_returned). You will need to
restrict your query further.
</BLOCKQUOTE></CENTER><P>!;
}
}
# Then the script displays the footer information defined
# with $sc_product_display_footer in web-store.setup and
# adds the final basic HTML footer. Notice that one of the
# submit buttons, "Return to Frontpage" is isolated into
# the $sc_no_frames_button variable. This is because in
# the frames version, we do not want that option as it
# will cause an endlessly fracturing frame system. Thus,
# in a frame store, you would simply set
# $sc_no_frames_button to "" and nothing would print here.
# Otherwise, you may include that button in your footer
# for ease of navigation. The variable itself is defined
# in web_store.setup. The script also will print the
# warning message if there is a value for it.
print qq~
$sc_product_display_footer
<P>
$warn_message~;
&StoreFooter;
print qq~
</BODY>
</HTML>~;
exit;
}
#######################################################################
# html_search_page_footer Subroutine #
#######################################################################
# html_search_page_footer is used to generate the HTML
# footer for HTML-based product pages when the script
# must perform a keyword search and generate a list of
# hits. It is called with no argumnets with the following
# syntax:
#
# &html_search_page_footer;
#
# Notice again the use of $sc_no_frames_button in place of
# the "Return to Frontpage" button as discussed in the
# last section.
sub html_search_page_footer
{
print qq!
<CENTER>
<INPUT TYPE = "submit" NAME = "modify_cart_button"
VALUE = "View/Modify Cart">
$sc_no_frames_button
<INPUT TYPE = "submit" NAME = "order_form_button"
VALUE = "Checkout Stand">
</FORM>
</CENTER>
</BODY>
</HTML>!;
}
#######################################################################
# standard_page_header Subroutine #
#######################################################################
# standard_page_header is used to generate a standard HTML
# header for pages within either the HTML-based or
# Database-based stores. It takes a single argumnet, the
# title of the page to be displayed and is called with the
# following syntax:
#
# &standard_page_header("TITLE");
#
# Note, as in the case of product_page_header, all state
# variables must be passed as hidden fields. These hidden
# fields are generate by make_hidden_fields discussed
# later.
sub standard_page_header
{
local($type_of_page) = @_;
local ($hidden_fields) = &make_hidden_fields;
print qq!
<HTML>
<HEAD>
<TITLE>$type_of_page</TITLE>
</HEAD>
<BODY link="#339900" vlink="#339900" alink="#339900">
<FORM METHOD = "post" ACTION = "$sc_main_script_url">
$hidden_fields
!;
}
#######################################################################
# modify_form_footer Subroutine #
#######################################################################
# modify_form_footer is used to generate the HTML footer
# code for the "modify quantity of items in the cart" form
# page. It takes no arguments and is called with the
# following syntax:
#
# &modify_form_footer;
#
# As usual, we will admit the "Return to Frontpage" button
# only if we are not using frames by defining it with the
# $sc_no_frames_button in web_store.setup.
sub modify_form_footer
{
print qq!
<P>
<INPUT TYPE = "submit" NAME = "submit_change_quantity_button"
VALUE = "Submit Changes">
<INPUT TYPE = "submit" NAME = "continue_shopping_button"
VALUE = "Continue Shopping">
</FORM>
</CENTER>!;
&StoreFooter;
print qq!
</BODY>
</HTML>!;
}
#######################################################################
# delete_form_footer Subroutine #
#######################################################################
# delete_form_footer is used to generate the HTML footer
# code for the "delete items from the cart" form
# page. It takes no arguments and is called with the
# following syntax:
#
# &delete_form_footer;
#
# As usual, we will admit the "Return to Frontpage" button
# only if we are not using frames by defining it with the
# $sc_no_frames_button in web_store.setup.
sub delete_form_footer
{
print qq!
<P>
<INPUT TYPE = "submit" NAME = "submit_deletion_button"
VALUE = "Submit Deletion">
<INPUT TYPE = "submit" NAME = "continue_shopping_button"
VALUE = "Continue Shopping">
</FORM>
</CENTER>!;
&StoreFooter;
print qq!
</BODY>
</HTML>!;
}
#######################################################################
# cart_footer Subroutine #
#######################################################################
# cart_footer is used to generate the HTML footer
# code for the "view items in the cart" form
# page. It takes no arguments and is called with the
# following syntax:
#
# &cart_footer;
#
# As usual, we will admit the "Return to Frontpage" button
# only if we are not using frames by defining it with the
# $sc_no_frames_button in web_store.setup.
sub cart_footer
{
print qq!
<P><HR WIDTH=500></P>
<INPUT TYPE = "submit" NAME = "change_quantity_button" VALUE = "Edit Quantity">
<INPUT TYPE = "submit" NAME = "delete_item_button" VALUE = "Remove Items">
</FORM>
<FORM METHOD=POST ACTION=$sc_order_script_url>
<INPUT TYPE = "submit" NAME = "order_form_button" VALUE = "Complete Secure Order">
<INPUT TYPE = HIDDEN NAME="cart_id" VALUE = $cart_id>
</FORM>
</CENTER>!;
&StoreFooter;
print qq!
</BODY>
</HTML>!;
}
#######################################################################
# bad_order_note Subroutine #
#######################################################################
# bad_order_note generates an error message for the user
# in the case that they have not submitted a valid number
# for a quantity. It takes no argumnets and is called
# with the following syntax:
#
# &bad_order_note;
sub bad_order_note
{
local($button_to_set) = @_;
$button_to_set = "try_again" if ($button_to_set eq "");
&standard_page_header("Error");
&StoreHeader;
print qq!
<CENTER><H2>Error</H2></CENTER>
<BLOCKQUOTE>
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<P>
<CENTER>
<INPUT TYPE = "submit" NAME = "$button_to_set" VALUE = "Try Again">
</CENTER>
</BLOCKQUOTE>
</BODY>
</HTML>!;
exit;
}
#######################################################################
# cart_table_header Subroutine #
#######################################################################
# cart_table_header is used to generate the header
# HTML for views of the cart. It takes one argument, the
# type of view we are requesting and is called with the
# following syntax:
#
# &cart_table_header(TYPE OF REQUEST);
sub cart_table_header
{
local ($modify_type) = @_;
# We take modify_type and make it into a table header if
# it has a value. If it does not have a value, then we
# don't want to output a needless column. There are
# really only four values that modify type should be
# equal to:
#
# 1. "" (View/Modify Cart or Order Form Screen)
# 2. "New Quantity" (Change Quantity Form)
# 3. "Delete Item" (Delete Item Form)
# 4. "Process Order" (Order Form Process Confirmation)
#
# These four types distinguish the five types of pages on
# which a cart will be displayed. We need to know these
# values in order to determine if there will be an extra
# table header in the cart display. In the case of
# quantity changes or delete item forms, there must be an
# extra table cell for the checkbox and textfield inputs
# so that the customer can select items. In the
# View/Modify cart screen ($modify_type ne ""), no extra
# cell is necessary.
if ($modify_type ne "")
{
$modify_type = "<TH>\ \;$modify_type\ \;</TH>";
}
&StoreHeader;
print qq!
<CENTER>
<TABLE BORDER = "1" CELLPADDING="4">
<TR>
$cart_font_style
$modify_type!;
# @sc_cart_display_fields is the list of all of the table
# headers to be displayed in the cart display table and is
# defined in web_store.setup.
foreach $field (@sc_cart_display_fields)
{
print qq!<TH>$cart_font_style $field </FONT></TH>\n!;
}
# We'll also add on table headers for Quantity and
# Subtotal.
print qq!<TH>$cart_font_style Quantity </FONT></TH>\n<TH>$cart_font_style Subtotal </FONT></TH>\n</TR>\n!;
}
#######################################################################
# display_cart_table Subroutine #
#######################################################################
# The job of display_cart_table is to display the current
# contents of the user's cart for several diffferent
# types of screens which all display the cart in some form
# or another. The subroutine takes one argumnet, the
# reason that the cart is being displayed, and is called
# with the following syntax:
#
# &display_cart_table("reason");
#
# There are really only five values that
# $reason_to_display_cart should be equal to:
#
# 1. "" (View/Modify Cart Screen)
# 2. "changequantity" (Change Quantity Form)
# 3. "delete" (Delete Item Form)
# 4. "orderform" (Order Form)
# 5. "process order" (Order Form Process Confirmation)
#
# Notice that this corresponds closely to the list in
# cart_table_header because the goal of this subroutine is
# to fill in the actual cells of the table created by
# cart_table_header
sub display_cart_table
{
# Working variables are initialized and defined as local
# to this subroutine. Don't mess with these definitions.
local($reason_to_display_cart) = @_;
local(@cart_fields);
local($cart_id_number);
local($quantity);
local($unformatted_subtotal);
local($subtotal);
local($unformatted_grand_total);
local($grand_total);
local($price);
local($text_of_cart);
local($total_quantity) = 0;
local($total_measured_quantity) = 0;
local($display_index);
local($counter);
local($hidden_field_name);
local($hidden_field_value);
local($display_counter);
local($product_id, @db_row);
# Next the script determines which type of cart display it
# is being asked to produce. It uses pattern matching to
# look for key phrases in the ($reason_to_display_cart
# defined as an incoming argument. Whatever the case, the
# subroutine calls cart_table_header to begin outputting
# the HTML cart display.
if ($reason_to_display_cart =~ /change*quantity/i)
{
&cart_table_header("New Quantity");
}
elsif ($reason_to_display_cart =~ /delete/i)
{
&cart_table_header("Delete Item");
}
else
{
&cart_table_header("");
}
# Next, the client's cart is read line by line (file open
# errors handled by file_open_error as usual).
open (CART, "$sc_cart_path") ||
&file_open_error("$sc_cart_path",
"display_cart_contents", __FILE__, __LINE__);
while (<CART>)
{
# Since every line in the cart will be displayed as a cell
# in an HTML table, we begin by outputting an opening
# <TR> tag.
print "<TR>";
# Next, the current line has it's final newline charcater
# chopped off.
chop;
# Then, the script splits the row in the client's cart
# and grabs the unique product ID number, the unique cart
# id number, and the quantity. We will use those values
# while processing the cart.
@cart_fields = split (/\|/, $_);
$cart_row_number = pop(@cart_fields);
push (@cart_fields, $cart_row_number);
$quantity = $cart_fields[0];
$product_id = $cart_fields[1];
# Next we will need to begin to distinguish between types
# of displays we are being asked for because each type of
# display is slightly different. For example, if we are
# being asked to display a cart for the delete item
# form, we will need to add a checkbox before each item so
# that the customer can select which items to delete. If,
# on the other hand, we are being asked for modify the
# quantity of an item form, we need to add a text field
# instead, so that the customer can enter a new quantity.
#
# The first case we will handle is if we are being asked
# to display the cart as part of order processing.
if (($reason_to_display_cart =~ /process.*order/i) &&
($sc_order_check_db =~ /yes/i))
{
# If we are displaying the cart for order
# processing AND we are checking the
# database to make sure that the product being
# ordered is OK, then we need to load the
# database libraries if they have not been
# required already.
if (!($sc_db_lib_was_loaded =~ /yes/i))
{
&require_supporting_libraries (__FILE__, __LINE__,
"$sc_db_lib_path");
}
# Then, we call the check_db_with_product_id
# in the database library. If it returns
# false, then we output a footer
# complaining about the problem and
# exit the program.
if (!(&check_db_with_product_id($product_id,*db_row)))
{
print qq~
</TR></TABLE>
Product ID: $product_id not found in database. Your
order will NOT be processed without this validation!
</BODY>
</HTML>~;
exit;
}
# Otherwise, we check the returned row
# with the price of the product in the
# cart. If the prices do not match
# then another complaint message is printed
# and we exit the program.
else
{
if ($db_row[$sc_db_index_of_price] ne
$cart_fields[$sc_cart_index_of_price])
{
print qq~
</TR></TABLE>
Price for product id:$product_id did not match
database! Your order will NOT be processed without
this validation!
</BODY>
</HTML>~;
exit;
}
} # End of Else
} # End of if (($reason_to_display_cart =~ /process.*order/i)...
# Remember, we need to use the display_table_cart
# to keep track of totals such as quantity, subtotal,
# and total measured quantity.
#
# Directly below, we keep track of total quantity.
$total_quantity += $quantity;
# Now, we need to fill in the table row for every cart
# database row. @sc_display_numbers defined in the database
# 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_fields array.
#
# Hidden fields are generated with the items
# in the cart if we are displaying the order
# form, and wish the form to be submitted
# to a different CGI script that merely takes in
# all form values indiscriminantly.
if (($reason_to_display_cart =~ /order*form/i) &&
($sc_order_with_hidden_fields =~ /yes/i))
{
$counter++;
$hidden_field_name = "cart-"
. substr("000", length($counter))
. $counter;
$hidden_field_value = join("\|", @cart_fields);
$hidden_field_value =~ s/\"/~qq~/g;
$hidden_field_value =~ s/\>/~gt~/g;
$hidden_field_value =~ s/\</~lt~/g;
print qq!
<INPUT TYPE = "HIDDEN" NAME = "$hidden_field_name" VALUE = "$hidden_field_value">
!;
}
# In the case of a quantity change form, we will need to
# create a cell for the text field in which the customer
# can input a new quantity. The NAME value is set equal
# to the unique cart id number of the current item so that
# when we submit this information, the items will be
# associated with the new quantities.
if ($reason_to_display_cart =~ /change*quantity/i)
{
print qq!
<TD ALIGN = "center">
<INPUT TYPE = "text" NAME = "$cart_row_number" SIZE ="3"></TD>!;
}
# Similarly, in the case of a delete item form, we must
# include a cell with a checkbox so that the customer can
# select items to delet efrom their cart. The NAME value
# is set equal to the unique cart id number of the
# current item so that when we submit this information,
# the items will be associated with the checked
# checkboxes.
elsif ($reason_to_display_cart =~ /delete/i)
{
print qq!
<TD ALIGN = "center">
<INPUT TYPE = "checkbox" NAME = "$cart_row_number">!;
}
# $display_counter is set equal to zero. This variable
# will be used for
#
# $text_of_cart is initialized with two newlines. This
# variable will be used to hold the entire formatted cart
# contents in one string so that we will be able to send a
# nicely formatted copy of the cart as plain ASCII to a
# log file or as email to the admin. We'll be using the
# ".=" operator to append to the variable rather than
# overwrite it.
$display_counter = 0;
$text_of_cart .= "\n\n";
# Now, for every item in the cart row which should be
# displayed as defined in the setup file, we'll do two
# things. First, we'll append the data to the
# $text_of_cart variable (formatting it nicely). Then we
# will display the data as a table cell.
#
# However, there are three types of data which must be
# displayed in table cells but which must be formatted
# slightly differently.
#
# The first type of cell is a cell with no data. To give
# the table a nice three dimensional look to it, we will
# substitute all occurances of no data for the
# character in order to get a blank but indented table
# cell. Of course, this routine simply overwrites the
# empty value of the data with the character, it
# does not actually display the cell...instead, it passes
# that job on to the next if test.
#
# Another case is when a table cell must reflect a price.
# In that case we must format the data with the monetary
# symbol defined in web_store.setup using display_price
# discused in web_store.cgi.
#
# Finally, non proce table cells are displayed (including
# those passed down from the first case.
foreach $display_index (@sc_cart_index_for_display)
{
# Reformat blank cells.
if ($cart_fields[$display_index] eq "")
{
# The text of the cart is entered into a buffer
#
# The actual item being purchased is formatted
# inside a 25 character width field
$text_of_cart .= &format_text_field(
$sc_cart_display_fields[$display_counter]) .
"= nothing entered\n";
$cart_fields[$display_index] = " ";
}
# Display price cell.
if (($display_index == $sc_cart_index_of_price_after_options)||
($display_index == $sc_cart_index_of_price))
{
$price = &display_price($cart_fields[$display_index]);
print qq!<TD ALIGN = "center">$cart_font_style$price</FONT></TD>\n!;
$text_of_cart .= &format_text_field(
$sc_cart_display_fields[$display_counter]) .
"= $price\n";
}
# Display all other cells (blank cells have already been
# reformatted)
else
{
print qq!<TD ALIGN = "center">$cart_font_style$cart_fields[$display_index]</FONT></TD>\n!;
if ($display_index != 5)
{
$text_of_cart .= &format_text_field(
$sc_cart_display_fields[$display_counter]) .
"= $cart_fields[$display_index]\n";
}
}
# If the current display index happens to be a cell which
# must be measured, we will add the value to
# $total_measured_quantity for later calculation and
# display.
if ($display_index == $sc_cart_index_of_measured_value)
{
$total_measured_quantity += $cart_fields[$display_index];
$shipping_total = $total_measured_quantity;
}
$display_counter++;
} # End of foreach $display_index (@sc_cart_index_for_display)
# 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[$sc_cart_index_of_price_after_options]);
$subtotal = &format_price($unformatted_subtotal);
$unformatted_grand_total = $grand_total + $subtotal;
$grand_total = &format_price($unformatted_grand_total);
$price = &display_price($subtotal);
print qq!<TD ALIGN = "center">$cart_font_style$quantity</FONT></TD>
<TD ALIGN = "center">$cart_font_style$price</FONT></TD>
</TR>!;
$text_of_cart .= &format_text_field("Quantity") .
"= $quantity\n";
$text_of_cart .= &format_text_field("Subtotal For Item") .
"= $price\n";
} # End of while (<CART>)
close (CART);
# Finally, print out the footer with the cart_footer
# subroutine in web_store.html.
$price = &display_price($grand_total);
&cart_table_footer($price);
# In the case of an order form, we will also have to
# create a hidden input tag with which to transfer the
# subtotal state information to the order processing
# routines.
#
# This is really only necessary if the order
# is being submitted to another server which
# does not have access to the cart file.
# for processing against
if (($reason_to_display_cart =~ /order*form/i) &&
($sc_order_with_hidden_fields =~ /yes/i))
{
$hidden_field_name = "subtotal";
$hidden_field_value = $subtotal;
print qq!
<INPUT TYPE = "HIDDEN" NAME = "$hidden_field_name"
VALUE = "$hidden_field_value">
!;
}
# The Subtotal info is also added to $text_of_cart
$text_of_cart .= "\n\n" . &format_text_field("Subtotal:") .
"= $price\n\n";
# We need to return the subtotal for those routines such
# as ordering calculations
#
# We also need to return the text of the cart in case we
# are logging orders to email or to a file
return($grand_total,
$total_quantity,
$total_measured_quantity,
$text_of_cart);
} # End of display_cart_table
#######################################################################
# cart_table_footer Subroutine #
#######################################################################
# cart_table_footer is used to display the footer for cart
# table displays. It takes one argumnet, the pre shipping
# grand total and is called with the following syntax:
#
# &cart_table_footer(PRICE);
sub cart_table_footer
{
local($price) = @_;
print qq!
</TABLE>
<P>
Subtotal = $price
<P>!;
}
#######################################################################
# make_hidden_fields Subroutine #
#######################################################################
# make_hidden_fields is used to generate the hidden fields
# necessary for maintaining state. It takes no arguments
# and is called with the following syntax:
#
# &make_hidden_fields;
sub make_hidden_fields
{
local($hidden);
local($db_query_row);
local($db_form_field);
# $hidden is defined initially as containing the cart_id
# and page hidden tags which are necessry state variables
# on EVERY page in the cart.
#
# The script then goes through checking to see which
# optional state variables it has received as incoming
# form data. For each of those, it adds a hidden input
# tag.
$hidden = qq!
<INPUT TYPE = "hidden" NAME = "cart_id" VALUE = "$cart_id">
<INPUT TYPE = "hidden" NAME = "page" VALUE = "$form_data{'page'}">!;
if ($form_data{'keywords'} ne "")
{
$hidden .= qq!
<INPUT TYPE = "hidden" NAME = "keywords"
VALUE = "$form_data{'keywords'}">!;
}
if ($form_data{'exact_match'} ne "")
{
$hidden .= qq!
<INPUT TYPE = "hidden" NAME = "exact_match"
VALUE = "$form_data{'exact_match'}">!;
}
if ($form_data{'case_sensitive'} ne "")
{
$hidden .= qq!
<INPUT TYPE = "hidden" NAME = "case_sensitive"
VALUE = "$form_data{'case_sensitive'}">!;
}
foreach $db_query_row (@sc_db_query_criteria)
{
$db_form_field = (split(/\|/, $db_query_row))[0];
if ($form_data{$db_form_field} ne "" && $db_form_field ne "keywords")
{
$hidden .= qq!
<INPUT TYPE = "hidden" NAME = "$db_form_field"
VALUE = "$form_data{$db_form_field}">!;
}
}
return ($hidden);
} # End of make_hidden_fields
#######################################################################
# PrintNoHitsBodyHTML Subroutine #
#######################################################################
# PrintNoHitsBodyHTML is utilized by the HTML-based store
# search routines to produce an error message in case no
# hits were found based on the client-defined keyords
# It is called with no argumnets and the following syntax:
#
# &PrintNoHitsBodyHTML;
sub PrintNoHitsBodyHTML
{
print qq!
<P>
<CENTER>
<H2>Sorry, No Pages Were Found With Your Keyword(s).</H2>
</CENTER>
<P>!;
}
##################################################################
# PrintBodyHTML Subroutine #
##################################################################
# PrintBodyHTML is utilized by the HTML-based store
# search routines to produce a list of hits. These hits
# will be the pages which had the client-defined keywords
# within them. The subroutine takes two arguments, the
# filename as it will appear in the URL link as well as
# the text which should be visibly hyperlinked and is
# called with the following syntax:
#
# &PrintBodyHTML("file.name", "Title to be linked");
sub PrintBodyHTML
{
local($filename, $title) = @_;
print qq!
<LI><B>
<A HREF = "$sc_main_script_url?page=$filename&cart_id=$cart_id">$title</A>
</B>(/$filename)!;
}
1;