#!/usr/bin/perl -wT
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use DBI;
use strict;

my $item = $ENV{QUERY_STRING};

# connect to the database
my $dbh = DBI->connect( "dbi:mysql:products", "webserver", "", { RaiseError => 1, AutoCommit => 1 }) or &dienice("Can't connect to database: $DBI::errstr");

# 1. First be sure the item they're ordering is actually valid. No 
#    point in setting cookies for bogus items.

if ($item =~ /\D/) {  # make sure the item number is alphanumeric.
   &dienice("Item `$item' is not a valid item number.");

my $sth = $dbh->prepare("select * from items where stocknum=?") or &dbdie;
$sth->execute($item) or &dbdie;
if (my $rec = $sth->fetchrow_hashref) {
   if ($rec->{status} eq "OUT") { # out of stock. They can't order it.
      &dienice("We're sorry, but $rec->{name} (item #$item) is out of stock.");
} else {
   &dienice("There is no item numbered `$item' in the database.");

# 2. See if a cookie has already been set (and is valid). 

my $cookie_id;
if (cookie('cart')) { # found a cookie! see if it's valid...
   $sth = $dbh->prepare("select * from cart_cookies where cookie_id=?") or &dbdie;
   $sth->execute(cookie('cart')) or &dbdie;
   if ($sth->fetchrow_hashref) {
      $cookie_id = cookie('cart');

# 2a. If no cookie was found, set one.

if ($cookie_id) {       # A valid cookie was found. Print a regular header. 
   print header();
} else {                # no valid cookie found, so set one.
   $cookie_id = &random_id();
   my $cookie = cookie(-name=>'cart', -value=>$cookie_id, 
   $sth = $dbh->prepare("insert into cart_cookies values(?,current_timestamp())") or &dbdie;
   $sth->execute($cookie_id) or &dbdie;
   print header(-cookie=>$cookie);

# 3. Add the ordered item to the shopping cart table.
#    If they already ordered one of these items, increment the QTY
#    Otherwise, insert a new record with QTY=1.

$sth = $dbh->prepare("select * from shopcart where cookie=? and item_number=?") or &dbdie;
$sth->execute($cookie_id, $item) or &dbdie;
if ($sth->fetchrow_hashref) {
   $sth = $dbh->prepare("update shopcart set qty=qty+1 where cookie=? and item_number=?") or &dbdie;
   $sth->execute($cookie_id, $item) or &dbdie;
} else {
   $sth = $dbh->prepare("insert into shopcart values(?,?,?)") or &dbdie;
   $sth->execute($cookie_id, $item, 1) or &dbdie;

# 4. Display the shopping cart

print start_html("Add Item");


print end_html;

sub random_id {
    # This routine generates a 32-character random string
    # out of letters and numbers.
    my $rid = "";
    my $alphas = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    my @alphary = split(//, $alphas);
    foreach my $i (1..32) {
       my $letter = $alphary[int(rand(@alphary))];
       $rid .= $letter;
    return $rid;

sub dienice {
    my($msg) = @_;
    print header;
    print start_html("Error");
    print "<h2>Error</h2>\n";
    print $msg;

sub display_shopcart {
    my($cookie_id) = @_;
    my $sth = $dbh->prepare("select * from shopcart, items where shopcart.cookie=? and items.stocknum=shopcart.item_number") or &dbdie;
    $sth->execute($cookie_id) or &dbdie;
    my $subtotal = 0;
    print qq(
<h3>Your Shopping Cart</h3>
<form action="edcart.cgi" method="POST">
<table border=0 width=70%>
    <th bgcolor="#cccccc">Item Number</th>
    <th bgcolor="#cccccc">Name</th>
    <th bgcolor="#cccccc">Price</th>
    <th bgcolor="#cccccc">Qty.</th>
    while (my $rec = $sth->fetchrow_hashref) {
       $subtotal = $subtotal + ($rec->{price} * $rec->{qty});
       print qq(
    <td align="CENTER">$rec->{item_number}</td>
    <td align="CENTER">$rec->{name}</td>
    <td align="CENTER">\$$rec->{price}</td>
    <td align="CENTER"><input type="text" name="item_$rec->{item_number}" size=3 value="$rec->{qty}"></td>
    $subtotal = sprintf("%4.2f", $subtotal);
    print qq(
    <td><b>Subtotal:</b> \$$subtotal</td>
<input name="cartact" type="submit" value="Update Qty">
<input name="cartact" type="submit" value="Check Out">

sub dbdie {
    my($package, $filename, $line) = caller;
    my($errmsg) = "Database error: $DBI::errstr<br>
                called from $package $filename line $line";