Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Sort help needed in sloppy code. :(

Status
Not open for further replies.

FixItPete

Programmer
Feb 19, 2008
11
US
I have a long sub. that is *very* sloppy and I need to have it sort by the variable $item_id which is the first field in the flat file db that this sub get's its information from. If I am not making sense, please don't beat me up too bad... I don't know exactly what I'm talking about. I know just enough to get me into trouble. :D

Hope you can help!

Thanks!



Here is the code:

#######################################################################
# create_html_page_from_db Subroutine #
#######################################################################

# create_html_page_from_db is used to genererate the
# navigational interface for database-base stores. It is
# used to create both product pages and "list of products"
# pages. The subroutine takes no arguments and is called
# with the following syntax:
#
# &create_html_page_from_db;

sub create_html_page_from_db
{

# First, the script defines a few working variables which
# will remain local to this subroutine.



local (@database_rows, @database_fields, @item_ids, @display_fields);



local ($total_row_count, $id_index, $display_index);
local ($row, $field, $empty, $option_tag, $option_location, $output);









# Next the script checks to see if there is actually a
# page which must be displayed. If there is a value for
# the page variable incoming as form data, (ie: list of
# product page) the script will simply display that page
# with the display_page subroutine and exit.

if ($page ne "" && $form_data{'search_request_button.x'} eq "" &&
$form_data{'continue_shopping_button.x'} eq "")
{
&display_page("$sc_html_product_directory_path/$form_data{'page'}",
"Display Products for Sale", __FILE__, __LINE__);
exit;
}

# If there is no page value, then the script knows that it
# must generate a dynamic product page using the value of
# the product form variable to query the database.
#
# First, the script uses the product_page_header
# subroutine in order to dynamically generate the product
# page header. We'll pass to the subroutine the value of
# the page we have been asked to display so that it can
# display something useful in the <TITLE></TITLE> area.
#
# The product_page_header subroutine is located in
# web_store_html_lib.pl and $sc_product_display_title is
# defined in the setup file.

## Remarked by Jimmy
# &product_page_header($sc_product_display_title);

if ($form_data{'add_to_cart_button.x'} ne "" &&
$sc_shall_i_let_client_know_item_added eq "yes")
{
print "$sc_item_ordered_message";
}

# Next the database is querried for rows containing the
# value of the incoming product variable in the correct
# category as defined in web_store.setup. The script uses
# the submit_query subroutine in web_store_db_lib.pl
# passing to it a reference to the list array
# database_rows.
#
# submit_query returns a descriptive status message
# if there was a problem and a total row count
# for diagnosing if the maximum rows returned
# variable was exceeded.


if (!($sc_db_lib_was_loaded =~ /yes/i)) {
&require_supporting_libraries (__FILE__, __LINE__,
"$sc_db_lib_path");
}

($status, $total_row_count) = &submit_query(*database_rows,
$form_data{'hits_seen'});
$hits_seen = $form_data{'hits_seen'} + $sc_db_max_rows_returned;



if ($total_row_count == 0)
{


&search_not_found_bac;

exit;
}

else {
## Added By Jimmy
## &product_page_header($sc_product_display_title);


##$product_category =~ tr/._/ /;


######################################
#Category Page Headers from flat file#
######################################

open(prod_page_title,"$ENV{'DOCUMENT_ROOT'}/cgi-local/titleinfo.data")||die "Can't Read file";
@prodpagetitle=<prod_page_title>;
close(prod_page_title);


foreach $ttrec(@prodpagetitle){
($orig_cat,$title_desc,$keytry,$metadesc)=split(/\|/,$ttrec);

if ($orig_cat eq $product_category)
{
$product_category = $title_desc;
$key_try = $keytry;
$meta_desc = $metadesc;
}

else
{
$product_category=$product_category
}
}


if ($product_category eq "")
{
&product_page_header($sc_product_display_title);
}
else
{
&product_page_header($product_category, $key_try, $meta_desc);
}
###########################################
#End Category Page Headers (for SEs)#######
###########################################

## Removed by PMT $hits_seen = $form_data{'hits_seen'} + $sc_db_max_rows_returned;


# Now that the script has the database rows to be
# displayed, it will display them.
#
# Firstly, the script goes through each database row
# contained in @database_rows splitting it into it's
# fields.
#
# For the most part, in order to display the database
# rows, the script will simply need to take each field
# from the database row and substitute it for a %s in the
# format string defined in web_store.setup.
#
# However, in the case of options which will modify a
# product, the script must grab the code from an options
# file.
#
# The special way that options are denoted in the database
# are by using the format %%OPTION%%option.html in the
# data file. This string includes two important bits of
# information.
#
# Firstly, it begins with %%OPTION%%. This is a flag
# which will let the script know that it needs to deal
# with this database field as if it were an option. When
# it sees the flag, it will then look to the bit after the
# flag to see which file it should load. Thus, in this
# example, the script would load the file option.html for
# display.
#
# Why go through all the trouble? Well basically, we need
# to create a system which will handle large chunks of
# HTML code within the database that are very likely to be
# similar. If there are options on product pages, it is
# likely that they are going to be repeated fairly
# often. For example, every item in a database might have
# an option like tape, cd or lp. By creating one
# options.html file, we could easily put all the code into
# one shared location and not need to worry about typing
# it in for every single database entry.

#print @database_rows;





foreach $row (@database_rows)
{
@database_fields = split (/\|/, $row);
foreach $field (@database_fields)



#pmt play
#print "$field";


{
#print "$field\n";

######TRYTRYTRY#####

if ($field =~ /%%cart_id%%/)
{
$field =~ s/%%cart_id%%/$cart_id/g
} # End of if ($field =~ /%%cart_id%%/)


if ($field =~ /%%session_id_place%%/)
{
$field =~ s/%%session_id_place%%/$session_id_place/g
} # End of if ($field =~ /%%session_id_place%%/)


if ($field =~ /%%detail%%/)
{
$field =~ s/%%detail%%/$detail/g
} # End of if ($field =~ /%%detail%%/)


#####KEEP THIS HINT print $field;



#############



# For every field in every database row, the script simply
# checks to see if it begins (^) with %%OPTION%%. If so,
# it splits out the string into three strings, one
# empty, one equal to OPTION and one equal to the location
# of the option to be used. Then the script resets the
# field to null because it is about to overwrite it.

if ($field =~ /^%%OPTION%%/)
{
($empty, $option_tag, $option_location) = split (/%%/, $field);
$field = "";

# The option file is then opened and read. Next, every
# line of the option file is appended to the $field
# variable and the file is closed again. However, the
# current product id number is substituted for the
# %%PRODUCT_ID%% flag

open (OPTION_FILE, "<$sc_options_directory_path/$option_location")
||
&file_open_error ("$sc_options_directory_path/$option_location",
"Display Products for Sale", __FILE__,
__LINE__);

while (<OPTION_FILE>)
{
s/%%PRODUCT_ID%%/$database_fields[$sc_db_index_of_product_id]/g;
$field .= $_;
}
close (OPTION_FILE);
} # End of if ($field =~ /^%%OPTION%%/)
} # End of foreach $field (@database_fields)




# Finally, the database fields (including the option field
# which has been recreated) are stuffed into the format
# string, $sc_product_display_row and the entire formatted
# string is printed to the browser along with the footer.
#
# First, however, we must format the fields correctly.
# Initially, @display_fields is created which contains the
# values of every field to be displayed, including a
# formatted price field.

#######################################################







########################################################
@display_fields = ();
@temp_fields = @database_fields;


if ($form_data{'detail'} eq "yes")
{
@sc_db_index_for_display = @sc_db_index_for_display_detail;
$sc_product_display_row = $sc_product_display_row_new;
}


foreach $display_index (@sc_db_index_for_display)
{
if ($display_index == $sc_db_index_of_price)
{
$temp_fields[$sc_db_index_of_price] =
&display_price($temp_fields[$sc_db_index_of_price]);
}
push(@display_fields, $temp_fields[$display_index]);
}

# Then, the elements of the NAME field are created so that
# customers will be able to specify an item to purchase.
# We are careful to substitute double quote marks ("), and
# greater and less than signs (>,<) for the tags ~qq~,
# ~gt~, and ~lt~. The reason that this must be done is so
# that any double quote, greater than, or less than
# characters used in URL strings can be stuffed safely
# into the cart and passed as part of the NAME argumnet in
# the "add item" form. Consider the following item name
# which must include an image tag.
#
# <INPUT TYPE = "text"
# NAME = "item-0010|Vowels|15.98|The letter A|~lt~IMG SRC = ~qq~Html/Images/a.jpg~qq~ ALIGN = ~qq~left~qq~~gt~"
#
# Notice that the URL must be edited. If it were not, how
# would the browser understand how to interpret the form
# tag? The form tag uses the double quote, greater
# than, and less than characters in its own processing.

@item_ids = ();
foreach $id_index (@sc_db_index_for_defining_item_id)
{
$database_fields[$id_index] =~ s/\"/~qq~/g;
$database_fields[$id_index] =~ s/\>/~gt~/g;
$database_fields[$id_index] =~ s/\</~lt~/g;
push(@item_ids, $database_fields[$id_index]);
}

# Finally, $sc_product_display_row is created with the two
# arrays using printf to apply the formatting.
#
{





#SreeJune
sree_printf ($sc_product_display_row,
join("\|",@item_ids),
@display_fields);
}
} # End of foreach $row (@database_rows)


if ($form_data{'detail'} eq "yes")
{
&product_page_footer_detail($status, $total_row_count, $hits_seen); # replaced authors $total_rows_returned
}
else
{
&product_page_footer($status, $total_row_count, $hits_seen); # replaced authors $total_rows_returned
}

}
exit;
}
 
What got me started on this is this code:

(He sorted by date, which is not what I want, I want to sort by the first field in the db, which is the item number.)

Don't know if this helps... but I'm lost:

Code:
Hi guys just added a new functionality to the web_store script That I thought you might want to show folks. 

I'm doing two separate implementations of the script that require things be displayed sorted by date. I looked through the forum and saw I wasn't the only one wanting to do this so I took it upon myself to try figuring out the ever so cryptic sort command. The result is actually usable for any type of field you might wish to sort by. It's not the cleanest code in the world but it works. 

step 1.) add this to the end of the web_store.cgi file: 


#######################################
# -JV- presort results I've added this little
# snippet to allow results 
# of a search to be sorted by the start date
# of the particular event
# This of course can be adjusted to sort by whatever
# you wish and even 
# added to the search criteria with out too much
# trouble. Of course you 
# also need to add the date_to_unix subroutine to
# get this to actually 
# work for date sorting.
##############################################
sub get_this_sorted {

@data_sorted = @database_rows;

        foreach (@data_sorted) {
                ($item_num,$type,$price,$start,$end,
                 $locat,$name,$pictur,$desc,$options,
                 $avail) = split /\|/; # get start
              $start{$_} = $start; # record it
        }
    @database_rows = sort {
               &date_to_unix($start{$a}) <=>
               &date_to_unix($start{$b});
        } @data_sorted;
        }
        
sub date_to_unix {
#####################################
# This routine just takes your date
# format and return the  UNIX time().
#####################################
    my ($date)   = $_[0]; 
    my (%months) = ("Jan" => 0, "Feb" => 1, "Mar" => 2,
                    "Apr" => 3, "May" => 4, "Jun" => 5, 
                    "Jul" => 6, "Aug" => 7, "Sep" => 8,
                    "Oct" => 9, "Nov" => 10,"Dec" => 11);
 my ($time);
    my ($day, $mon, $year) = split(/-/, $_[0]);
    unless ($day and $mon and $year)  { return undef; }
    unless (defined($months{$mon}))   { return undef; }    

 use Time::Local;
    eval {  
  $day = int($day); $year = int($year) - 1900; 
        $time = timelocal(0,0,0,$day, $months{$mon}, $year);
    };
    if ($@) { return undef; } # Could return 0 if you want.
    return ($time); 
}

Step 2.) call the get_this_sorted routine from the subroutine create_html_page_from_db in web_store.cgi somewhere around line 1928 just before the foreach statement used on @database_rows. That's it! It can be customized to sort by whatever field you want and can even be added to the search criteria with a simple if statement. With all the brain damage I went through to get this figured out, I thought I'd try to spare others that fate. As soon as I get these projects done (they were supposed to be done yesterday), I'll do a better job of integrating it by putting a couple of variables into the setup file.
 
the more code you post the less likely you are to get help. Try and narrow down the scope of your problem to something people reading your post will take the time to review. I don't even see $item_id anywhere in your code.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
without knowing what your data is:

Code:
sub get_this_sorted {
   @data_sorted = @database_rows;

   @database_rows = map {$_->[0]}
                    sort {$a->[1] <=> $b->[1]} 
                    map {[$_,(split(/\|/))[0]]} @data_sorted;
}

untested and no garauntees it works as-is.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Thanks KevinADC...

Where/how would I call that sub?

Thanks again!
 
Ok... Here is what I got so far,

This is VERY freaky... it works, but not for everything. For example. On some results it DOES sort by product id (which in this case is done in the defining of $sc_db_index_for_sort as: $db{"product_id"}

On others the sort "jumps around" is there something wrong with the code?

If anyone could help me on this, it would be great... I'm happy to forward the two files that spoken about below.

Thanks!
Pete

This is what I am following as the modification to the code:

Code:
First establish a variable in your setup file, $sc_db_index_for_sort, to indicate which field you'll be sorting by. Then this code could be places right after submit_query, at about line 1883 in web_store.cgi: 


foreach $row (@database_rows) 
{ 
chomp $row; 
@tmp = split (/\|/,$row); 
$tmp_row = "$tmp[$sc_db_index_for_sort]\|$row"; 
push (@rows_to_sort,"$tmp_row\n"); 
} 
@sorted_rows = sort(@rows_to_sort); 
@database_rows = (); 

foreach $sorted_row (@sorted_rows) 
{ 
@tmp = split(/\|/,$sorted_row); 
shift @tmp; 
push(@database_rows,join("\|",@tmp)); 
} 

It says, "For each row, chomp any extraneous newline off the end (in case the field we wanna sort by is the last field on the row, in which case its having a newline might get interesting :-), then split its fields into a temporary holding array so we can locate the one field we want to sort by. Find that field, and glue it onto the front of the $row (adding back a newline at the end), and stash the lengthened rows into a holding array. Sort what's in that array. Empty out $database_rows. For each of the sorted rows, split them one more time and discard the field we glued on at the front. Then stash them all back into @database_rows, and continue normally from that point.
 
Where/how would I call that sub?

The code I posted was a drop in replacement for the sub routine you posted:

Code:
sub get_this_sorted {

@data_sorted = @database_rows;

        foreach (@data_sorted) {
                ($item_num,$type,$price,$start,$end,
                 $locat,$name,$pictur,$desc,$options,
                 $avail) = split /\|/; # get start
              $start{$_} = $start; # record it
        }
    @database_rows = sort {
               &date_to_unix($start{$a}) <=>
               &date_to_unix($start{$b});
        } @data_sorted;
        }

I thought that was where you were wanting to sort the data by $item_num.

Can't tell why your code does sort how you think it should because I have no idea what the data is you are sorting.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
What do the keys look like?

Are they numeric but getting sorted as text or something like that?

When you say it jumps around, are you able to work out what the pattern is?
 
wardy,

The more I look at it, the more it looks like the code:

Code:
foreach $row (@database_rows) 
{ 
chomp $row; 
@tmp = split (/\|/,$row); 
$tmp_row = "$tmp[$sc_db_index_for_sort]\|$row"; 
push (@rows_to_sort,"$tmp_row\n"); 
} 
@sorted_rows = sort(@rows_to_sort); 
@database_rows = (); 

foreach $sorted_row (@sorted_rows) 
{ 
@tmp = split(/\|/,$sorted_row); 
shift @tmp; 
push(@database_rows,join("\|",@tmp)); 
}

is in the wrong place in the sub... only I have NO idea where it goes... I keep moving it around... and nothing... at this point should I attach the files in question?
 
If you let us see some of the data we can tell you how to sort it, but we can't tell you where to put it in your script.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Thanks guys I was wayyyyyy too tired last night. I have a clearer picture of things now!... and a slight change. We want to sort by PRICE, NOT item #. So in the db below, it is the third field (in this example |4.95|)

If there is another file you need that this file calls... PLEASE let me know and I'll get what you need. I really need help! :)

Here is the a sample of the database (pipe delimited):

Code:
60000|WaterCandle|4.85|Romantic Water Candles|<a href="/webstore/web_store.cgi?keywords=tn_pic60000lg&detail=yes&amp;cart_id=%%cart_id%%&amp;session_id_place=%%session_id_place%%"><IMG BORDER="0" SRC=Html/Images/tn_pic60000lg.jpg></a>|Floating Water Candles - Burns corn, vegetable, or olive oil!  You get 5 discs and enough wicks for 800 hours of candlelight!! (2.5" wide)|<IMG SRC="Html/Images/pic60000lg.jpg">||More information about water candles can be found  <a href="/webstore/web_store.cgi?page=watercandlepage.html&amp;cart_id=%%cart_id%%&amp;session_id_place=%%session_id_place%%"><font color ="#000080">here</font></a>.

and here is the .cgi file, alllllll of it... :)

Code:
#!/usr/bin/perl -T
use Tie::STDERR 'email';

# Name: Web Store
# Authors: Selena Sol and Gunther Birznieks
# Version: 1.0
# Last Modified: 01/09/96
#
# Copyright Info: This application was written by Selena Sol (selena@eff.org, 
#	[URL unfurl="true"]http://www.eff.org/~erict)[/URL] and Gunther Birznieks
#	(gunther@clark.net) 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 Selena know where it goes so that we 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.

		# First, Perl is told to bypass its own buffer so that the
                # information generated by this script will be sent
		# immediately to the browser.

$| = 1;

		# Then, the http header is sent to the browser.  This is
		# done early for two reasons.  
		# 
		# Firstly, it will be easier to debug the script while
		# making modifications or customizing because we will be
		# able to see exactly what the script is doing.
		# 
		# Secondly, the http header is sent out early so that the
		# browser will not "time out" in case the script takes a
		# long time to complete its work. 

#print "Content-type: text/html\n\n";

		# Next we will execute a few subroutines which will define
		# the environment in which the script will operate.
		#
		# First we will require the web_store.setup file so that
		# we will be able to read in global variables.  Notice
		# that in the distribution, we have six setup files by
		# default.  We'll use frames.javascript as out basic
		# example though.
		#
		# Secondary supporting files are also read in using
		# require_supporting_libraries which is used to require
		# the supporting files needed by this script. Notice
		# that we are going to pass the current filename as well
		# as the current line number to the 
		# require_supporting_libraries subroutine.  It will use
		# these values to generate useful error messages in case
		# it is unable to read in the files requested.
		# 
		# Note: Here is where we read in all of the global
		# variables and definitions included in the setup files
		#
		# web_store.setup.* defines many global variables
		# 	for this script relative to the local server and
		#	installation.
		#
		# $sc_cgi_lib_path is the location of cgi-lib.pl which is
		#	used to parse incoming form data.
		#
		# $sc_html_setup_file_path is the location of
		# 	web_store_html_lib.pl which is used to define
		#	various customizable HTML interface headers,
		#	footers and pages.
		#
		# $sc_mail_lib_path is the location of mail-lib.pl which is
		#	used to mail non-encrypted mail to the admin
		#	about usage of the script.
		#

&require_supporting_libraries (__FILE__, __LINE__,
      "./Library/web_store.setup.frames.javascript");

&require_supporting_libraries (__FILE__, __LINE__, "./Library/cookie.lib"); 

&require_supporting_libraries (__FILE__, __LINE__, 
			      "$sc_cgi_lib_path",
			      "$sc_html_setup_file_path", 
			      "$sc_mail_lib_path");

		# Next we read and parse the incoming form data.
		# read_and_parse_form_data is a very short subroutine
		# which simply uses the ReadParse subroutine in cgi-lib.pl
		# to parse the incoming form data into the associative
		# array, %form_data.

&read_and_parse_form_data;

		# Once we have parsed the incoming form data,
		# we can assign the values of administrative variables to
		# regularized scalars, local to this script.
		#
		# $page will contain the path location of any pages which
		# this script is required to display.  This may be the
		# store frontpage, order form or any number of product or
		# category pages used for store navigation.
		#
		# $search_request is the value of the button used when a
		# customer submits search terms used to generate a dynamic
		# custom product page.
		#
		# $cart_id is the id number of the customer's unique cart
		# containing all of the items they have ordered so far.
		# The specifics of cart generation and maintenance are
		# covered in greater depth in the next section.
		#
		# $sc_cart_path is the actual path of the shopping cart
		# combining both $sc_user_carts_directory_path and
		# $cart_id
		#
		# These three variables are crucial state variables which
		# must be passed as form data from every instance of this
		# script to the next.	

$session_id_place = $form_data{'session_id_place'};
$page = $form_data{'page'};
$page_num = $form_data{'page_num'};

# Modified 4-10-98 Gunther Birznieks
#
# Added code to stop snooping beyond the root store HTML
# directory
#
# The following code only allows
# word characters, - sign, + sign, = sign, / for sub
# directories in the page definition
#
# If you find yourself needing more definitions the
# regular expression below is the one you want to modify
#
# One dot is allowed for an extension. I don't allow
# periods because of ../../.. type of manipulations
#
# $1 matches the first part
# $2 matches the extension which shouldnt have
# any weird characters in it, so I just left it 
# as matching \w (word characters)
$page =~ /([\w\-\=\+\/]+)\.(\w+)/;
$page = "$1.$2";
$page = "" if ($page eq ".");

$page =~ s/^\/+//; # Get rid of any residual / prefix

########################################
#See If we can get Information in title#
########################################

$product_category = $form_data{'product'};
$key_try= $form_data{'product'};
$meta_desc= $form_data{'product'};

########################################

$search_request = $form_data{'search_request_button'};
$cart_id = $form_data{'cart_id'};
if ($cart_id =~ /^(\w+)$/) {
    $cart_id = $1;
} else {
    $cart_id = "";
}
$sc_cart_path = "$sc_user_carts_directory_path/$cart_id.cart";

		# Finally we submit the incoming form data to some
		# security checks. error_check_form_data is a subroutine
		# which checks the just-parsed incoming form data to make sure 
		# that the script is only being used to display proper
		# pages (typically .html, .shtml, or .htm).
		#
		# This is an important security precaution. 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 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 might reassign page from, say,
		# "vowel.html" to "../../../etc/passwd"!  As you can
		# imagine, this could end up displaying your password file
		# to the browser window.  Thus, we need to make sure that
		# only appropriate files can be displayed by the store.

&error_check_form_data;

		# What is the purpose of a unique cart?  Well, simply,
		# every customer who is using the application must be
		# assigned a unique cart which will contain their specific
		# shopping list.  
		#
		# These carts are actually short flatfile text databases
		# stored by default in the User_carts subdirectory in the
		# format "somerandomnumber.cart". These files contain
		# information about which items the client has ordered and
		# how many of each item they ordered.
		#
		# Once a client enters the store, they are assigned their
		# own unique cart.  For the rest of their stay, the script
		# will make sure that it matches clients with their carts
		# no matter which page they go to.
		#
		# It does this by continually passing the location of the
		# cart ($cart_id) along as either hidden form data or URL
		# encoded information depending on if the customer uses a 
		# submit button or a hyperlink to navigate through the
		# store. Thus, as long as the customer follows the path
		# provided by the application, she will never lose her
		# cart.
		#
		# Thus, before anything else, the script must check to see 
		# if the client has already received a unique shopping
		# cart. If so, it will be coming in as form data and have
		# been just assigned to $cart_id.  If the script has not
		# received a shopping cart id number as form data
		# ($cart_id eq ""), however, it means that the client has
		# not yet received a unique shopping cart.
		#
		# If this is the case, the script must assign them
		# one.  However, as a matter of good housekeeping, it will
		# first take a second to delete old carts that have been
		# abandoned using the delete_old_carts subroutine
		# documented later in this script. Then, it will assign
		# the client their own fresh new cart using
		# assign_a_unique_shopping_cart_id also discussed later.

 if ($form_data{'cart_id'} eq "") { 
                    &GetCookies; 
                    if ($Cookies{'cart_id'} ne "") { 
                    $cart_id = $Cookies{'cart_id'}; 
                    } 	
                    else { 
                    &delete_old_carts; 
                    &assign_a_unique_shopping_cart_id;
                    &SetCookies('cart_id',"$cart_id"); 
                    } 
                    } 
                    else {
                    $cart_id = $form_data{'cart_id'}; 
                    }

############DEALING WITH DYNAMIC PAGES AND SEs AS WELL AS CARTS THAT HAVE BEEN CHECKED OUT#######################################

 if ($cart_id ne "") {
                 open(CHECK_ORDERS_RECEIVED,"/home/pmt/public_html/cgi-local/ordersrec.orrc")||die "Can't Read file";
		@checkedout=<CHECK_ORDERS_RECEIVED>;
      	foreach $rec(@checkedout){
      	           ($check_cart_id_already,$date_it_was_sent)=split(/\|/,$rec);
				if ($check_cart_id_already eq $cart_id)
            	 
                              {
                              $form_data{'cart_id'} = "";
 		if ($form_data{'cart_id'} eq "") { 
                    &GetCookies; 
                    if ($Cookies{'cart_id'} ne "") { 
                    $cart_id = $Cookies{'cart_id'}; 
                    } 	
                    else { 
                    &delete_old_carts; 
                    &assign_a_unique_shopping_cart_id;
                    &SetCookies('cart_id',"$cart_id"); 
                    } 
                    } 
                    else {
                    $cart_id = $form_data{'cart_id'}; 
                    } 

                              }

		}
      	close(CHECK_ORDERS_RECEIVED);
                    }
#################################################################################################################################

print "Content-type: text/html\n\n"; 
                    
############DEALING WITH DYNAMIC PAGES AND SEs AS WELL AS CARTS THAT HAVE BEEN CHECKED OUT#######################################
#may want to move print "content... above se issue code
#################################################################################################################################

		# Now that the script has created the entire environment
		# in which it must operate, it is time to provide
		# the logic for it to determine what it should do.
		#
		# The logic is broken down into a series of "if" tests.
		#
		# Specifically, the script checks the values of incoming
		# administrative form variables (mainly supplied from
		# the SUBMIT buttons on dynamically generated HTML forms)
		# and will perform its operations depending on whether
		# those administrative variables have values associated
		# with them or not.
		#
		# The basic format for such an "if" test follows the
		# syntax:
		#
		# if (the value of some submit button is not equal to nothing)
		#   {
		#   process that type of request;
		#   exit;
		#   }
		#
		# For example, consider the second case in which the
		# customer has clicked on the "Add to Cart" submit
		# button denoted with the NAME value of "add_to_cart_button". 
		#
		# elsif ($form_data{'add_to_cart_button'} ne "")
		#  {
		#  &add_to_the_cart;
		#  exit;
		#  }
		#
		# Because the submit button will have some value
		# like "Add this item to my Cart", when the script reaches
		# this line, it will answer true to the test.  
		#
		# Since the customer can only click on one submit button
		# at a time, we can be assured that only one operation
		# will answer true.  
		#
		# The beauty of using the not equal (ne) test is that
		# regardless of what the submit button actually says
		# (it might say "Add a weiner dog to the chopping block")
		# the if test will still be satisfied if they have clicked
		# the button, since whatever the VALUE is, it will
		# certainly not be equal to "nothing". Of course, this
		# assumes that you do not rename the NAME argument of the
		# submit buttons.  If you do so, you must harmonize the
		# variable you use on the input forms, with the variables
		# used here to test.
		#
		# Similarly, if you wish to have graphical submit buttons
		# instead of the ugly default buttons supplied by the
		# browser, you will have to modify the if tests so that
		# they follow the standard image map test:
		#
		# if ($form_data{'some_button.x'} ne "")
		#  {
		#  &do some subroutine;
		#  exit;
		#  }
		#
		# where the HTML code looks like the following:
		#
		# <INPUT TYPE = "image" NAME = "some_button"
		#	 SRC = "Images/button.gif" BORDER = "0">
		#
		# Thus, if the button actually has an X-dimension value
		# (any x-dimension value), it means that the button had
		# been clicked.
		#
		# Finally, note that every if test is concluded with an
		# exit statement.  This is because once the script is done
		# executing the routine specified in the submit button, it
		# is done with its work and should exit immediately.
		#
		# Get used to the idea that this script is "self-referencing".
		# The application itself contains many mini-routines
		# which all refer back to the routine community.  Every
		# instance of the script need only execute maybe 1/8th of
		# the routines in the whole file, but in the lifetime of
		# the application, most, if not all, routines are
		# executed.
		#
		# Okay, so now let's look at each of the routines which
		# this applicaiton must execute.
		#
		# 1. Adding an Item to the Shopping Cart - One
		# request that the script may have to handle is that of
		# adding an item to a shopping cart. Once the client has
		# decided to purchase an item, she will have added a
		# quantity to the text box and hit the "add this item"
		# submit button. So we must be prepared to add items to
		# the client's cart.  Additions are handled with the
		# add_to_the_cart subroutine discussed later.
		#
		# 2. Displaying the Client's Cart with Cart Manipulation
		# Options - 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 delete or modify
		# as well as send her a table depicting the current
		# contents of the shopping cart. This is all done using
		# the display_cart_contents subroutine at the end of this
		# file.
		#
		# 3. Displaying the Change Quantity Form - Yet another
		# function that this script may be asked to perform is
		# modifying the quantities of some of the items in the
		# client's cart. If the client has asked to make a
		# quantity modification, the script must give her a form
		# so that she can specify the changes she wants made.
		#
		# The form is fairly simple.  We will use the same basic
		# table presentation that we used in the
		# display_cart_contents subroutine, except that we will
		# add another column of text input fields used to submit
		# a new quantity for every row in the cart.  These text
		# input fields however, will use as there NAME argument,
		# the unique cart row number for every row.  Consider the
		# following cell definition:
		#
		# <TD><INPUT TYPE = "text" NAME = "219" SIZE ="3"></TD>
		#		
		# Thus, when the client submits a quantity change, they
		# will be submitting a cart_row_number (219) associated
		# with a quantity value (the value submitted in the text
		# field). 
		#
		# We'll use the cart row number to figure out exactly
		# which item in the cart should be modified.
		#
		# 4. Changing the Quanity of Items in the Cart - Once the
		# client has typed in some quantity changes and submitted
		# the information back to this script, we must make the
		# modifications to the database.  This is done with the
		# modify_quantity_of_items_in_cart subroutine discussed
		# below.
		#
		# 5. Displaying the Delete Item Form - Perhaps instead,
		# the client asked to delete an item rather than modify
		# the quantity.  If this is the case, the script must 
		#  display a form very similar to the one for
		# modification.  The only difference is that we will use
		# checkboxes for each item instead of text boxes because
		# in the case of delete, the user need only select which
		# items to delete rather than to also specify a quantity.
		# As in the case of modifcation, the script associates the
		# NAME argument of the checkboxes with the cart row number
		# of the item they represent. Thus, the syntax will
		# resemble the following:
		# 
		#      <TD><INPUT TYPE = "checkbox" NAME = "220"></TD>
		#
		# where 220 is the cart row number of some element which
		# can be deleted.  We will handle the display of the
		# delete item form using the output_delete_item_form
		# subroutine discussed later.
		#
		# 6. Deleting Items From the Cart - Once the client
		# submits some items to delete, the script must also
		# be able to delete them from the cart.  This is done with
		# the delete_from_cart subroutine discussed later.
		#
		# 7. Displaying the Order Form - Further, the script must
		# be able to display the order form for the client if that
		# is what they want to see.  The script uses the
		# display_page subroutine which will be discussed later to
		# display a pre-designed order form.  Note that the
		# handling of the order form will not be done by this
		# script.  Instead, the order form will reference one
		# final script which may be located in a separate,
		# "secure" directory (if one exists).  In the case of
		# secure ordering, we do not want a self-referential link
		# because we do not want the entire script being run from
		# the secure directoryt.   This would be inefficient.  The
		# only time we want to utilize the secure directory is if
		# we are processing the order.  Thus, the ordering process
		# has been broken out into its own mobile script.
		#
		# 8. Submitting the Order - Once the user fills out the
		# order form she may submit the order for final
		# processing.  Final processing involves calculating
		# shipping logic like (shipping  method, tax rates,
		# discounts, etc), sending the order to the order
		# processing administrator and letting the customer know
		# that all was completed successfully.  All orders are
		# processed by the process_order_form subroutine which is
		# designed to handle all of these chores.
		#
		# However, there is one catch to order processing: Secure
		# servers.  Many stores have secure server functionality
		# in which specific directories are designed to handle
		# encrypted communication between server and browser.
		# (typically https setups).  In this case, the cgi script
		# handling the order processing must be physically located
		# inside the secure directory.
		#
		# If this is your situation, then you must make a mirror
		# copy of the application directories and place them all
		# inside the secure area.  Then, you will set
		# $sc_order_script_url in the setup file equal to the
		# secured mirror of the script.  Then, the script will
		# dynamically refernce the secured location instead of the
		# insecure location for order processing.  In actuality,
		# only the order processing routine will be executed in
		# the secure directory, but we copy the whole script there
		# for simplicity's sake.
		# 
		# If you are not running a secure server, you may just set
		# $sc_order_script_url equla to web_store.cgi and
		# continue the regular self-referencing behavior.
		#
		# 9. Displaying Products, Categories and Misc. Pages - 
		# If the script is getting in a value for page or for
		# product, it means that it is being asked to navigate
		# through the store.
		#
		# The page variable is used to locate a page which the
		# store should display to the user.  In the case of an
		# HTML-based Web Store, the page value will be used to
		# point to both pages with products as well as pages with
		# "lists" of products.  Also in the case of the HTML-based
		# store, there will be no need for the product variable
		# since the product variable is specific to the
		# database-based store which must be able to interpret
		# between a "list of products" type page and an actual
		# product page.  This is because when the database-based
		# version creates a page to view, it needs to generate it
		# on the fly.  Thus, it searches for the product in the
		# database.  If it needs to display a "list of products"
		# type page with sub links to actual product pages within a
		# similar group,  it should not go to the database.
		# Instead, it actually needs to display a list page just
		# as the HTML-based store would do.
		#
		# As we've said, the product value will be used by the
		# database-based shopping cart to cull out the list of
		# products which the customer is interested in seeing.
		# Think of this as a sort've hard-coded search of the
		# database where the admin may hard code a category to
		# search for in the URL string which requests a product
		# page view.
		#
		# Consider the following hyperlinks as examples.
		#
		# web_store.cgi?page=Letters.html&cart_id=98.123
		# web_store.cgi?page=Numbers.html&cart_id=8708496.3559
		# web_store.cgi?product=Numbers&cart_id=2196655.5107
		#
		# The first case could be used in either the HTML or
		# Database-based version.  The script would display the
		# HTML page "Letters.html" which would be a "list of
		# products" type page.  In our distribution example page,
		# Letters.html contains links to both Vowels.html
		# and Consonants.html
		#
		# The second URL would be used for an HTML-based store.
		# It would cause this script to display the pre-designed
		# product page, Numbers.html.
		#
		# Finally, the last line would be used for a
		# database-based cart system and would cause this script
		# to search through the database for all items with
		# "Numbers" in the category field (by default, this is the
		# second field in data.file)
		#
		# Thus, there are two ways that products can be displayed
		# with this script.  
		#
		# The first way is for the store administrator to create a
		# delimited data file with all the data to be displayed
		# incorporated in database rows.  The contents of these
		# rows will be displayed according to the format defined
		# in the $sc_product_page_row variable in
		# web_store_html_lib.pl.  But this will be discussed in
		# greater detail later.
		# 
		# The second way is for the admin to create HTML
		# pages directly with the same data already incorporated
		# into some desired interface.
		#
		# The admin specifies which method she will use by setting
		# the variable $sc_use_html_product_pages in the setup file.
		# If this variable is set to yes, it means that the script
		# should simply output a predesigned HTML product page.
		# Anything else, and it will expect a database.
		#
		# The display_products_for_sale subroutine discussed
		# later does just that. However, there is
		# one catch to the presentation of an HTML page.  If the
		# client is doing a keyword search, we'll have to generate
		# a list of pages on which their keyword was founds using
		# the html-search subroutine located in
		# web_store_html_search.pl
		#
		# 10. Display The Frontpage - Finally, if all else has
		# failed, it means that we are simply being asked to
		# display the store frontpage, for no other routines
		# remain.
		#
		# To display the store front page, we will access the
		# output_frontpage subroutine discussed later.
		#
		# Okay, so those are all the cases.  Now let's go through
		# them one by one as code.
		#
		# First though, we need to set up a flag to see
		# if the user has any values inside any of the query
		# fields.
		#

$are_any_query_fields_filled_in = "no";
foreach $query_field (@sc_db_query_criteria) {
  @criteria = split(/\|/, $query_field);
  if ($form_data{$criteria[0]} ne "") {
       if ($criteria[0] =~ /price/i) {
        $form_data{$criteria[0]} =~ s/\D*(\d+\.?\d*|\.\d+)\D*/$1/g;
    }
    $are_any_query_fields_filled_in = "yes";
  }
}

if ($form_data{'add_to_cart_button.x'} ne "")
  {
  &add_to_the_cart;
  exit;
  }

elsif ($form_data{'modify_cart_button.x'} ne "")
  {
  &display_cart_contents;
  exit;
  }

elsif ($form_data{'more_item_detail.x'} ne "")
  {
  &create_html_page_from_db;
  exit;
  }

elsif ($form_data{'login_button.x'} ne "" && $session_id_place eq "")
  {
  &customer_wants_to_login;
  exit;
  }

elsif ($form_data{'login_button.x'} ne "" && $session_id_place ne "")
  {
  &already_logged_in_silly;
  exit;
  }

elsif ($form_data{'step_two_login.x'} ne "")
  {
  &login_lookup;
  exit;
  }

elsif ($form_data{'forgot_password_button.x'} ne "")
  {
  &login_forgot_password;
  exit;
  }

elsif ($form_data{'find_lost_login.x'} ne "")
  {
  &find_lost_login;
  exit;
  }

#elsif ($form_data{'lostpasswordfind'} ne "")
#  {
#  &lost_login_password_lookup;
#exit;
#  }

#################################################
#This seems to deal with a blank entry          #
#just make sure you have the hidden             #
#<input type="hidden" name="bluffer" value="on">#
#input line in the html that is used            #
#to call the lostpasswordfind                   #
#################################################

if ($form_data{'lostpasswordfind'} eq "" && $form_data{'bluffer'} eq "on")
{
#if ($form_data{'lostpasswordfind'} eq "") {

$form_data{'lostpasswordfind'} = "nothingentered";
&lost_login_password_lookup;
}
elsif ($form_data{'lostpasswordfind'})
   {
   &lost_login_password_lookup;
exit;
   }

######################################

elsif ($form_data{'change_login_info.x'} ne "" && $session_id_place eq "")
  {
  &change_login_info;
  exit;
  }

elsif ($form_data{'change_login_info.x'} ne "" && $session_id_place ne "")
  {
  &logout_first_please;
  exit;
  }

elsif ($form_data{'logout_now.x'} ne "" && $session_id_place ne "")
  {
  &log_me_out_now;
  exit;
  }

elsif ($form_data{'logout_now.x'} ne "" && $session_id_place eq "")
  {
  &you_are_not_logged_in;
  exit;
  }

elsif ($form_data{'remove_session_now.x'} ne "")
  {
  &sign_me_out_now;
  exit;
  }

elsif ($form_data{'delete_login_info.x'} ne "" && $session_id_place ne "")
  {
  &logout_first_please;
  exit;
  }

elsif ($form_data{'delete_login_info.x'} ne "" && $session_id_place eq "")
  {
  &delete_login_info;
  exit;
  }

elsif ($form_data{'change_login_step_two.x'} ne "")
  {
  &submit_change_login_check;
  exit;
  }

elsif ($form_data{'submit_login_changes.x'} ne "")
  {
  &we_have_changes_to_login_for_submission;
  exit;
  }

elsif ($form_data{'remove_login_step_two.x'} ne "")
  {
  &we_need_to_remove_id;
  exit;
  }

######### This is here to clean up the heading if a customer tries to change ###########
######### quantity from a cart that is already empty                         ###########

elsif (($form_data{'change_quantity_button.x'} ne "") && (-z $sc_cart_path))
  {
&try_to_subdel;
exit;
  }

######### End ###########

elsif ($form_data{'change_quantity_button.x'} ne "")
  {
  &output_modify_quantity_form;
  exit;
  }

elsif ($form_data{'submit_change_quantity_button.x'} ne "")
  {
  &modify_quantity_of_items_in_cart;
  exit;
  }

######### This is here to clean up the heading if a customer tries to###########
######### delete from a cart that is already empty                 ###########

elsif (($form_data{'delete_item_button.x'} ne "") && (-z $sc_cart_path))
  {
&try_to_subdel;
exit;
  }

######### End ###########

elsif ($form_data{'delete_item_button.x'} ne "")
  {
  &output_delete_item_form;
  exit;
  }

elsif ($form_data{'submit_deletion_button.x'} ne "")
  {   
  &delete_from_cart;
  exit;
  }

elsif ($form_data{'order_form_button.x'} ne "")
               {

                 
               &require_supporting_libraries (__FILE__, __LINE__,
                                           "$sc_order_lib_path");

		   $goofy=1;
               #print "dangit";
               #exit;
               &input_ship; # JPW NEWLINE: REDIRECT TO INPUT_SHIP (BELOW)
               exit;
               }

  elsif ($form_data{'order_form_button_final.x'} ne "") # BEGIN NEW ELSIF
               {

               
               &require_supporting_libraries (__FILE__, __LINE__,
                                           "$sc_order_lib_path");
		   
               &is_there_coup;
               exit;
               } # END NEW ELSIF - NEXT 3 ELSE TESTS UNCHANGED

elsif ($form_data{'real_order_form_button_final.x'} ne "") # BEGIN NEW ELSIF
               {
               &require_supporting_libraries (__FILE__, __LINE__,
                                           "$sc_order_lib_path");

               &display_order_form;
               exit;
               } # END NEW ELSIF - NEXT 3 ELSE TESTS UNCHANGED

elsif ($form_data{'submit_order_form_button.x'} ne "")
               {
               &require_supporting_libraries (__FILE__, __LINE__,
                                           "$sc_order_lib_path");

               $thurman=1;
		   &process_order_form;
               exit;
               }

#######################################################################
#This was done by PMT to address the search button if the field is    #
#left blank and submitted - it is STILL BEING TESTED                  #
#######################################################################

if ($form_data{'keywords'} eq "" && $form_data{'searchbluffer'} eq "on")
           {
           &search_not_found_bac;
	     #print "you didn't enter anything in the search box silly";
           exit;
           }
#######################################################################

 elsif (($page ne "" || $form_data{'search_request_button'} ne ""
                                 || $form_data{'continue_shopping_button'}
                                 || $are_any_query_fields_filled_in =~ /yes/i) &&
                     ($form_data{'return_to_frontpage_button.x'} eq ""))
               {
               &display_products_for_sale;
               exit;
               }

else
               {
               &output_frontpage;
               exit;
               }

                             # Well that's it.  That is the end of the program!  Well,
                             # not exactly.  That is just the end of the main body of
                             # logic.  From here on out we will define the logic of the
                             # subroutines called in the "if" tests above.

             #######################################################################
             #                     Input Shipping Rate Form                        #
             #######################################################################

                             # &input_ship is the NEW subroutine
                             # responsible for gathering the shipping details required
                             # by order_lib_pl
                             #
                             # &input_ship;

             sub input_ship
               {
               #print "silly boy";
               #exit;
		   &shipping_header_mydomain("Enter Shipping Rate");
               &input_ship_footer;
               }

#######################################################################
#                       Require Supporting Libraries.		      #
#######################################################################

		# require_supporting_libraries is used to read in some of
		# the supporting files that this script will take
		# advantage of.
		#
		# require_supporting_libraries takes a list of arguments
		# beginning with the current filename, the current line
		# number and continuing with the list of files which must
		# be required using the following syntax:
		#
		# &require_supporting_libraries (__FILE__, __LINE__,
		#				"file1", "file2",
		#				"file3"...);
		#
		# Note: __FILE__ and __LINE__ are special Perl variables
		# which contain the current filename and line number
		# respectively.  We'll continually use these two variables
		# throughout the rest of this script in order to generate
		# useful error messages.

sub require_supporting_libraries
  {

		# The incoming file and line arguments are split into
		# the local variables $file and $line while the file list
		# is assigned to the local list array @require_files.
		#
		# $require_file which will just be a temporary holder
		# variable for our foreach processing is also defined as a
		# local variable.

  local ($file, $line, @require_files) = @_;
  local ($require_file);

		# Next, the script checks to see if every file in the
		# @require_files list array exists (-e) and is readable by
		# it (-r). If so, the script goes ahead and requires it.

  foreach $require_file (@require_files)
    {
    if (-e "$require_file" && -r "$require_file")
      {
      require "$require_file";
      }

		# If not, the scripts sends back an error message that
		# will help the admin isolate the problem with the script.

    else
      {
      print "I am sorry but I was unable to require $require_file at line
  	    $line in $file.  Would you please make sure that you have the
	    path correct and that the permissions are set so that I have
	    read access?  Thank you.";
      exit;
      }
    } # End of foreach $require_file (@require_files)
  } # End of sub require_supporting_libraries

#######################################################################
#                     Read and Parse Form Data.			      #
#######################################################################

		# read_and_parse_form_data is a short subroutine 
		# responsible for calling the ReadParse subroutine in
		# cgi-lib.pl to parse the incoming form data.  The script 
		# also tells cgi-lib to prepare that information in the
		# associative array named %form_data which we will be able
		# to use for the rest of this script.
		#
		# read_and_parse_form_data takes no arguments and is
		# called with the following syntax:
		#
		# &read_and_parse_form_data;

sub read_and_parse_form_data
  {
  &ReadParse(*form_data);
  }

#######################################################################
#                     Error Check Form Data.                          #   
####################################################################### 

		# error_check_form_data is responsible for checking to
		# make sure that only authorized pages are viewable using
		# this application. It takes no arguments and is called
		# with the following syntax:
		#
		# &error_check_form_data;
		#
		# The routine simply checks to make sure that if
		# the page variable extension is not one that is defined
		# in the setup file as an appropriate extension like .html
		# or .htm, or there is no page being requestd (ie: the
		# store front is being displayed) it will send a warning
		# to the user, append the error log, and exit.
		#
		# @acceptable_file_extensions_to_display is an array of
		# acceptable file extensions defined in the setup file.
		# To be more or less restrictive, just modify this list.
		#
		# Specifically, for each extension defined in the setup
		# file, if the value of the page variable coming in from
		# the form ($page) is like the extension (/$file_extension/) 
		# or there is no value for page (eq ""), we will set
		# $valid_extension equal to yes.  
		
sub error_check_form_data
  {
  foreach $file_extension (@acceptable_file_extensions_to_display)
    {
    if ($page =~ /$file_extension/ || $page eq "")
      {
      $valid_extension = "yes";
      }
    }

		# Next, the script checks to see if $valid_extension has
		# been set to "yes".
		#
		# If the value for page satisfied any of the extensions 
		# in @acceptable_file_extensions_to_display, the script
		# will set $valid_extension equal to yes. If the value 
		# is set to yes, the subroutine will go on with it's work.
		# Otherwise it will exit with a warning and write to the
		# eror log if appropriate
		#
		# Notice that we pass three parameters to the
		# update_error_log subroutine which will be discussed
		# later. The subroutine gets a warning, the
		# name of the file, and the line number of the error.
		#
		# $sc_page_load_security_warning is a variable set in
		# web_store.setup.  If you want to give a more or less
		# informative error message, you are welcome to change the
		# text there.

  if ($valid_extension ne "yes")
    {
    print "$sc_page_load_security_warning";
    &update_error_log("PAGE LOAD WARNING", __FILE__, __LINE__);
    exit;
    }        
  }

#######################################################################
#                        Delete Old Carts. 	                      #
#######################################################################

		# delete_old_carts is a subroutine which is used to prune
		# the carts directory, cleaning out all the old carts
		# after some time interval defined in the setup file.  It
		# takes no argumnetes and is called with the following
		# syntax:
		#
		# &delete_old_carts;

sub delete_old_carts
  {

		# The subroutine begins by grabbing a listing of all of
		# the client created shoppping carts in the User_carts
		# directory.
		#
		# It then opens the directory and reads the contents using
		# grep to grab every file with the extension .cart. Then
		# it closes the directory.  
		#
		# If the script has any trouble opening the directory,
		# it will output an error message using the
		# file_open_error subroutine discussed later.  To the
		# subroutine, it will pass the name of the file which had
		# trouble, as well as the current routine in the script
		# having trouble , the filename and the current line
		# number.

  opendir (USER_CARTS, "$sc_user_carts_directory_path") ||
           &file_open_error("$sc_user_carts_directory_path", 
	  		    "Delete Old Carts", __FILE__, __LINE__);
  @carts = grep(/\.cart/,readdir(USER_CARTS));
  closedir (USER_CARTS);
      
		# Now, for every cart in the directory, delete the cart if
		# it is older than half a day.  The -M file test returns
		# the number of days since the file was last modified.
		# Since the result is in terms of days, if the value is
		# greater than the value of $sc_number_days_keep_old_carts
		# set in web_store.setup, we'll delete the file.

  foreach $cart (@carts)
    {
      if ($cart =~ /^(\w+\.cart)$/) {
          $cart = $1;
          if (-M "$sc_user_carts_directory_path/$cart" > $sc_number_days_keep_old_carts) {
             unlink("$sc_user_carts_directory_path/$cart");
          }
      }
    } # end of foreach

  } # End of sub delete_old_carts

#######################################################################
#                        Delete Old Login_Sessions. 	                #
#######################################################################

		# delete_old_login_sessions is a subroutine which is used to prune
		# the login_sessions directory, cleaning out all the old login_sessions
		# after some time interval defined in the setup file.  It
		# takes no argumnetes and is called with the following
		# syntax:
		#
		# &delete_old_carts;

sub delete_old_login_sessions
  {

		# The subroutine begins by grabbing a listing of all of
		# the client created shoppping carts in the User_carts
		# directory.
		#
		# It then opens the directory and reads the contents using
		# grep to grab every file with the extension .cart. Then
		# it closes the directory.  
		#
		# If the script has any trouble opening the directory,
		# it will output an error message using the
		# file_open_error subroutine discussed later.  To the
		# subroutine, it will pass the name of the file which had
		# trouble, as well as the current routine in the script
		# having trouble , the filename and the current line
		# number.

  opendir (LOGIN_SESSIONS, "$sc_login_sessions_directory_path") ||
           &file_open_error("$sc_login_sessions_directory_path", 
	  		    "Delete Old Login Sessions", __FILE__, __LINE__);
  @login_sessions = grep(/\.sess/,readdir(LOGIN_SESSIONS));
  closedir (LOGIN_SESSIONS);
      
		# Now, for every cart in the directory, delete the cart if
		# it is older than half a day.  The -M file test returns
		# the number of days since the file was last modified.
		# Since the result is in terms of days, if the value is
		# greater than the value of $sc_number_days_keep_old_carts
		# set in web_store.setup, we'll delete the file.

  foreach $login_sessions (@login_sessions)
    {
      if ($login_sessions =~ /^(\w+\.sess)$/) {
          $login_sessions = $1;
          if (-M "$sc_login_sessions_directory_path/$login_sessions" > $sc_number_days_keep_old_login_sessions) {
             unlink("$sc_login_sessions_directory_path/$login_sessions");
          }
      }
    } # end of foreach

  } # End of sub delete_old_carts

#######################################################################
#                        Assign a Shopping Cart.                      #   
#######################################################################  

		# assign_a_unique_shopping_cart_id is a subroutine used to
		# assign a unique cart id to every new clinet.  It takes
		# no argumnets and is called with the following syntax:
		#
		# &assign_a_unique_shopping_cart_id;

sub assign_a_unique_shopping_cart_id
  {

		# First we will check to see if the admin has asked us to
		# log all new clients.  If so, we will get the current
		# date using the get_date subroutine discussed later, open the 
		# access log file for appending, and print to the access
		# log file all of the environment variable values as well
		# as the current date and time.  
		#
		# However, we will protect ourselves from multiple,
		# simultaneous writes to the access log by using the
		# lockfile routine documented at the end of this file,
		# passing it the name of a temporary lock file to use.
		#
		# Remember that there may be multimple simultaneous
		# executions of this script because there may be many
		# people shopping all at once.  It would not do if one
		# customer was able to overwrite the information of
		# another customer if they accidentally wanted to acccess
		# the log file at the same exact time.

    if ($sc_shall_i_log_accesses eq "yes")
      {
      $date = &get_date;
      &get_file_lock("$sc_access_log_path.lockfile");
      open (ACCESS_LOG, ">>$sc_access_log_path");

		# Using the keys function, the script grabs all the
		# keys of the %ENV associative array and assigns them as
		# elements of @env_keys.  It then creates a new row for
		# the access log which will be a pipe delimited list of
		# the date as well as all the environment variables and
		# their values.

      @env_keys = keys(%ENV);
 
      $new_access = "$date\|";
      foreach $env_key (@env_keys)
        {
        $new_access .= "$ENV{$env_key}\|";
        }

		# The script then takes off the final pipe, adds the new
		# access to the log file, closes the log file and removes
		# the lock file.

      chop $new_access;
      print ACCESS_LOG "$new_access\n";
      close (ACCESS_LOG);
      &release_file_lock("$sc_access_log_path.lockfile");
      }

		# Now that the new access is recorded, the script assigns 
		# the user their own unique shopping cart.  To do so,
		# it generates a random (rand) 8 digit (100000000)
		# integer (int) and then appends to that string the current
		# process id ($$). However, the srand function is seeded
		# with the time and the current process id in order to
		# produce a more random random number.  $sc_cart_path is
		# also defined now that we have a unique cart id number.

    srand (time|$$);
    $cart_id = int(rand(10000000));
    $cart_id .= "A$$";
    $cart_id =~ s/-//g;
    $sc_cart_path = "$sc_user_carts_directory_path/${cart_id}.cart";

		# However, before we can be absolutely sure that we have
		# created a unique cart, the script must check the existing
		# list of carts to make sure that there is not one with
		# the same value.
		#
		# It does this by checking to see if a cart with the
		# randomly generated ID number already exists in the Carts
		# directory.  If one does exit (-e), the script grabs
		# another random number using the same routine as
		# above and checks again.  
		#
		# Using the $cart_count variable, the script executes this
		# algorithm three times.  If it does not succeede in finding
		# a unique cart id number, the script assumes that there is
		# something seriously wrong with the randomizing routine
		# and exits, warning the user on the web and the admin
		# using the update_error_log subroutine discussed later.

    $cart_count = 0;

    while (-e "$sc_cart_path")
      {
      if ($cart_count == 3)
        {
        print "$sc_randomizer_error_message";
        &update_error_log("COULD NOT CREATE UNIQUE CART ID", __FILE__,
   			  __LINE__);
        exit;
        }

      $cart_id = int(rand(10000000));
      $cart_id .= "A$$";    
      $cart_id =~ s/-//g;
      $sc_cart_path = "$sc_user_carts_directory_path/${cart_id}.cart";
      $cart_count++;

      } # End of while (-e $sc_cart_path)
       
		# Now that we have generated a truly unique id
		# number for the new client's cart, the script may go
		# ahead and create it in the User_carts sub-directory.  
		#
		# If there is a problem opening the new cart, we'll output
		# an error message with the file_open_error subroutine
		# discussed later.

    open (CART, ">$sc_cart_path") ||
  	  &file_open_error("$sc_cart_path",
                           "Assign a Shopping Cart", __FILE__, __LINE__);

}

#######################################################################   
#                       Output Frontpage.                             #
#######################################################################  

		# output_frontpage is used to display the frontpage of the
		# store.  It takes no argumnets and is accessed with the
		# following syntax:
		#
		# &output_frontpage;
		#
		# The subroutine simply utilizes the display_page
		# subroutine which is discussed later to output the
		# frontpage file, the location of which, is defined
		# in web_store.setup.  display_page takes four arguments:
		# the cart path, the routine calling it, the current
		# filename and the current line number.

sub output_frontpage
  {
  &display_page("$sc_store_front_path", "Output Frontpage", __FILE__,
		__LINE__);
  }

#######################################################################
#                    Add to Shopping Cart                             #
#######################################################################

		# The add_to_the_cart subroutine is used to add items to
		# the customer's unique cart.  It is called with no
		# arguments with the following syntax:
		#
		# &add_to_the_cart;

sub add_to_the_cart
  {
		# the script first opens the user's shopping cart with read/write access,
		# creating it if for some reason it is not already there. If there is a
		# problem opening the file, it will call file_open_error subroutine
		# to handle the error reporting.

		open (CART, "+>>$sc_cart_path") ||
			&file_open_error("$sc_cart_path",
				"Add to Shopping Cart", __FILE__, __LINE__);

		# The script then retrieves the highest item number of the items already
		# in the cart (if any). The item number is an arbitrary number used to
		# uniquely identify each item, as described below.

		$highest_item_number = 100;				# init highest item number (start at 100)
		seek (CART, 0, 0);						# make sure we're positioned at top of file
		while (<CART>)							# loop on cart contents, if any
		{
			chomp $_;							# get rid of terminating newline
		    my @row = split (/\|/, $_);			# split cart row into fields
    		my $item_number = pop (@row);		# get item number of row (last field)
			$highest_item_number = $item_number if ($item_number > $highest_item_number);
		}

		# $highest_item_number is now either the highest item number,
		# or 100 if the cart was empty. Position the file pointer to the
		# end of the cart, in preparation for appending the new items later.

		seek (CART, 0, 2);						# position to end of file

		# The script must first figure out what the client has
		# ordered.
		#
		# It begins by using the %form_data associative array
		# given to it by cgi-lib.pl.  It takes all of the keys
		# of the form_data associative array and drops them into
		# the @items_ordered array.
		#
		# Note: An associative array key is like a variable name
		# whereas an associative array value is the
		# value associated with that variable name. The
		# benefit of an associative array is that you can have
		# many of these key/value pairs in one array.
		# Conveniently enough, you'll notice that input fields on
		# HTML forms will have associated NAMES and VALUES
		# corresponding to associative array KEYS and VALUES.
		#
		# Since each of the text boxes in which the client could
		# enter quantities were associated with the database id
		# number of the item that they accompany, (as defined
		# in the display_page routine at the end of this
		# script), the HTML should read
		#
		#         <INPUT TYPE = "text" NAME = "1234">
		#
		# for the item with database id number 1234 and
		#
		#         <INPUT TYPE = "text" NAME = "5678">
		#
		# 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 associative
		# array and 5678 is associated with 9.  The script uses
		# the keys function to pull out just the keys.  Thus,
		# @items_ordered would be a list like (1234, 5678, ...).

  @items_ordered = keys (%form_data);

		# Next it begins going through the list of items ordered
		# one by one.

  foreach $item (@items_ordered)
    {

		# However, there are some incoming items that don't need
		# to be processed. Specifically, we do not care about cart_id,
		# page, keywords, add_to_cart, or whatever incoming
		# administrative variables exist because these are all
		# values set internally by this script. They will be
		# coming in as form data just like the client-defined
		# data, and we will need them for other things, just not
		# to fill up the user's cart. In order to bypass all of
		# these administrartive variables, we use a standard
		# method for denoting incoming items.  All incoming items
		# are prefixed with the tag "item-".  When the script sees
		# this tag, it knows that it is seeing an item to be added
		# to the cart.
		#
		# Similarly, items which are actually options info are
		# denoted with the "option" keyword.  We will also accept
		# those for further processing.
		#
		# And fo course, 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 =~ /^item-/i ||
        $item =~ /^option/i) &&
        $form_data{$item} ne "")
      {

		# Once the script has determined that the current element
		# ($item) of @items_ordered is indeeed a non-admin item,
		# it must separate out the items that have been ordered
		# from the options which modify those items.  If $item
		# begins with the keyword "option", which we set
		# specifically in the HTML file, the script will add
		# (push) that item to the array called @options.  However,
		# before we make the check, we must strip the "item-"
		# keyword off the item so that we have the actual row
		# number for comparison.

        $item =~ s/^item-//i;

        if ($item =~ /^option/i)
          {
          push (@options, $item);
          }

		# On the other hand, if it is not an option, the script adds
		# it to the array @items_ordered_with_options, but adds
		# both the item and its value as a single array element.
		#
		# The value will be a quantity and the item will be
		# something like "item-0001|12.98|The letter A" as defined in
		# the HTML file.  Once we extract the initial "item-"
		# tag from the string using regular expressions ($item =~
		# s/^item-//i;), the resulting string would be something
		# like the following:
		#
		#           2|0001|12.98|The letter A
		#
		# where 2 is the quantity.
		#
		# Firstly, it must be a digit ($form_data{$item} =~ /\D/).
		# That is, we do not want the clients trying to enter
		# values like "a", "-2", ".5" or "1/2".  They might be
		# able to play havok on the ordering system and a sneaky
		# client may even gain a discount because you were not
		# reading the order forms carefully.
		#
		# Secondly, the script will dissallow any zeros
		# ($form_data{$item} == 0).  In both cases the client will
		# be sent to the subroutine bad_order_note located in
		# web_store_html_lib.pl.

        else
          {
          if (($form_data{"item-$item"} =~ /\D/) ||
              ($form_data{"item-$item"} == 0))
            {
	    &bad_order_note;
            }
          else
            {
            $quantity = $form_data{"item-$item"};
            push (@items_ordered_with_options, "$quantity\|$item\|");
	    }
 	  }
        } # End of if ($item ne "$variable" && $form_data{$item} ne "")
    } #End of foreach $item (@items_ordered)


		# Now the script goes through the array
		# @items_ordered_with_options one item at a time in order
		# to modify any item which has had options applied to it.
		# Recall that we just built the @options array with all
		# the options for all the items ordered.  Now the script
		# will need to figure out which options in @options belong
		# to which items in @items_ordered_with_options.

  foreach $item_ordered_with_options (@items_ordered_with_options)
    {

		# First, 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.  Note that we have defined the index location of
		# some important fields in web_store.setup.  Specifically,
		# the script must know the index of quantity, item_id and
		# item_price within the array.  It will need these values
		# in particular for further calculations.  Also, the
		# script will change all occurances of "~qq~" to a double
		# quote (") character, "~gt~" to a greater than sign (>)
		# and "~lt~" to a less than sign (<).  The reason that
		# this must be done is so that any double quote, greater
		# than, or less than characters used in URLK strings can
		# be stuffed safely into the cart and passed as part of
		# the NAME argumnet in the "add item" form.  Consider the
		# following item name which must include an image tag.
		#
		# <INPUT TYPE = "text"
		#	 NAME = "item-0010|Vowels|15.98|The letter A|~lt~IMG SRC = ~qq~Html/Images/a.jpg~qq~ ALIGN = ~qq~left~qq~~gt~"
		#
		# Notice that the URL must be edited. If it were not, how
		# would the browser understand how to interpret the form
		# tag?  The form tag uses the double quote, greater
                # than, and less than characters in its own processing.

     $item_ordered_with_options =~ s/~qq~/\"/g;
     $item_ordered_with_options =~ s/~gt~/\>/g;
     $item_ordered_with_options =~ s/~lt~/\</g;

     @cart_row = split (/\|/, $item_ordered_with_options);
     $item_quantity = $cart_row[$sc_cart_index_of_quantity];
     $item_id_number = $cart_row[$sc_cart_index_of_item_id];
     $item_price = $cart_row[$sc_cart_index_of_price];

		# Then for every option in @options, the script splits up
		# each option into it's fields.
		#
		# Once it does both splits, the script can compare the name
		# of the item with the name associated with the option.
		# If they are the same, it knows that this is an option
		# which was meant to enhance this item.

    foreach $option (@options)
      {
      ($option_marker, $option_number, $option_item_number) = split
	    (/\|/, $option);

		# If the script finds a match, it records the option
		# information contained in the $option variable.

      if ($option_item_number eq "$item_id_number")
	{

		# Since it must apply this option to this item, the script
		# splits out the value associated with the option and
		# appends it to $options.  Once it has gone through all of
		# the options, using .=, the script will have one big string
		# containing all the options so that it can print them
		# out. Note that in the form on which the client chooses
		# options, each option is denoted with the form
		#
		#            NAME = "a|b|c" VALUE = "d|e"
		#
		# where
		#
		# a is the option marker "option"
		# b is the option number (you might have multiple options
		#	which all modify the same item.  Option number
		#	identifies each option uniquely)
		# c is the option item number (the unique item id number
		#	which the option modifies)
		# d is the option name (the descriptive name of the
		#	option)
		# e is the option price.
		#
		# For example, consider this option from the default
		# Vowels.html file which modifies item number 0001:
		#
		#      <INPUT TYPE = "radio" NAME = "option|2|0001"
                #             VALUE = "Red|0.00" CHECKED>Red<BR>
		#
		# This is the second option modifying item number 0001.
		# When displayed in the display cart sscreen, it will read
		# "Red 0.00, and will not affect the cost of the item.

        ($option_name, $option_price) = split (/\|/,$form_data{$option});
        $options .= "$option_name $option_price,";

		# But the script must also calculate the cost changes with
		# options. To do so, it will take the current value of
		# $option_grand_total and add to it the value of the
		# current option.  It will then format the result to
		# two decimal places using the format_price subroutine
		# discussed later and assign the new result to
		# $option_grand_total

  	$unformatted_option_grand_total = $option_grand_total + $option_price;
        $option_grand_total = &format_price($unformatted_option_grand_total);

  	} # End of if ($option_item_number eq "$item_id_number")
      } # End of foreach $option (@options)

		# Next, the script takes off the last comma in options.
		# Look a few lines up, you'll see that a comma is added to
		# the end of each option.  Well the last option does not
		# need that last comma.

    chop $options;

		# Now, the script adds a space after each comma so the
		# display looks nicer.

    $options =~ s/,/, /g;

		# Next, calculate $item_number which the script can use to
		# identify a shopping cart item absolutely.  This must be done so
		# that when we modify and delete from the cart, we will
		# know exactly which item to affect. We cannot rely simply
		# on the unique database id number because a client may
		# purchase two of the same item but with different
		# options. Unless there is a separate, unique cart row id
		# number, how would the script know which to delete if the
		# client asked to delete one of the two. Add 1 to
		# $highest_item_number, which was set at the beginning of the subroutine.

    $item_number = ++$highest_item_number;

		# Finally, the script makes the last price calculations
		# and appends every ordered item to $cart_row
		#
		# A completed cart row might look like the following:
		# 2|0001|Vowels|15.98|Letter A|Times New Roman 0.00|15.98|161

    $unformatted_item_grand_total = $item_price + $option_grand_total;
    $item_grand_total = &format_price("$unformatted_item_grand_total");

    foreach $field (@cart_row)
      {
      $cart_row .= "$field\|";
      }

    $cart_row .= "$options\|$item_grand_total\|$item_number\n";

    } # End of foreach $item_ordered_with_options.....

		# When it is done appending all the items to $cart_row,
		# the script appends the new items to the end of the
		# shopping cart, which was opened at the beginning of the subroutine.

  print CART "$cart_row";
  close (CART);

		# Then, the script sends the client back to a previous
		# page.  There are two pages that the customer can be sent
		# of course, the last product page they were on or the
		# page which displays the customer's cart.  Which page the
		# customer is sent depends on the value of
		# $sc_should_i_display_cart_after_purchase which is defined
		# in web_store.setup.  If the customer should be sent to
		# the display cart page, the script calls
		# display_cart_contents, otherwise it calls display_page
		# if this is an HTML-based cart or
		# create_html_page_from_db if this is a database-based
		# cart.

  if ($sc_use_html_product_pages eq "yes")
    {
    if ($sc_should_i_display_cart_after_purchase eq "yes")
      {
      &display_cart_contents;
      }
    else
      {
      &display_page("$sc_html_product_directory_path/$page",
                    "Display Products for Sale");
      }
    }
  else
    {
    if ($sc_should_i_display_cart_after_purchase eq "yes")
      {
      &display_cart_contents;
      }

    elsif ($are_any_query_fields_filled_in =~ /yes/i)
      {
      $page = "";
      &display_products_for_sale;
      }

    else
      {
      &create_html_page_from_db;
      }
    }
  } 

#######################################################################
#                  Output Modify Quantity Form                        #
#######################################################################

		# output_modify_quantity_form is the subroutine
		# responsible for displaying the form which customers can
		# use to modify the quantity of items in their cart.  It
		# is called with no argumnets with the
 
Forget it... I give up. :( (It cut off part of the code) :(

Pete

P.S. If anyone feels like working ont his, send me a message.

 
there is no way to send messages on this forum. You are posting too much code my friend, nobody wants to look over that much code, especially not written using "strict". I already showed you one way to sort your data and you seem to have completely ignored my suggestion so I see little reason to continue trying to help you. But I wish you all the best and hope you get it working.

Kevin

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Thanks for the reply kevin,

I saw your code, however it is a sub that I would need to call... I don't know where I am suppose to call it and that is what I needed help with.

Sorry if I offended you.
 
You have not offended me at all. I suggest you reread the entire thread, skipping your posts. Or hire a programmer. I am not available. Good luck.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
We want to sort by PRICE, NOT item #. So in the db below, it is the third field (in this example |4.95|)

Looks like that field is numeric to a human but text to Perl.

So 4.95 will sort after 10.90

Is this the problem??
 
Wardy... Turns out it wasn't working at all. :(

I'm going to try it a different way and perhaps start a new thread, one without all the long-winded code, etc. :)

Thanks,
Pete
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top