在线商店脚本的数据库集成与功能实现
在构建在线商店时,使用关系型数据库可以更高效地管理商品信息、购物车数据和订单信息。本文将详细介绍如何对在线商店的脚本进行修改,以使其与关系型数据库协同工作,包括商品目录展示、购物车管理和结账流程。
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 参数
:
- 打印页面开头
- 连接数据库
- 获取商品信息
- 展示商品目录
- 清理数据库连接
- 打印页面结尾
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 参数
:
- 打印页面开头
- 连接数据库
- 获取购物车内容
- 根据购物车是否有商品,打印购物车或提示无商品
- 打印页面结尾
- 清理数据库连接
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 主要流程
- 检查会话 ID,如果没有则提示错误并退出。
- 连接数据库
- 获取购物车内容
-
根据购物车是否有商品和用户是否提交信用卡信息,执行不同操作:
-
有商品且提交信用卡信息:
- 设置变量
- 验证表单
- 若表单有效,插入订单,清空购物车,打印成功信息
- 若表单无效,打印错误信息和表单
- 有商品但未提交信用卡信息:打印结账表单
- 无商品:提示购物车为空
-
有商品且提交信用卡信息:
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 缓存商品信息 |
通过以上对在线商店脚本的详细分析和优化建议,可以构建一个更稳定、安全和高效的在线商店系统。这些脚本和优化措施为开发人员提供了一个良好的基础,可以根据实际需求进行扩展和定制。
超级会员免费看

被折叠的 条评论
为什么被折叠?



