CGI编程:订单处理、内容类型与应用实践
1. 订单信息存储流程
在处理用户的订单时,需要将用户在结账表单中输入的信息存储到数据库中。具体步骤如下:
1. 生成订单ID :订单ID的生成方式与目录程序中会话ID的创建方式相同,用于唯一标识订单。
2. 存储购物车商品信息 :使用 while 循环遍历从用户购物车中检索所有商品的查询结果,将当前商品插入 order_products 表的新行。
insert into order_products values (‘$order_id’, $product_id, $quantity)
- 存储订单信息 :将用户输入的订单信息插入
orders表。
insert into orders values (‘$order_id’, ‘$name’, ‘$address’, ‘$city’,
‘$state’, ‘$zip’, ‘$cc_number’,’$cc_type’, ‘$exp_month’, ‘$exp_year’)
- 清空购物车 :使用单个
delete语句删除与用户会话ID关联的购物车表中的所有行。
1.1 订单处理流程图
graph TD;
A[生成订单ID] --> B[存储购物车商品信息];
B --> C[存储订单信息];
C --> D[清空购物车];
2. 数据库使用常见问题解答
2.1 能否混合使用关系数据库表和平面文件存储应用数据?
可以,但如果使用关系数据库存储应用的任何数据,建议将所有数据存储在其中,因为关系数据库在数据存储方面比平面文件有很多优势。
2.2 从CGI脚本访问关系数据库是否存在性能问题?
存在。每次请求CGI程序时,都会启动一个新进程来执行该程序,这意味着每次调用脚本时都要打开一个新的数据库连接,并在脚本退出时关闭连接,这可能会导致性能问题,特别是对于某些数据库。
2.3 测试示例程序需要什么?
除了Web服务器软件和Perl解释器外,还需要一个关系数据库。可以从 http://www.mysql.com 下载免费的MySQL(适用于Windows和UNIX)。
3. 处理其他内容类型
3.1 设置内容类型
Web服务器依赖CGI程序生成 Content-type 头,因为它无法知道CGI程序将生成何种内容。发送不同的内容类型很简单,例如发送纯文本:
print “Content-type: text/plain\n\n”;
使用 CGI.pm 打印HTTP头:
print $query->header(-type=>’text/plain’);
3.2 处理二进制内容
3.2.1 发送文本文件
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header(-type=>’text/plain’);
open (FILE, “< some_file.txt”)
or die “Can’t open some_file.txt”;
while (<FILE>) {
print;
}
3.2.2 发送二进制文件
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header(-type=>’image/gif’);
open (FILE, “< some_image.gif”)
or die “Can’t open some_image.gif”;
binmode FILE;
while (read(FILE, my $buf, 512)) {
print $buf;
}
3.3 处理二进制内容步骤
- 设置适当的内容类型。
- 将二进制内容作为请求的主体发送给用户。
3.4 二进制内容处理流程图
graph TD;
A[设置内容类型] --> B[发送二进制内容];
4. 认证下载应用
4.1 需求背景
许多网站允许用户下载软件或其他文件,但有时需要控制谁可以下载这些文件。使用CGI程序可以创建更灵活的认证方案。
4.2 脚本实现
脚本需要两个参数: auth_code (通过查询字符串中的传统名/值对传递)和用户要下载的文件名(通过额外的路径信息传递)。
#!/usr/local/bin/perl
use CGI;
use strict;
use vars qw($query $auth_code $file $error_message);
$query = new CGI;
$auth_code = $query->param(‘auth_code’);
$file = $query->path_info();
$file =~ s/^\/(.*)$/$1/;
$error_message = ‘’;
if (!&valid_auth_code && !&valid_file) {
&send_file;
}
else {
&print_error;
}
sub valid_auth_code {
if ($auth_code ne ‘1’) {
$error_message = ‘<li>Invalid authentication code.</li>’;
}
return $error_message;
}
sub valid_file {
if (!$file) {
$error_message = “<li>No filename specified.</li>”;
}
if ($file =~ /^([-\@\w.]+)$/) {
$file = $1;
if (!(-e $file) || !(-r $file)) {
$error_message = ‘<li>File not available.</li>’;
}
} else {
$error_message = “<li>Tainted data in $file.</li>”;
}
return $error_message;
}
sub send_file {
print $query->header(-type=>’application/octet-stream’,
-attachment=>$file);
open (FILE, “< $file”)
or die “Can’t open $file”;
while (read FILE, my $buf, 512) {
print $buf;
}
}
sub print_error {
print $query->header;
print $query->start_html(‘An error occurred.’);
print “<h1>Error</h1>\n”;
print “<ul>$error_message</ul>\n”;
print $query->end_html;
}
4.3 认证下载流程
- 提取参数 :从请求中提取
auth_code和文件名。 - 验证参数 :调用
valid_auth_code和valid_file子例程验证参数。 - 发送文件或显示错误 :如果验证通过,调用
send_file子例程发送文件;否则,调用print_error子例程显示错误信息。
4.4 认证下载流程图
graph TD;
A[提取参数] --> B[验证参数];
B -->|验证通过| C[发送文件];
B -->|验证失败| D[显示错误];
5. 创建自己的广告服务器
5.1 广告服务器原理
广告服务器的基本工作是向每个用户显示广告,并确保所有可用广告都能按适当次数显示。示例中的广告服务器每次调用脚本时随机显示一个广告。
5.2 脚本实现
#!/usr/local/bin/perl
use strict;
use CGI;
use vars qw($ad_directory $query);
$query = new CGI;
$ad_directory = “ads”;
my $ad = &pick_image;
&print_header;
&log_ad($ad);
&print_image($ad);
sub pick_image {
opendir(FILES, $ad_directory)
or die “Can’t open $ad_directory”;
my @files = readdir FILES;
my @ads;
foreach my $file (@files) {
if (-f “$ad_directory/$file”) {
push @ads, $file;
}
}
return $ads[int(rand(scalar @ads))];
}
sub print_header {
print $query->header(-type=>”image/gif”);
}
sub log_ad {
my $ad = shift(@_);
if (!$ad) {
return;
}
open (LOG, “>> adlog.txt”)
or die “Can’t open log”;
print LOG “$ad\n”;
close LOG;
}
sub print_image {
my $ad = shift(@_);
if (!$ad) {
return;
}
open (FILE, “< $ad_directory/$ad”)
or die “Can’t open $ad”;
while (read FILE, my $buf, 512) {
print $buf;
}
}
5.3 广告服务器工作流程
- 选择广告 :从广告目录中随机选择一个广告。
- 打印头部 :设置响应的内容类型为
image/gif。 - 记录广告 :将选择的广告记录到日志文件中。
- 打印广告 :将广告文件的内容发送给用户。
5.4 广告服务器流程图
graph TD;
A[选择广告] --> B[打印头部];
B --> C[记录广告];
C --> D[打印广告];
6. 总结与对比
6.1 不同功能脚本对比
| 脚本功能 | 主要参数 | 关键操作 | 内容类型 |
|---|---|---|---|
| 订单处理 | 订单ID、商品ID、数量、用户信息 | 插入订单和商品信息到数据库,清空购物车 | 无(主要是数据库操作) |
| 认证下载 | auth_code、文件名 | 验证认证码和文件有效性,发送文件或显示错误 | application/octet-stream(文件下载)、text/html(错误信息) |
| 广告服务器 | 无(从广告目录选择) | 随机选择广告,记录日志,发送广告文件 | image/gif |
6.2 不同内容类型处理对比
| 内容类型 | 设置方式 | 发送方式 | 示例场景 |
|---|---|---|---|
| 文本文件 | print “Content-type: text/plain\n\n”; 或 print $query->header(-type=>’text/plain’); | 逐行读取文件并打印 | 简单文本信息展示 |
| 二进制文件 | print $query->header(-type=>’image/gif’); 等 | 使用read函数分块读取并打印 | 图片、软件等文件下载 |
7. 常见问题解答总结
7.1 数据库使用问题
| 问题 | 解答 |
|---|---|
| 能否混合使用关系数据库表和平面文件存储应用数据? | 可以,但建议将所有数据存储在关系数据库中,因其有更多优势。 |
| 从CGI脚本访问关系数据库是否存在性能问题? | 存在,每次调用脚本需打开和关闭数据库连接,可能导致性能问题。 |
| 测试示例程序需要什么? | 除Web服务器软件和Perl解释器外,还需关系数据库,如可下载MySQL。 |
7.2 脚本使用问题
| 问题 | 解答 |
|---|---|
| 为什么在cart.pl脚本中使用连接查询? | 为了在查询结果中包含购物车表和产品表的信息。 |
| 为什么在checkout.pl脚本中使用两个不同的变量作为语句处理程序? | 为了在处理select语句的结果集时执行insert语句,且不覆盖结果。 |
8. 拓展与实践
8.1 脚本拓展建议
- 订单处理脚本 :可以添加订单状态跟踪功能,如待支付、已支付、已发货等,在数据库中增加相应字段并在脚本中进行更新。
- 认证下载脚本 :可以将认证码存储在数据库中,通过查询数据库验证认证码的有效性,而不是简单的硬编码。
- 广告服务器脚本 :可以根据用户的浏览历史、地理位置等信息进行广告的精准投放,而不是随机选择广告。
8.2 实践任务
- 创建产品目录添加脚本 :创建一个脚本,允许通过Web界面向产品目录中添加新商品。可以参考以下步骤:
- 创建一个HTML表单,包含商品名称、价格、描述等字段。
- 使用CGI程序接收表单数据。
- 将数据插入到产品目录的数据库表中。
以下是一个简单的示例代码:
#!/usr/local/bin/perl
use CGI;
use strict;
use DBI;
my $query = new CGI;
my $dbh = DBI->connect("dbi:mysql:database=your_database;host=localhost", "your_username", "your_password")
or die "Can't connect to database: $DBI::errstr";
if ($query->param()) {
my $name = $query->param('name');
my $price = $query->param('price');
my $description = $query->param('description');
my $stmt = $dbh->prepare("INSERT INTO products (name, price, description) VALUES (?,?,?)");
$stmt->execute($name, $price, $description)
or die "Can't insert data: " . $stmt->errstr;
print $query->header;
print $query->start_html('Success');
print "<h1>Product added successfully!</h1>";
print $query->end_html;
} else {
print $query->header;
print $query->start_html('Add Product');
print '<form method="post">';
print 'Name: <input type="text" name="name"><br>';
print 'Price: <input type="text" name="price"><br>';
print 'Description: <textarea name="description"></textarea><br>';
print '<input type="submit" value="Add Product">';
print '</form>';
print $query->end_html;
}
$dbh->disconnect;
8.3 实践任务流程图
graph TD;
A[显示添加产品表单] --> B[用户提交表单];
B --> C[接收表单数据];
C --> D[插入数据到数据库];
D --> E[显示成功信息];
通过以上的总结和拓展实践,我们可以更深入地理解和应用这些CGI脚本的功能,并且可以根据实际需求进行灵活的拓展和优化。
超级会员免费看
915

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



