#!/usr/bin/perl
use warnings;
use CGI::Carp qw/fatalsToBrowser/;
use CGI qw(:standard);
use MD5;
# Manual add item hack here (auction payments)
# Format price hack here
# Add item name to "thank you your selection added" message
# hack here - sub add_to_the_cart
# Quantity break discount hack entry here and subroutine
# in commerce_order_lib.pl
# added switch for ordered message for trollbeads wishlist # trollbeads list
#set the default first choice for options that we will disallow
$default_first_choice = "Please Choose...";
## This script is FREE but if you'd like to help us develop
## more free stuff, your always welcome to send a donation!
##
## Carey Internet Services
## 28 Route 6A
## Sandwich, MA 02563
##
## Commerce.cgi 2.0 Beta 2
##
## Version history is available at...
## http://www.careyinternet.com/main/commerce/version.html
##
## Commerce.cgi is based on Selena Sol's freeware 'Web Store'
## available at http://www.extropia.com. Modifications made
## independently by Carey Internet Services. The entire package as
## distributed here is Copyright 1999-2000 by Carey Internet Services
## and is distributed free of charge consistent with the GNU General
## Public License Version 2 dated June 1991.
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## Version 2 as published by the Free Software Foundation.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
## Set this to "yes" for card validation, or "no" for none:
$validate_card_cc="no";
$| = 1;
## Hack for external cgi scripts
# This is a list of the scripts that you want to be able to call from commerce.cgi
# If they are in the same folder as commerce.cgi then you can use ./ otherwise you
# should just use the full Unix path to the file.
$ENV{"PATH"} = "";
@execute_cgi = ("./page.pl?page=classes");
## end external cgi
$time = time;
## Stop and record hackers
if ($ENV{'REQUEST_URI'} =~ /\.\./i)
{
$ipnum = $ENV{'REMOTE_ADDR'};
@digits = split (/\./, $ipnum);
$address = pack ("C4", @digits);
$host = gethostbyaddr ($address, 2);
$date = &get_date;
open (HACK_LOG, "+>>./log_files/hack.log");
print HACK_LOG "$ENV{'REMOTE_ADDR'}\|$ENV{'REMOTE_PORT'}\|$host\|$date\|$ENV{'REQUEST_URI'}\n";
close HACK_LOG;
print "Content-type: text/html\n\n";
print qq~
Hack Attempt
Hack attempt logged and will be reported to your ISP!
~;
exit;
}
## End hack stop
&require_supporting_libraries (__FILE__, __LINE__,
"./admin_files/commerce_user_lib.pl");
&require_supporting_libraries (__FILE__, __LINE__,
"./admin_files/$sc_gateway_name-user_lib.pl");
&require_supporting_libraries (__FILE__, __LINE__,
"./library/commerce.setup.db");
&require_supporting_libraries (__FILE__, __LINE__,
"./library/commerce_order_lib.pl");
&require_supporting_libraries (__FILE__, __LINE__,
"$sc_cgi_lib_path",
"$sc_html_setup_file_path",
"$sc_mail_lib_path",
"$sc_cookie_lib",
"$sc_commerce_subs_path",
"$sc_process_order_lib_path");
# to disallow categories
require "./disallow-lib.pl";
&read_and_parse_form_data;
&require_supporting_libraries (__FILE__, __LINE__,
"./library/se_advanced.pl");
&get_cookie;
&require_supporting_libraries (__FILE__, __LINE__,
"./library/special_library.pl");
$page = $form_data{'page'};
$page =~ /([\w\-\=\+\/]+)\.(\w+)/;
$page = "$1.$2";
$page = "" if ($page eq ".");
$page =~ s/^\/+//; # Get rid of any residual / prefix
$search_request = $form_data{'search_request_button'};
$cart_id = $form_data{'cart_id'};
&error_check_form_data;
if ($cookie{'cart_id'} eq "" && $form_data{'cart_id'} eq "")
{
&delete_old_carts;
&assign_a_unique_shopping_cart_id;
}
if ($form_data{'cart_id'} eq "")
{
$cart_id = $cookie{'cart_id'};
$sc_cart_path = "$sc_user_carts_directory_path/${cart_id}.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
}
else
{
$cart_id = $form_data{'cart_id'};
$sc_cart_path = "$sc_user_carts_directory_path/${cart_id}.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
}
# new 07-10-10 Chris Costa
if ($cookie{'cart_id'} eq "" && ($form_data{'cart_id'} || $cart_id))
{
&SetCookies;
}
#Chris Costa 03-2012 to allow mobile site template use
# if ($form_data{'mobile'} eq "yes"){
# &delete_cookie("ismobile");
# &set_custom_cookie("ismobile","yes");
# $sc_store_template_file = $sc_mobile_template_file;
# }elsif ($form_data{'mobile'} eq "no"){
# &delete_cookie("ismobile");
# &set_custom_cookie("ismobile","no");
# $sc_store_template_file = $sc_store_template_file;
# }else{ # no override on mobile, run the subroutine
&checkmobilebrowser;
# }
sub checkmobilebrowser{
if ($cookie{'ismobile'} eq "yes"){
$sc_store_template_file = $sc_mobile_template_file;
}elsif ($cookie{'ismobile'} eq "no"){
$sc_store_template_file = $sc_store_template_file;# do nothing here
}else{ # no mobile cookie set yet
# check if on a mobile device - subroutine is found in commerce html lib.pl
my $checkmobile = &isMobile; # 1 is yes, 0 is no
if ($checkmobile eq "1") {
$sc_store_template_file = $sc_mobile_template_file;
# &set_custom_cookie("ismobile","yes");
}else{
# &set_custom_cookie("ismobile","no");
}
} # end mobile cookie code
} # end sub checkmobilebrowser
print "Content-type: text/html\n\n";
# Make sure that the cart_id starts with a digit.
if (substr($cart_id, 0, 1) =~ /\D/)
{
print "Invalid Cart ID!\n";
exit;
}
$are_any_query_fields_filled_in = "no";
foreach $query_field (@sc_db_query_criteria)
{
@criteria = split(/\|/, $query_field);
if ($form_data{$criteria[0]} ne "")
{
$are_any_query_fields_filled_in = "yes";
}
}
if ($form_data{'add_to_cart_button.x'} ne "")
{
# fix for new_arrivals
if (($form_data{product} eq "") && ($sc_show_new_arrivals eq "yes") && (!$form_data{pid}) && (!$form_data{keywords})){
$form_data{product} = "New_Arrivals";
}
&add_to_the_cart;
exit;
}
elsif ($form_data{'modify_cart_button.x'} ne "")
{
&display_cart_contents;
exit;
}
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;
}
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");
&display_order_form;
exit;
}
elsif ($form_data{'submit_order_form_button'} ne "")
{
&require_supporting_libraries (__FILE__, __LINE__, "$sc_order_lib_path");
&process_order_form;
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'} eq ""))
{
&display_products_for_sale;
exit;
}
# Authorize.net
elsif ($form_data{'x_response_code'})
{
# You can uncomment the section below and set the URL if
# you want to validate the Authorize.net referring URL
#
#if ($ENV{'HTTP_REFERER'} ne 'https://secure.authorize.net/gateway/transact.dll')
#{
#print "Refering Site Authentication Failed!";
#exit;
#}
$cart_id = $form_data{'x_cust_id'};
$sc_cart_path = "$sc_user_carts_directory_path/$cart_id.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
&processOrder;
exit;
}
# iTransact
elsif ($form_data{'authcode'})
{
# You can uncomment the section below and set the URL if
# you want to validate the iTransact referring URL
#
#if ($ENV{'HTTP_REFERER'} ne 'https://secure.itransact.com/cgi-bin/mas/split.cgi')
#{
#print "Refering Site Authentication Failed!";
#exit;
#}
$cart_id = $form_data{'p5'};
$sc_cart_path = "$sc_user_carts_directory_path/$cart_id.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
&processOrder;
exit;
}
# Linkpoint
elsif ($form_data{'approval_code'})
{
# You can uncomment the section below and set the URL if
# you want to validate the Linkpoint referring URL
#
#if ($ENV{'HTTP_REFERER'} ne 'https://secure.linkpt.net/cgi-bin/hlppay')
#{
#print "Refering Site Authentication Failed!";
#exit;
#}
$cart_id = $form_data{'custnum'};
$sc_cart_path = "$sc_user_carts_directory_path/$cart_id.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
&processOrder;
exit;
}
# Offline
elsif ($form_data{'process_order'})
{
# You can uncomment the section below and set the URL if
# you want to validate the referring URL
#
#if ($ENV{'HTTP_REFERER'} ne 'https://secure.your_domain.com/cgi-bin/store/commerce.cgi')
#{
#print "Refering Site Authentication Failed!";
#exit;
#}
$cart_id = $form_data{'cart_id'};
$sc_cart_path = "$sc_user_carts_directory_path/$cart_id.cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual / prefix
&processOrder;
exit;
}
## to display html invoice
elsif(($form_data{'show'} eq "html_invoice") && ($create_html_invoice eq "yes")){
#UT invoice
$html_invoice_num = $form_data{'INVOICE'};
$html_invoice_num =~ /^([-\@\w\D]+)$/;
$html_invoice_num = "$1";
$html_invoice_num =~ s/^\/+//; # Get rid of any residual / prefix
&show_invoice;
exit;
}
# To add functionality to Calendar
elsif ($form_data{'action'} eq "showheader"){
&StoreHeader;
exit;
}elsif($form_data{'action'} eq "showfooter"){
&StoreFooter;
exit;
}
elsif ($form_data{'action'} eq "calendar"){
my $caldisp;
# Removed below - next line causing error and resource violation
# use LWP::Simple;
# Convert form data
# my $linkadd = '';
# foreach my $key(keys %form_data){
# $linkadd .= "&$key=$form_data{$key}";
# }
# $linkadd =~ s/^&//;
# $linkadd = "?".$linkadd if($linkadd);
# my $cjls = "http://www.wildaboutbeads.com/cgi-bin/calendar/calendar.cgi$linkadd";
# $cjls =~ s/ //g;
# $caldisp = get("$cjls");
# if ($caldisp eq ''){
$caldisp = " Calendar Currently Unavailable - Please Check Back Soon!";
# $caldisp .= " $! $cjls";
# }
&StoreHeader;
print $caldisp;
&StoreFooter;
exit;
}
else
{
&output_frontpage;
exit;
}
#######################################################################
# 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
# commerce.setup.db 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(/\.[0-9]/,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 commerce.setup.db, we'll delete the file.
foreach $cart (@carts)
{
if (-M "$sc_user_carts_directory_path/$cart" > $sc_number_days_keep_old_carts)
{
$sc_cart_path = "$sc_user_carts_directory_path/$cart";
$sc_cart_path =~ /([\w\-\=\+\/]+)\.(\w+)/;
$sc_cart_path = "$1.$2";
$sc_cart_path = "" if ($sc_cart_path eq ".");
$sc_cart_path =~ s/^\/+//; # Get rid of any residual /prefix
unlink("$sc_cart_path");
print "$sc_cart_path";
}
}# 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.
$remote_addr = $ENV{'REMOTE_ADDR'};
$request_uri = $ENV{'REQUEST_URI'};
$http_user_agent = $ENV{'HTTP_USER_AGENT'};
if ($ENV{'HTTP_REFERER'} ne "")
{
$http_referer = $ENV{'HTTP_REFERER'};
}
else
{
$http_referer = "possible bookmarks";
}
$remote_host = $ENV{'REMOTE_HOST'};
#$shortdate = `date +"%T"`;
$shortdate = date;
chop ($shortdate);
$unixdate = time;
$new_access = "$form_data{'url'}\|$shortdate\|$request_uri\|$cookie{'visit'}\|$remote_addr\|$http_user_agent\|$http_referer\|$unixdate\|";
# 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 .= ".$$";
$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 .= "_$$";
$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.
&SetCookies;
}
#######################################################################
# 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 commerce.setup.db. 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
{
#print " ADDING To CART
";
## Added by Chris Costa,
# if this is a multiple_add
# we need to loop through all the items
# if the checkbox is checked $form_data{check-item-$item} eq "add"
# leave it alone, or else
# we need to undefine the item before going to the add to cart routine
if ($form_data{multiple_add} eq "yes"){
$sc_should_i_display_cart_after_purchase = "yes";
#$sc_item_ordered_message ='';
@check_ordered = keys (%form_data);
# Next it begins going through the list of items ordered
# one by one.
foreach $check_item (@check_ordered)
{
#if it's an item, check for the checkbox or undefine it
if ($check_item =~ /^item-/i){
my $checkboxname = "check-$check_item";
unless($form_data{$checkboxname} eq "add"){
undef ($form_data{$check_item});
} # end unless ($form_data{$checkboxname} eq "add"){
} # end if ($check_item =~ /^item-/i){
} # end foreach $check_item
} # end if multiple add
#&checkReferrer;
# 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.
# init highest item number (start at 100)
$highest_item_number = 100;
# make sure we're positioned at top of file
seek (CART, 0, 0);
# loop on cart contents, if any
while ()
{
# get rid of terminating newline
chomp $_;
# split cart row into fields
my @row = split (/\|/, $_);
# get item number of row (last field)
my $item_number = pop (@row);
$highest_item_number = $item_number if ($item_number > $highest_item_number);
}
# $highest_item_number is now either the highest item number,
# or 0 if the cart was empty. Position the file pointer to the
# end of the cart, in preparation for appending the new items later.
# position to end of file
seek (CART, 0, 2);
# 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
#
#
#
# for the item with database id number 1234 and
#
#
#
# for item 5678.
#
# If the client orders 2 of 1234 and 9 of 5678, then
# @incoming_data will be a list of 1234 and 5678 such that
# 1234 is associated with 2 in %form_data 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)
{
### Use this to disallow items:
# check for disallowed categories
&check_disallow;
### use this hack to add the items name to the selection added
### message. Also edit the message in commerce.setup.db
if ($item =~ /^item-/i){
###this is a product heading, split it and return the item name
@cjn = split(/\|/ , $item);
$cjprodname = $cjn[3];
#trollbeads list
if ($cjn[1] =~ /^Trollbeads/i){
$sc_item_ordered_message = $sc_item_wishlist_message;
$sc_item_ordered_message =~ s/%%catname%%/Trollbeads/ig;
}
unless($form_data{multiple_add} eq "yes"){
$sc_item_ordered_message =~ s/%%cjprodname%%/$cjprodname/ig;
} else {# end unless multiple items
$sc_item_ordered_message =~ s/\"%%cjprodname%%\"//ig;
}# end unless multiple items
}
# 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.
# MD5 Check
if (($item =~ /^item-/i) && (!$item =~ /^item-79/i)){
print "\n\n\n\n";
$CONTROL = &make_hash($item);
if ($CONTROL ne $form_data{'CONTROL'}){
&bogus;
exit;
}
}
# end MD5
#original below
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){
$form_data{$item} =~ s/\"//ig;
# Manual add item hack here
$cjref = "79"; # the ref num in manager for the auction payments
$cjoptprice = "2"; # the option number of the price in the option file
if ($item eq "option|1|$cjref"){
$form_data{$item} =~ s/\$//ig;
$form_data{$item} = "Item # "."$form_data{$item}";
}
elsif ($item eq "option|$cjoptprice|$cjref"){
$form_data{$item} =~ s/\$//ig;
$form_data{$item} = "Price|"."$form_data{$item}";
}
# End make price hack
#Manual price entry hack by Chris Costa
elsif ($item =~ /^option\|price/i){
$form_data{$item} =~ s/\$//ig;
$form_data{$item} =~ s/[a-zA-Z]//ig;
$form_data{$item} = &format_price("$form_data{$item}");
$optchprice = $form_data{$item};
#$form_data{$item} = "Price|"."$form_data{$item}";
undef $form_data{$item};
}
# end manual price hack
# Manual Option Label Hack by Chris Costa
else {
# Check if [1] spot has words
my (@cwiopt) = split (/\|/, $item);
if ($cwiopt[1] =~ /\D/){
$cwiopt[1] =~ s/_/ /g;
$form_data{$item} = "$cwiopt[1]- "."$form_data{$item}";
}
}
# Added by Chris Costa to prevent user forgetting to choose options
# Variable $default_first_choice = "Please Choose..."; is set at top of this file
if ($form_data{$item} =~ /^$default_first_choice/){
&bad_option_note;
}
# end if user forgot to choose and default first choice was left chosen
push (@options, $item) if ($form_data{$item});
} # end if option
# 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
# commerce_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.
#for adding multiple items, must add this next line undef (@option_array);
undef (@option_array);
$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 commerce.setup.db 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.
#
# /g;
$item_ordered_with_options =~ s/~lt~/\Red
#
# 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});
if($option_name)
{
# added next line to sort options by number
if ($option_number =~ /\D/){
$cwoptnum ++;
$option_array[$cwoptnum] = "$option_name $option_price ";
}else{
$option_array[$option_number] = "$option_name $option_price ";
}
#$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, 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.
# added to sort options
foreach $option (@option_array){
$options .= $option;
}
$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.
if (-e "$sc_cart_path")
{
open (CART, ">>$sc_cart_path") || &file_open_error("$sc_cart_path", "Add to Shopping Cart", __FILE__, __LINE__);
print CART "$cart_row";
close (CART);
}
else
{
open (CART, ">$sc_cart_path") || &file_open_error("$sc_cart_path", "Add to Shopping Cart", __FILE__, __LINE__);
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 commerce.setup.db 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;
# add new subroutine here if you want to do something else after
# adding to the cart
}
# elsif ($are_any_query_fields_filled_in =~ /yes/i)
elsif (($are_any_query_fields_filled_in =~ /yes/i) || ($form_data{'keywords'}))
{
$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 following syntax:
#
# &output_modify_quantity_form;
sub output_modify_quantity_form
{
# The subroutine begins by outputting the HTML header
# using standard_page_header, adds the modify form using
# display_cart_table and finishes off the HTML page with
# modify_form_footer. All of these subrotuines are
# discussed in commerce_html_lib.pl
&standard_page_header("Change Quantity");
&display_cart_table("changequantity");
&modify_form_footer;
}
#######################################################################
# Modify Quantity of Items in the Cart #
#######################################################################
# The modify_quantity_of_items_in_cart subroutine is
# responsible for making quantity modifications in the
# customer's cart. It takes no arguments and as called
# with the following syntax:
#
# &modify_quantity_of_items_in_cart;
sub modify_quantity_of_items_in_cart
{
#&checkReferrer;
# First, the script gathers the keys as it did for the
# add_to_cart routine previously, checking to make
# sure the customer entered a positive integer (not
# fractional and not less than one).
@incoming_data = keys (%form_data);
foreach $key (@incoming_data)
{
if (($key =~ /[\d]/) && ($form_data{$key} =~ /\D/))
{
&update_error_log("BAD QUANTITY CHANGE", __FILE__, __LINE__);
&bad_order_note("change_quantity_button");
}
# Just as the script did in the add to cart routine
# previuosly, it will create an array (@modify_items) of
# valid keys.
unless ($key =~ /[\D]/ && $form_data{$key} =~ /[\D]/)
{
if ($form_data{$key} ne "")
{
push (@modify_items, $key);
}
}
# End of foreach $key (@incoming_data)
}
# Then, the script must open up the client's cart and go
# through it line by line. File open problems are
# handled by file_open_error as usual.
open (CART, "<$sc_cart_path") || &file_open_error("$sc_cart_path", "Modify Quantity of Items in the Cart", __FILE__, __LINE__);
# As the script goes through the cart, it will split each
# row into its database fields placing them as elements in
# @database_row. It will then grab the unique cart row
# number and subsequently replace it in the array.
#
# The script needs this number to check the current line
# against the list of items to be modified. Recall that
# this list will be made up of all the cart items which
# are being modified.
#
# The script also grabs the current quantity of that row.
# Since it is not yet sure if it wants the current
# quantity, it will hold off on adding it back to the
# array. Finally, the script chops the newline character
# off the cart row number.
while ()
{
@database_row = split (/\|/, $_);
$cart_row_number = pop (@database_row);
push (@database_row, $cart_row_number);
$old_quantity = shift (@database_row);
chop $cart_row_number;
# Next, the script checks to see if the item number
# submitted as form data is equal to the number of the
# current database row.
foreach $item (@modify_items)
{
if ($item eq $cart_row_number)
{
if ($form_data{$item} gt 0)
{
# If so, it means that the script must change the quantity
# of this item. It will append this row to the
# $shopper_row variable and begin creating the modified
# row. That is, it will replace the old quantity with the
# quantity submitted by the client ($form_data{$item}).
# Recall that $old_quantity has already been shifted off
# the array.
$shopper_row .= "$form_data{$item}\|";
# Now the script adds the rest of the database row to
# $shopper_row and sets two flag variables.
#
# $quantity_modified lets us know that the current row
# has had a quantity modification for each iteration of
# the while loop.
# Quantity break pricing hack by Chris Costa
if ($sc_use_quantity_break_pricing eq "yes"){
$pri = &format_price($database_row[2]);
$prio = &format_price($database_row[7]);
$item_price_now = &check_quantity_break($pri,$form_data{$item},$database_row[0]);
$item_price_now_formatted = &format_price($item_price_now);
if ($database_row[2] ne $item_price_now){
if ($pri ne $prio){
$database_row[2] = $item_price_now;
$database_row[7] = $database_row[7] - $pri + $item_price_now_formatted;
} else {
$database_row[2] =$item_price_now;
$database_row[7] =$item_price_now_formatted;
}
}
}
# end quantity break hack
foreach $field (@database_row)
{
#quantity break hack was here
$shopper_row .= "$field\|";
}
$quantity_modified = "yes";
chop $shopper_row; # Get rid of last pipe symbol but not the
# newline character
} else {
$quantity_modified = "yes";
}
# End of if ($item eq $cart_row_number)
}
# End of foreach $item (@modify_items)
}
# If the script gets this far and $quantity_modified has
# not been set to "yes", it knows that the above routine
# was skipped because the item number submitted from the
# form was not equal to the curent database id number.
#
# Thus, it knows that the current row is not having its
# quantity changed and can be added to $shopper_row as is.
# Remember, we want to add the old rows as well as the new
# modified ones.
if ($quantity_modified ne "yes")
{
$shopper_row .= $_;
}
# Now the script clears out the quantity_modified variable
# so that next time around it will have a fresh test.
$quantity_modified = "";
# End of while ()
}
close (CART);
# At this point, the script has gone all the way through
# the cart. It has added all of the items without
# quantity modifications as they were, and has added all
# the items with quantity modifications but made the
# modifications.
#
# The entire cart is contained in the $shopper_row
# variable.
#
# The actual cart still has the old values, however. So
# to change the cart completely the script must overwrite
# the old cart with the new information and send the
# client back to the view cart screen with the
# display_cart_contents subroutine which will be discussed
# later. Notice the use of the write operator (>) instead
# of the append operator (>>).
open (CART, ">$sc_cart_path") || &file_open_error("$sc_cart_path", "Modify Quantity of Items in the Cart", __FILE__, __LINE__);
print CART "$shopper_row";
close (CART);
&display_cart_contents;
# End of if ($form_data{'submit_change_quantity'} ne "")
}
#######################################################################
# Output Delete Item Form #
#######################################################################
# The output_delete_item_form subroutine is responsible
# for displaying the HTML form which the customer can use
# to delete items from their cart. It takes no arguments
# and is called with the following syntax:
#
# &output_delete_item_form;
sub output_delete_item_form
{
# As it did when it printed the modification form, the
# script uses several subroutines in commerce_html_lib.pl
# to generate the header, body and footer of the delete
# form.
&standard_page_header("Delete Item");
&display_cart_table("delete");
&delete_form_footer;
# End of if ($form_data{'delete_item'} ne "")
}
#######################################################################
# Delete Item From Cart #
#######################################################################
# The job of delete_from_cart is to take a set of items
# submitted by the user for deletion and actually delete
# them from the customer's cart. The subroutine takes no
# arguments and is called with the following syntax:
#
# &delete_from_cart;
sub delete_from_cart
{
#&checkReferrer;
# As with the modification routines, the script first
# checks for valid entries. This time though it only needs
# to make sure that it filters out the extra form
# keys rather than make sure that it has a positive
# integer value as well because unlike with a text entry,
# clients have less ability to enter bad values with
# checkbox submit fields.
@incoming_data = keys (%form_data);
foreach $key (@incoming_data)
{
# We still want to make sure that the key is a cart row
# number though and that it has a value associated with
# it. If it is actually an item which the user has asked to
# delete, the script will add it to the delete_items
# array.
unless ($key =~ /[\D]/)
{
if ($form_data{$key} ne "")
{
push (@delete_items, $key);
}
# End of unless ($key =~ /[\D]/...
}
# End of foreach $key (@incoming_data)
}
# Once the script has gone through all the incomming form
# data and collected the list of all items to be deleted,
# it opens up the cart and gets the $cart_row_number,
# $db_id_number, and $old_quantity as it did in the
# modification routines previously.
open (CART, "<$sc_cart_path") || &file_open_error("$sc_cart_path", "Delete Item From Cart", __FILE__, __LINE__);
while ()
{
@database_row = split (/\|/, $_);
$cart_row_number = pop (@database_row);
$db_id_number = pop (@database_row);
push (@database_row, $db_id_number);
push (@database_row, $cart_row_number);
chop $cart_row_number;
$old_quantity = shift (@database_row);
# Unlike modification however, for deletion all we need to
# do is check to see if the current database row matches
# any submitted item for deletion. If it does not match
# the script adds it to $shopper_row. If it is equal,
# it does not. Thus, all the rows will be added to
# $shopper_row except for the ones that should be deleted.
$delete_item = "";
foreach $item (@delete_items)
{
if ($item eq $cart_row_number)
{
$delete_item = "yes";
}
# End of foreach $item (@add_items)
}
if ($delete_item ne "yes")
{
$shopper_row .= $_;
}
# End of while ()
}
close (CART);
# Then, as it did for modification, the scipt overwrites
# the old cart with the new information and
# sends the client back to the view cart page with the
# display_cart_contents subroutine which will be discussed
# later.
open (CART, ">$sc_cart_path") || &file_open_error("$sc_cart_path", "Delete Item From Cart", __FILE__, __LINE__);
print CART "$shopper_row";
close (CART);
&display_cart_contents;
# End of if ($form_data{'submit_deletion'} ne "")
}
#######################################################################
# Display Products for Sale #
#######################################################################
# display_products_for_sale is used to generate
# dynamically the "product pages" that the client will
# want to browse through. There are two cases within it
# however.
#
# Firstly, if the store is an HTML-based store, this
# routine will either display the requested page
# or, in the case of a search, perform a search on all the
# pages in the store for the submitted keyowrd.
#
# Secondly, if this is a database-based store, the script
# will use the create_html_page_from_db to output the
# product page requested or to perform the search on the
# database.
#
# The subroutine takes no arguments and is called with the
# following syntax:
#
# &display_products_for_sale;
sub display_products_for_sale
{
## for search logging:
if (($form_data{'keywords'} ne "")&&(!$form_data{'no_log'})){
open(SEARCH,"./data_files/search.log")||die "search log path doesn't look good";
@lines=;
close(SEARCH);
foreach $link(@lines)
{
chomp($link);
($phrase,$hits)=split(/\|/,$link);
$phrase_array{$phrase}=$hits;
}
{$phrase_used=$form_data{'keywords'}}
$phrase_array{$phrase_used}++;
{@keys=sort {$phrase_array{$b} <=> $phrase_array{$a}} keys(%phrase_array)}
open(SEARCH,">./data_files/search.log");
foreach $key(@keys)
{
print SEARCH qq~$key|$phrase_array{$key}\n~;
}
close(SEARCH);
}
#end search logging
# The script first determines which type of store this is.
# If it turns out to be an HTML-based store, the script
# will check to see if the current request is a keyword
# search or simply a request to display a page. If it is
# a keyword search, the script will require the html
# search library and use the html_search subroutine with
# in it to perform the search.
if ($sc_use_html_product_pages eq "yes")
{
if ($form_data{'search_request_button'} ne "")
{
&standard_page_header("Search Results");
require "$sc_html_search_routines_library_path";
&html_search;
&html_search_page_footer;
exit;
}
# If the store is HTML-based and there is no current
# keyword however, the script simply displays the page as
# requested with display_page which will be discussed
# shortly.
&display_page("$sc_html_product_directory_path/$page", "Display Products for Sale", __FILE__, __LINE__);
}
# On the other hand, if $sc_use_html_product_pages was set to
# no, it means that the admin wants the script to generate
# HTML product pages on the fly using the format string
# and the raw database rows. The script will do so
# using the create_html_page_from_db subroutine which will
# be discussed next.
else
{
&create_html_page_from_db;
}
}
#######################################################################
# 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'} eq "" && $form_data{'continue_shopping_button'} eq "")
{
&display_page("$sc_html_product_directory_path/$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.
#
# Next the database is querried for rows containing the
# value of the incoming product variable in the correct
# category as defined in commerce.setup.db The script uses
# the submit_query subroutine in commerce_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);
if (($form_data{'pid'}) || (!$database_rows[1])){
my @cjdispname = split(/\|/,$database_rows[0]);
my $cjdispname = $cjdispname[3];
$display_name_title = $cjdispname;
}
#above section and this switched by Chris Costa
# now 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 area.
#
# The product_page_header subroutine is located in
# commerce_html_lib.pl and $sc_product_display_title is
# defined in the setup file.
&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";
}
# 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 commerce.setup.db
#
# 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.
$nextCount = $form_data{'next'}+$sc_db_max_rows_returned;
$prevCount = $form_data{'next'}-$sc_db_max_rows_returned;
$minCount = $form_data{'next'};
$maxCount = $form_data{'next'}+$sc_db_max_rows_returned;
## could insert code right here to calculate the $warn_message for page index nav
## at top of page.
## this is before any products are printed to the screen, but after
## the header and after the require information of $status and $total_row_count
## are available. Store the page nav in a variable, print it here and then again
## before the footer Use an if statement to determine if it's even needed.
## problem -- uses $rowCount variable, which is incremented below
## Add page navigation to top of page by Chris Costa
if ($status =~ /max.*row.*exceed.*/i){
$prevHits = $sc_db_max_rows_returned;
$nextHits = $sc_db_max_rows_returned;
$just_get_nav = "yes";
$rowCount = $rowCount + $#database_rows + 1;
my ($page_index_nav) = &product_page_footer($status,$total_row_count);
$rowCount = $rowCount - $#database_rows - 1;
$just_get_nav = "no";
print qq~
$page_index_nav
~;
}
## end page index nav to top hack
# insert code to start table for new tile
# do not shrink tile if there is only one returned item
#commented below line to allow more than one result for pid search
# if ((!$database_rows[1]) && (!$form_data{'pid'})){
if (!$database_rows[1]){
$sc_shrink_tile = "no";
}
#commented below line to allow more than one result for pid search
# if (($sc_shrink_tile eq "yes") && (!$form_data{'pid'})){
if ($sc_shrink_tile eq "yes"){
print "";
print "
";
$tile_keep_count = "1";
}
# end new tile code
foreach $row (@database_rows)
{
# insert code to start table for new tile
# if (($sc_shrink_tile eq "yes") && (!$form_data{'pid'})){
if ($sc_shrink_tile eq "yes"){
if ($rowCount > $minCount && $rowCount <= $maxCount){
if ($tile_keep_count == $tile_display_rows){
print "<\/td><\/tr>
";
$tile_keep_count = "1";
} else {
print "<\/td>
";
$tile_keep_count++;
}
}
}
# end new tile code here
$rowCount++;
$prevHits = $sc_db_max_rows_returned;
$nextHits = $sc_db_max_rows_returned;
if ($rowCount > $minCount && $rowCount <= $maxCount)
{
@database_fields = split (/\|/, $row);
foreach $field (@database_fields)
{
# 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 ()
{
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;
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.
#
# /~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.
#
$itemID = join("\|",@item_ids);
# #Chris Costa
# #This snippet adds the top categories to a listing where only the pid is supplied
# #allowing the customer to identify the category and check other items in the same category
# if ((!$form_data{'product'}) && ($form_data{'pid'})){
# $form_data{'product'} = $item_ids[1];
# my ($topcat_html) = &topcats;
# print qq~
# $topcat_html
# ~;
# } # end top categories for pid only
$sc_product_display_row = &displayProductPage;
# End of foreach $row (@database_rows)
}
}
# code to close new tile
#commented below line to allow more than one result for pid search
# if (($sc_shrink_tile eq "yes") && (!$form_data{'pid'})){
if ($sc_shrink_tile eq "yes"){
print "<\/td><\/tr>";
}
# end new tile code
##################################
if ($form_data{'productbefore'}){
$form_data{'product'} = $form_data{'productbefore'};
} # fix for removal of new_arrivals category name to allow bottom page nav to work in that category
##################################
&product_page_footer($status,$total_row_count);
print <
ENDOFTEXT
exit;
}
#######################################################################
# display_cart_contents Subroutine #
#######################################################################
# display_cart_contents is used to display the current
# contents of the customer's cart. It takes no arguments
# and is called with the following syntax:
#
# &display_cart_contents;
sub display_cart_contents
{
# The subroutine begins by defining some working variables
# as local to the subroutine.
local (@cart_fields);
local ($field, $cart_id_number, $quantity, $display_number,
$unformatted_subtotal, $subtotal, $unformatted_grand_total,
$grand_total);
# Next, as when we created the modification and deletion
# forms for cart manipulation, we will use the routines in
# commerce_html_lib.pl to generate the header, body and
# footer of the cart page. However, unlike with the
# modification and deletion forms, we will not need an
# extra table cell for the checkbox or text field. Thus,
# we will not pass anything to display_cart_table. We
# will simply get a table representing the current
# contents of the customer's cart.
&standard_page_header("View/Modify");
&display_cart_table("");
&cart_footer;
exit;
# End of sub display_cart_contents
}
#######################################################################
# file_open_error Subroutine #
#######################################################################
# If there is a problem opening a file or a directory, it
# is useful for the script to output some information
# pertaining to what problem has occurred. This
# subroutine is used to generate those error messages.
#
# file_open_error takes four arguments: the file or
# directory which failed, the section in the code in which
# the call was made, the current file name and
# line number, and is called with the following syntax:
#
# &file_open_error("file.name", "ROUTINE", __FILE__,
# __LINE__);
sub file_open_error
{
# The subroutine simply uses the update_error_log
# subroutine discussed later to modify the error log and
# then uses CgiDie in cgi-lib.pl to gracefully exit the
# application with a useful debugging error message sent
# to the browser window.
local ($bad_file, $script_section, $this_file, $line_number) = @_;
&update_error_log("FILE OPEN ERROR-$bad_file", $this_file, $line_number);
open(ERROR, $error_page);
while ()
{
print $_;
}
close (ERROR);
}
#######################################################################
# display_page Subroutine #
#######################################################################
# display_page is used to filter HTML pages through the
# script and display them to the browser window.
#
# display_page takes four arguments: the file or
# directory which failed, the section in the code in which
# the erroneous call was made, the current file name and
# line number, and is called with the following syntax:
#
# &file_open_error("file.name", "ROUTINE", __FILE__,
# __LINE__);
#
# (notice the two special Perl variables __FILE__, which
# equals the current filename, and __LINE__ which equals
# the current line number).
sub display_page
{
#####showcase grabber
# &grab_showcase;
####end showcase grabber (subs at end of script)
local ($page, $routine, $file, $line) = @_;
# the subroutine begins by opening the requested file for
# reading, exiting with file_open_error if there is a
# problem as usual.
my $newbies = &newbies;
## add random text & pics
my $rotatead = &rotatead;
if ($sc_header_for_pages eq "yes"){
&StoreHeader;
}
print "$clickthroughheader" if ($clickthroughheader);
open (PAGE, "<$page") || &file_open_error("$page", "$routine", $file, $line);
# It then reads in the file one line at a time. However,
# on every line it looks for special tag sequences which
# it knows it must modify in order to maintain the state
# information necessary for the workings of this script.
# Specifically, every form must include a page and a
# cart_id value and every url hyperlink must have a
# cart_id value added to it.
#
# Raw administratively pre-designed HTML pages must
# include the follwoing tag lines if they are to filter
# properly and pass along this necesary state information.
#
# All forms must include two hidden field lines with the
# "tags" tobe substituted for imbedded as follows:
#
#
#
#
# When the script reads in these lines, it will see the
# tags "%%cart_id%%" and"%%page%%" and substitute them for
# the actual page and cart_id values which came in as form
# data.
#
# Similarly it might see the following URL reference:
#
#
#
# In this case, it will see the cartid= tag and
# substitute in the correct and complete
# "cartid=some_number".
while ()
{
# Check if we are pretending to display static pages:
$_ = &checkstatic("$_");
s/%%showcase%%/$showcase/g;
s/%%showcase2%%/$showcase2/g;
s/%%showcase3%%/$showcase3/g;
s/%%mainnotice%%/$mainnotice/g;
s/%%cart_id%%/$cart_id/g;
s/%%page%%/$form_data{'page'}/g;
s/%%date%%/$date/g;
s/%%URLofImages%%/$URL_of_images_directory/g;
# display table of new products - sub newbie in html_lib.pl
s/%%newbies%%/$newbies/g;
# display rotating ad for items - sub rotatead in html_lib.pl
s/%%rotatead%%/$rotatead/g;
# Next, it checks to see if the add_to_cart_button button
# has been clicked. if so, it means that we have just
# added an item and are returning to the display of the
# product page. In this case, we will sneak in an addition
# confirmation message right after the