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

# if the pressed the "Check Out" button, redirect to the checkout
# script instead
if (param('cartact') eq "Check Out") {
   print redirect("http://www.cgi101.com/book/ch17/order.cgi");

print header;
print start_html("Update Cart");

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

# Put the cookie-detection stuff in a separate subroutine. 
# Since the validate_cookie routine must query the db,
# be sure to open the database connection BEFORE this.
my $cookie_id = &validate_cookie;

# prepare three statement handles - one to select data from the cart,
# a second to update a record in the cart with quantity changes,
# and a third to delete a record from the cart (if qty==0).

my $sth = $dbh->prepare("select * from shopcart where cookie=? and item_number=?") or &dbdie;
my $sth2 = $dbh->prepare("update shopcart set qty=? where cookie=? and item_number=?") or &dbdie;
my $sth3 = $dbh->prepare("delete from shopcart where cookie=? and item_number=?") or &dbdie;

foreach my $p (param()) {
   # first, be sure it's a NUMBER. if not, skip it.
   if ($p =~ /^item_.*/ and param($p) =~ /\D/) {
      print "error, `",param($p),"' isn't a number.<br>\n";
   my $item = $p;
   $item =~ s/item_//;
   $sth->execute($cookie_id, $item) or &dbdie;
   if ($sth->fetchrow_hashref) {
      if (param($p) > 0) {
         $sth2->execute(param($p), $cookie_id, $item) or &dbdie;
      } else {
         $sth3->execute($cookie_id, $item) or &dbdie;

# Display the shopping cart

print end_html;

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 validate_cookie {
# Look for cookies. If they have a valid cookie, return it; if not,
# print an error message and abort.
    my $cookie_id = "";
    if (cookie('cart')) {
       $cookie_id = cookie('cart');
    } else {
       &dienice("You don't have a cart. (Perhaps your cart expired?)");
    my $sth = $dbh->prepare("select * from cart_cookies where cookie_id=?")  or &dbdie;
    $sth->execute(cookie('cart')) or &dbdie;
    unless ($sth->fetchrow_hashref) {
       &dienice("You don't have a cart. (Perhaps your cart expired?)");
    return $cookie_id;

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