KGRKJGETMRETU895U-589TY5MIGM5JGB5SDFESFREWTGR54TY
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 :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /domains/thomasjolly1/cgi-bin/web_store_html_lib.pl

		# 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>\&nbsp\;$modify_type\&nbsp\;</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&nbsp;$field&nbsp;</FONT></TH>\n!;
    }

		# We'll also add on table headers for Quantity and
		# Subtotal.

  print qq!<TH>$cart_font_style&nbsp;Quantity&nbsp;</FONT></TH>\n<TH>$cart_font_style&nbsp;Subtotal&nbsp;</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 &nbsp;
		# 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 &nbsp; 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] = "&nbsp;";
        }       

		# 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;

Anon7 - 2021