33、在线商店脚本的数据库集成与功能实现

在线商店脚本的数据库集成与功能实现

在构建在线商店时,使用关系型数据库可以更高效地管理商品信息、购物车数据和订单信息。本文将详细介绍如何对在线商店的脚本进行修改,以使其与关系型数据库协同工作,包括商品目录展示、购物车管理和结账流程。

1. 数据库表结构相关

以下是部分数据库表结构定义,涉及用户地址、信用卡等信息:

20: addr varchar(60) not null,
21: city varchar(60) not null,
22: state char(2) not null,
23: zip char(5) not null,
24: cc_number varchar(20) not null,
25: cc_type varchar(4) not null,
26: cc_exp_month char(2) not null,
27: cc_exp_year char(4) not null); 
2. 商品目录脚本(catalog.pl)

这个脚本主要用于向用户展示商品目录,并处理将商品添加到购物车的请求。与旧版本不同,它通过打开数据库连接来处理 SQL 查询结果,而不是解析文件。

2.1 代码结构与变量设置
#!/usr/local/bin/perl
use strict;
use CGI;
use CGI::Carp qw( fatalsToBrowser );
use DBI;

my $query = new CGI;
my $database = “store”;
my $db_server = “db.example.com”;
my $user = “dbiuser”;
my $password = “dbipass”;
my ($session_id, $dbh, $sth, $action, $product_id, $quantity);
2.2 主要流程

根据是否接收到商品 ID 参数,脚本会执行不同的流程:
- 有商品 ID 参数
1. 获取或生成会话 ID
2. 设置变量
3. 连接数据库
4. 打印页面开头
5. 将商品添加到购物车
6. 获取商品信息
7. 展示商品目录
8. 清理数据库连接
9. 打印页面结尾

if ($query->param(‘product_id’)) {
    if ($query->cookie(‘session_id’)) {
        $session_id = ($query->cookie(‘session_id’));
    }
    else { $session_id = time . $$; }
    &set_variables;
    &db_connect;
    &print_page_start;
    &add_to_cart;
    &get_products;
    &display_catalog;
    &db_cleanup;
    &print_page_end;
}
  • 无商品 ID 参数
    1. 打印页面开头
    2. 连接数据库
    3. 获取商品信息
    4. 展示商品目录
    5. 清理数据库连接
    6. 打印页面结尾
else {
    &print_page_start;
    &db_connect;
    &get_products;
    &display_catalog;
    &db_cleanup;
    &print_page_end;
}
2.3 主要子函数
  • add_to_cart :决定是插入新记录还是更新现有记录到购物车。
sub add_to_cart {
    my $rec_quantity;
    if ($query->cookie(‘session_id’)) {
        my $statement = qq[select quantity from cart 
            where session_id = ‘$session_id’ 
            and product_id = $product_id];
        $sth = $dbh->prepare($statement)
            or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
        my $rv = $sth->execute
            or die “Couldn’t execute select statement: “, 
                $sth->errstr, “\n”;
        if (($rec_quantity) = $sth->fetchrow_array) {
            $action = “update”;
        }
        else {
            $action = “insert”;
        }
    }
    else {
        $action = “insert”;
    }
    if ($action eq “insert”) {
        my $statement = qq[insert into cart 
            values ($session_id, $product_id, $quantity)];
        $sth = $dbh->prepare($statement)
            or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
        my $rv = $sth->execute
            or die “Couldn’t execute insert statement: “, 
                $sth->errstr, “\n”;
    }
    else {
        my $new_quantity = $quantity + $rec_quantity;
        my $statement = qq[update cart 
            set quantity = $new_quantity 
            where session_id = $session_id and product_id = $product_id];
        $sth = $dbh->prepare($statement)
            or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
        my $rv = $sth->execute
            or die “Couldn’t execute update statement: “,   
                $sth->errstr, “\n”;
        my $rc = $sth->finish;
    }
}
  • get_products :从 products 表中获取商品信息。
sub get_products {
    my $statement = qq[select product_id, product_name, product_desc,
        product_price from products];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute select statement: “, $sth->errstr, “\n”;
}
  • display_catalog :展示商品目录。
sub display_catalog {
    print “<div align=\”center\”>\n”;
    print “<table border=\”1\” cellpadding=\”4\”>\n”;
    print “<tr>\n<th>Description</th>\n<th>Price</th>\n</tr>\n”;
    while (my @row = $sth->fetchrow_array) {
        my ($product_id, $product_name, $product_desc, 
            $product_price) = @row;
        print “<tr>\n”;
        print “<form>\n”;
        print “<input type=\”hidden\” name=\”product_id\” “;
        print “value=\”$product_id\” />\n”;
        print “<td>$product_desc</td>\n<td>$product_price</td>\n”;
        print “<td><input type=\”text\” name=\”quantity\” “;
        print “value=\”1\” size=\”2\” /></td>\n”;
        print “<td><input type=\”submit\” value=\”add\” /></td>\n”;
        print “</form>\n”;
        print “</tr>\n”;
    }
    print “</table>\n</div>\n”;
}
3. 购物车脚本(cart.pl)

这个脚本有两个主要功能:列出用户购物车的内容和从购物车中移除商品。

3.1 代码结构与变量设置
#!/usr/local/bin/perl
use strict;
use CGI;
use CGI::Carp qw( fatalsToBrowser );
use DBI;

my $query = new CGI;
my $database = “rafeco_rc3”;
my $db_server = “db4.pair.com”;
my $user = “rafeco_w”;
my $password = “vmppa55r”;
my ($session_id, $page_title, $dbh, $sth);
3.2 主要流程

根据是否接收到 action 参数,脚本会执行不同的流程:
- 有 action 参数且为 remove
1. 连接数据库
2. 移除商品
3. 打印页面开头
4. 获取购物车内容
5. 根据购物车是否有商品,打印购物车或提示无商品
6. 打印页面结尾
7. 清理数据库连接

if ($query->param(‘action’)) {
    if ($query->param(‘action’) eq ‘remove’) {
        $page_title = “Shopping Cart”;
        &db_connect;
        &remove_item;
        &print_page_start;
        &get_cart_contents;
        if ($sth->rows) {
            &print_cart;
        }
        else {
            &print_no_cart;
        }
        &print_page_end;
        &db_cleanup;
    }
}
  • 无 action 参数
    1. 打印页面开头
    2. 连接数据库
    3. 获取购物车内容
    4. 根据购物车是否有商品,打印购物车或提示无商品
    5. 打印页面结尾
    6. 清理数据库连接
else {
    $page_title = “Shopping Cart”;
    &print_page_start;
    &db_connect;
    &get_cart_contents;
    if ($sth->rows) {
        &print_cart;
    }
    else {
        &print_no_cart;
    }
    &print_page_end;
    &db_cleanup;
}
3.3 主要子函数
  • remove_item :从购物车中移除指定商品。
sub remove_item {
    my $product_id = $query->param(‘product_id’);
    my $statement = qq[
        delete from cart
        where session_id = ‘$session_id’
        and product_id = $product_id
    ];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute select statement: “, $sth->errstr, “\n”;
}
  • get_cart_contents :从数据库中获取购物车内容。
sub get_cart_contents {
    my $statement = qq[select cart.product_id as product_id, 
        quantity, product_name, product_price
        from cart, products
        where session_id = ‘$session_id’
        and cart.product_id = products.product_id];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute select statement: “, $sth->errstr, “\n”;
}
  • print_cart :打印购物车内容。
sub print_cart {
    print “<div align=\”center\”>\n<table>\n<tr>\n”;
    print “<th>Product ID</th>\n<th>Product Name</th>\n”;
    print “<th>Price</th>\n<th>Quantity</th>\n</tr>\n”;
    while (my @row = $sth->fetchrow_array) {
        my ($rec_product_id, $rec_quantity, $rec_product_name,
            $rec_price) = @row;
        print “<td>$rec_product_id</td>\n”;
        print “<td>$rec_product_name</td>\n”;
        print “<td>$rec_price</td>\n”;
        print “<td>$rec_quantity</td>\n”;
        print “<td>\n<form>\n”;
        print “<input type=\”hidden\” name=\”action\” “;
        print “value=\”remove\” />\n”;
        print “<input type=\”hidden\” name=\”product_id\” “;
        print “value=\”$rec_product_id\” />\n”;
        print “<input type=\”submit\” value=\”remove\” />\n”;
        print “</td>\n”;
        print “</tr>\n”;
    }
    print “</table>\n”;
}
4. 结账脚本(checkout.pl)

这个脚本用于处理用户结账流程,并将订单信息插入数据库。

4.1 代码结构与变量设置
#!/usr/local/bin/perl
use strict;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use DBI;

my $query = new CGI;
my $database = “rafeco_rc3”;
my $db_server = “db4.pair.com”;
my $user = “rafeco_w”;
my $password = “vmppa55r”;
my ($session_id, $page_title, $cart_query, $dbh, $sth, $name, $address,
    $city, $state, $zip, $cc_type, $cc_number, $exp_month, $exp_year);
my %cc_types = (‘AMEX’ => ‘American Express’,
                ‘VISA’ => ‘Visa’,
                ‘MC’ => ‘Mastercard’,
                ‘DISC’ => ‘Discover’);
4.2 主要流程
  1. 检查会话 ID,如果没有则提示错误并退出。
  2. 连接数据库
  3. 获取购物车内容
  4. 根据购物车是否有商品和用户是否提交信用卡信息,执行不同操作:
    • 有商品且提交信用卡信息:
      • 设置变量
      • 验证表单
      • 若表单有效,插入订单,清空购物车,打印成功信息
      • 若表单无效,打印错误信息和表单
    • 有商品但未提交信用卡信息:打印结账表单
    • 无商品:提示购物车为空
if ($query->cookie(‘session_id’)) {
    $session_id = $query->cookie(‘session_id’);
}
else {
    $page_title = “Checkout: Error”;
    &print_page_start;
    &print_no_cart;
    &print_page_end;
    exit;
}
&db_connect;
&get_cart_contents;
if ($cart_query->rows) {
    if ($query->param(‘cc_type’)) {
        &set_variables;
        my $error_message = &valid_form;
        if (! $error_message) {
            $page_title = “Checkout Complete”;
            &print_page_start;
            &insert_order;
            &empty_cart;
            &print_success;
            &print_page_end; 
        }
        else {
            $page_title = “Checkout: Please correct errors”;
            &print_page_start;
            &print_error($error_message);
            &print_form;
            &print_page_end;
        }
    }
    else {
        $page_title = “Checkout”;
        &print_page_start;
        &print_form;
        &print_page_end;
    }
}
else {
    $page_title = “Error: Your cart is empty”;
    &print_page_start;
    &print_no_cart;
    &print_page_end;
}
&db_cleanup;
4.3 主要子函数
  • insert_order :插入订单信息到数据库。
sub insert_order {
    my $order_id = time . $$;
    while (my @row = $cart_query->fetchrow_array) {
        my ($product_id, $quantity) = @row;
        my $statement = qq[
            insert into order_products
            values (‘$order_id’, $product_id, $quantity) ];
        $sth = $dbh->prepare($statement)
            or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
        my $rv = $sth->execute
            or die “Couldn’t execute insert statement: “, 
                $sth->errstr, “\n”;
    }
    my $statement = qq[
        insert into orders
        values (‘$order_id’, ‘$name’, ‘$address’,
                ‘$city’, ‘$state’, ‘$zip’, 
                ‘$cc_number’, ‘$cc_type’, 
                ‘$exp_month’, ‘$exp_year’) ];
    my $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Order insert failed: “, 
            $sth->errstr, “\n”;
}
  • empty_cart :清空购物车。
sub empty_cart {
    my $statement = qq[
        delete from cart 
        where session_id = $session_id ];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute delete statement: “, $sth->errstr, “\n”;
}
  • valid_form :验证表单信息。
sub valid_form {
    my $error_message = ‘’;
    $error_message .= “<li>You must enter your name</li>\n” 
        if ($name =~ /^\s*$/);
    $error_message .= “<li>You must enter your address</li>\n”
        if ($address =~ /^\s*$/);
    $error_message .= “<li>You must enter your city</li>\n”
        if ($city =~ /^\s*$/);
    $error_message .= “<li>You must enter a valid zip code</li>\n”
        if ($zip !~ /^\d+$/);
    if ($exp_month > 12 || $exp_month < 1) {
        $error_message .= “<li>You must enter a valid “;
        $error_message .= “expiration month.</li>\n”
    if ($exp_year < 2000 || $exp_year > 2010) {
        $error_message .= “<li>You must enter a valid expiration “;
        $error_message .= “year</li>\n”
    }
    if ($cc_number !~ /^\d+$/) {
        $error_message .= “<li>You must enter a valid credit card “;
        $error_message .= “number</li>\n”
    }
    return $error_message;
}
5. 总结

通过以上三个脚本,我们实现了一个基本的在线商店系统,包括商品展示、购物车管理和结账功能。这些脚本通过与关系型数据库的交互,提高了数据管理的效率和可靠性。

流程图

graph TD;
    A[开始] --> B{有商品 ID 参数?};
    B -- 是 --> C[获取或生成会话 ID];
    C --> D[设置变量];
    D --> E[连接数据库];
    E --> F[打印页面开头];
    F --> G[添加商品到购物车];
    G --> H[获取商品信息];
    H --> I[展示商品目录];
    I --> J[清理数据库连接];
    J --> K[打印页面结尾];
    B -- 否 --> L[打印页面开头];
    L --> E;

表格

脚本名称 主要功能 涉及数据库操作
catalog.pl 展示商品目录,处理商品添加到购物车请求 查询商品信息,插入或更新购物车记录
cart.pl 列出购物车内容,移除商品 查询购物车内容,删除购物车记录
checkout.pl 处理结账流程,插入订单信息 查询购物车内容,插入订单记录,清空购物车
6. 数据库操作详细解析
6.1 数据库连接

在各个脚本中,都使用了 db_connect 子函数来建立与数据库的连接。以 catalog.pl 脚本为例:

sub db_connect {
    $dbh = DBI->connect(“DBI:mysql:$database:$db_server”, $user, 
        $password);
}

这里使用了 DBI 模块的 connect 方法,传入数据库连接字符串、用户名和密码。连接字符串指定了数据库驱动( DBI:mysql )、数据库名称和服务器地址。

6.2 数据库清理

为了释放数据库连接资源,使用 db_cleanup 子函数。以 cart.pl 脚本为例:

sub db_cleanup {
    my $rc = $sth->finish;
    $rc = $dbh->disconnect;
}

$sth->finish 用于结束当前的查询操作, $dbh->disconnect 用于断开与数据库的连接。

6.3 SQL 查询操作

在不同的脚本中,使用了多种 SQL 查询来完成各种功能。
- 查询商品信息 :在 catalog.pl get_products 子函数中,使用 SELECT 语句从 products 表中获取商品信息。

sub get_products {
    my $statement = qq[select product_id, product_name, product_desc,
        product_price from products];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute select statement: “, $sth->errstr, “\n”;
}

首先使用 prepare 方法准备 SQL 语句,然后使用 execute 方法执行该语句。
- 插入购物车记录 :在 catalog.pl add_to_cart 子函数中,根据情况使用 INSERT UPDATE 语句来更新购物车记录。

if ($action eq “insert”) {
    my $statement = qq[insert into cart 
        values ($session_id, $product_id, $quantity)];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute insert statement: “, 
            $sth->errstr, “\n”;
}
else {
    my $new_quantity = $quantity + $rec_quantity;
    my $statement = qq[update cart 
        set quantity = $new_quantity 
        where session_id = $session_id and product_id = $product_id];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute update statement: “,   
            $sth->errstr, “\n”;
    my $rc = $sth->finish;
}
  • 查询购物车内容 :在 cart.pl get_cart_contents 子函数中,使用连接查询从 cart products 表中获取购物车内容。
sub get_cart_contents {
    my $statement = qq[select cart.product_id as product_id, 
        quantity, product_name, product_price
        from cart, products
        where session_id = ‘$session_id’
        and cart.product_id = products.product_id];
    $sth = $dbh->prepare($statement)
        or die “Couldn’t prepare the query:”, $sth->errstr, “\n”;
    my $rv = $sth->execute
        or die “Couldn’t execute select statement: “, $sth->errstr, “\n”;
}

这里使用了表连接,通过 product_id 关联 cart products 表。

7. 表单验证与处理
7.1 表单验证

checkout.pl 脚本中,使用 valid_form 子函数对用户输入的表单信息进行验证。

sub valid_form {
    my $error_message = ‘’;
    $error_message .= “<li>You must enter your name</li>\n” 
        if ($name =~ /^\s*$/);
    $error_message .= “<li>You must enter your address</li>\n”
        if ($address =~ /^\s*$/);
    $error_message .= “<li>You must enter your city</li>\n”
        if ($city =~ /^\s*$/);
    $error_message .= “<li>You must enter a valid zip code</li>\n”
        if ($zip !~ /^\d+$/);
    if ($exp_month > 12 || $exp_month < 1) {
        $error_message .= “<li>You must enter a valid “;
        $error_message .= “expiration month.</li>\n”
    if ($exp_year < 2000 || $exp_year > 2010) {
        $error_message .= “<li>You must enter a valid expiration “;
        $error_message .= “year</li>\n”
    }
    if ($cc_number !~ /^\d+$/) {
        $error_message .= “<li>You must enter a valid credit card “;
        $error_message .= “number</li>\n”
    }
    return $error_message;
}

该函数检查用户输入的姓名、地址、城市、邮编、信用卡有效期和卡号等信息是否符合要求,如果不符合则添加相应的错误信息到 $error_message 中。

7.2 表单处理

根据表单验证的结果,执行不同的操作。如果表单有效,则插入订单信息并清空购物车;如果表单无效,则打印错误信息和表单。

if ($query->param(‘cc_type’)) {
    &set_variables;
    my $error_message = &valid_form;
    if (! $error_message) {
        $page_title = “Checkout Complete”;
        &print_page_start;
        &insert_order;
        &empty_cart;
        &print_success;
        &print_page_end; 
    }
    else {
        $page_title = “Checkout: Please correct errors”;
        &print_page_start;
        &print_error($error_message);
        &print_form;
        &print_page_end;
    }
}
8. 优化建议
8.1 错误处理优化

当前脚本中使用 or die 来处理数据库操作的错误,在实际应用中,可以使用更友好的错误处理方式,例如记录错误日志并向用户显示友好的错误信息。

8.2 安全性优化

在 SQL 语句中直接使用变量可能会导致 SQL 注入攻击。可以使用 DBI 模块的绑定参数功能来防止此类攻击。例如,在 add_to_cart 子函数中:

my $statement = qq[insert into cart 
    values (?, ?, ?)];
$sth = $dbh->prepare($statement);
$sth->execute($session_id, $product_id, $quantity)
    or die “Couldn’t execute insert statement: “, 
        $sth->errstr, “\n”;
8.3 性能优化

对于频繁执行的查询,可以考虑使用缓存机制,减少数据库的访问次数。例如,将商品信息缓存到内存中,避免每次都从数据库中查询。

流程图

graph TD;
    A[开始结账] --> B{有会话 ID?};
    B -- 是 --> C[连接数据库];
    C --> D[获取购物车内容];
    D --> E{购物车有商品?};
    E -- 是 --> F{提交信用卡信息?};
    F -- 是 --> G[设置变量];
    G --> H[验证表单];
    H -- 有效 --> I[插入订单信息];
    I --> J[清空购物车];
    J --> K[打印成功信息];
    H -- 无效 --> L[打印错误信息];
    L --> M[打印表单];
    F -- 否 --> N[打印结账表单];
    E -- 否 --> O[提示购物车为空];
    B -- 否 --> P[提示错误并退出];

表格

优化点 优化方式 示例代码
错误处理 记录错误日志,显示友好错误信息 使用日志模块记录错误,向用户显示自定义错误信息
安全性 使用绑定参数防止 SQL 注入 $sth->execute($param1, $param2)
性能 使用缓存机制 使用 Memcached 或 Redis 缓存商品信息

通过以上对在线商店脚本的详细分析和优化建议,可以构建一个更稳定、安全和高效的在线商店系统。这些脚本和优化措施为开发人员提供了一个良好的基础,可以根据实际需求进行扩展和定制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值