Linux教程Linux
首页
基础知识
Linux业界
Linux系统
Linux人物
Linux文化
Linux资讯
Linux综合
当前位置:
Linux教程
-
Linux
- 网络数据库5日教程(5)
网络数据库5日教程(5)
原作者:<a href=mailto:
[email protected]
>Richard Dice</a>
--------------------------------------------------------------------------------
网络数据库教程-[第5天]
一 必不可少的CGI.pm
二 数据库转义序列
三 在Here-Document字符串内嵌入引用表达式
四 嵌入子程序
五 用SQL设置表单- selection.iphtml
六 用CGI.pm - receive.iphtml处理表单结果
--------------------------------------------------------------------------------
一、 必不可少的CGI.pm
在过去的几天里我们已经谈了许多重要的事项。当然谈得都不是太深入。今天我将用一个实例比较细致地阐述一下过去几天所学的概念。而且几天还会涉及一些新的问题。
在各种有关Perl CGI编程的讨论中常常会提到Lincoln Stein的CGI.pm 。总体来说,CGI.pm 所用的编程理念和我在本教程中所倡导的完全相反。
从一开始,我就在试图帮助你们建立互动、动态生成的网页。这也是嵌入式HTML编程的初衷,而且它也能使网站的编码和组织更简便快捷。
而CGI.pm的观点是将网络编程分离出来,它给你一种感觉仿佛你是在用CGI.pm搭建一个网页,例:
#!/usr/bin/perl
use CGI;
$query = new CGI;
print $query->header(),
$query->start_html(-title=>\"Made with CGI.pm\"),
\"This is what I mean by \",
$query->b(\"abstracted\"),
\".\",
$query->end_html();
exit 0;
该程序的执行结果是一个简单的HTTP头,一个起始HTML块(包括一个<TITLE>),几行文字,以及标准的HTML结束块。注意所有这些都是用CGI的$query 对象以及与其相关的方法编制的:
Content-type: text/html <!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\"> <HTML><HEAD><TITLE>Made with CGI.pm</TITLE> </HEAD><BODY>This is what I mean by <B>abstracted</B>.</BODY></HTML>
我总是尽量避免使用这种编程方法,但是我也不得不承认这种方法有时候
用起来很顺手。
CGI.pm的优点不在于它的抽象性,而在于它所提供的工具。CGI.pm有一个非常强大的cookie处理器以及表单参数解码方法。
我们都了解表单,它是HTML,而且它具有很多用途。
View the page source to see how I put this one together.
作为一个网络程序员,表单是从用户处收集的只要方法。当一个用户点击递交(Submit)按钮时,浏览器将用户输入的信息打包编码然后发送给你的CGI程序进行处理。而CGI程序的职责就是要解包,解码和使用表单中的内容。
这个过程很烦琐,为什么不让CGI.pm帮你处理这些事情呢?表单参数可以用param方法提取:
#!/usr/bin/perl
#
# BAR.cgi is a simple Perl CGI program using CGI.pm.
#
# A Web page with a form containing the FOO textarea
# is meant to submit to BAR.cgi (pay attention to
# the \"param\" method).
#
use CGI;
$query = new CGI;
print $query->header(),
$query->start_html(-title=>\"Test of the param method\"),
\"The value of the FOO parameter is: \",
$query->param(\"FOO\"),
$query->end_html();
exit 0;
这就是用CGI.pm解决这个问题的方法。在以后的某些ePerl代码中我还将用到CGI.pm,但只是为了利用其param方法的优势。
二、 数据库转义序列
在第3天的教程中我用做了一个唱片数据库,其中有一张唱片叫做\"We Can\"t Dance\",这一项不能作为字符串利用mysql程序插入到数据库中-因为MySQL将符号\"作为字符串的限位符。
变通方法是通过加入反斜杠将该限位符“转义”:
mysql> insert into albums(title,artist,released)
-> values(\"We Can\\\"t Dance\",\"Genesis\",\"1991-01-01\");
当然在为了数据库上下文中处理这些细节比较令人头疼。
当你想在数据库中插入项目时,通常会直接使用表单参数。你的ePerl代码可能如下:
$foo = $query->param(\"foo\");
$foo =~ s/\"/\\\\\"/g; # this Perl command will substitute \" with \\\"
$SQL = <<\"EOT\";
insert into my_table(my_column)
values (\"$foo\")
EOT
这种设置方法不好,因为:
MySQL用反斜杠\"转义\"字符,但其他的某些数据库程序则可能使用不同的转义序列,所以用反斜杠硬性“转义”会影响程序的可移植性另外,该转义符在此处只转义了单引号 \" -还有其他的字符也需要转义。
需要转义的其他字符在不同的数据库中会有所区别。
你不需要记忆文献中所述的细节。用$dbh->quote记忆可以帮你实现上述目的。
$foo = $dbh->quote($query->param(\"foo\"));
$query->param(\"foo\")将返回表单文字区输入的foo的值,并且$dbh->quote将根据和你的数据库相应的DBD转义必要的字符。
$dbh->quote还在这个字符串外添加引号,这样就省得你在键盘输入引号了。
三、 在Here-Document字符串内嵌入引用表达式
here-document字符串的语法如下:
$string = <<\"HERE_DOCUMENT\";
You can type all sorts of stuff in here....
You can also $interpolate variables right into your h-d string.
The here-document string will quit when it runs into the label
given at its outset.
HERE_DOCUMENT
here_document非常方便,特别是在编制传递给$dbh以生成客户端$cursor光标查询的 $SQL字符串时。
看一下我们如何在上面的$dbh->quote例子生成$SQL。 我必须生成一个中介变量$foo插入实际生成$SQL的here-document字符串。但这样也不是很理想。我们可以做得更好。
问题是,当$dbh->quote返回一个字符串标量值时,它不是字符串标量值,它是一个函数(实际上是一个方法),这个问题可以在here-documents中变通解决。例如,下面的代码就不能执行:
$SQL = <<\"EOT\";
insert into my_table(my_column)
values ($dbh->quote($query->param(\"foo\")))
EOT
我在here-document做一些变通 (变通方法用加重体字显示)
$SQL = <<\"EOT\";
insert into my_table(my_column)
values (${ \\($dbh->quote($query->param(\"foo\"))) })
EOT
\\ 对$dbh->quote所提供的值作了一个引用。${ ... }取消该引用。语法看起来不好看,但是,据我所知,从来也没有人认为Perl 是一种漂亮的语言。
四、 嵌入子程序
尽管ePerl可以让你在HTML中任意嵌入Perl,但有时候在你的.iphtml文件中
使用子程序能使你的程序显得简洁明了。
例:
<HTML>
<HEAD><TITLE>Embedding a Subroutine</TITLE></HEAD>
<BODY>
<P>
Here\"s an HTML calendar for the current month:
<B><?=${ \\(`cal| head -1`) }!></B>
<P>
<?=${ \\( calendar_table() ) }!>//
</BODY>
</HTML>
<?
sub calendar_table {
#
# I make copious use of the Unix \"cal\" command here.
# This won\"t work on DOS-derivative machines.
#
my @cal = `cal`; # fill the cal array with the
output of a shelled cal command
my $return = \"\";
shift @cal; # junk the first line... it\"s not needed
$return .= \"<TABLE BORDER>\\n\";
$return .= \"<TR>\";
# I dedicate the following line to my fellow Perl junkies
everywhere
$return .= join(\"\", map { s/\\W//g; \"<TH>$_</TH>\" }
unpack(\"A2A3A3A3A3A3A3\", shift @cal));
$return .= \"</TR>\\n\";
foreach ( @cal ) {
$return .= \"<TR>\\n\";
$return .= join(\"\", map { s/\\W//g; \"<TD>$_</TD>\" }
unpack(\"A2A3A3A3A3A3A3\",$_));
$return .= \"</TR>\\n\";
}
$return .= \"</TABLE>\\n\"; # the value of this line is
returned
}
!>//
这里是该程序执行的结果(如下)。 注意如果子程序非常大的话可能会给内存造成麻烦(因为$return的体积会很大),但是当我们遇到这个问题时我们会用相应的办法解决。
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
五、 用SQL设置表单 - selection.iphtml
这里是我所用到的例子,它包括两个程序selection.iphtml和receive.iphtml。
首先调用selection.iphtml - 它将提供一个表单。用户填完表单后,表单将被
递交给receive.iphtml。当它列表显示结果后,你将回到selection中。
但是我不能在这里演示插入、更新或删除SQL语句,因为我不能公开该数据库的
内容。
<?
my $dbh = DBI->connect(\"DBI:mysql:test:localhost\", \"\",\"\",
{ PrintError => 0}) || die $DBI::
errstr;
!>//
<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<HTML>
<HEAD>
<TITLE>An ePerl Database Example: Fiddling with
Albums</TITLE>
</HEAD>
<BODY>
<P>
Use the following form to query the contents of an
(admittedly limited)
database of CD albums of mine.
<TABLE>
<TR>
<TD><?=${ \\( search_by_band ( \\$dbh ) ) }!></TD>
<TD><?=${ \\( search_by_year ( \\$dbh ) ) }!></TD>
</TR>
</TABLE>
<FORM ACTION=receive.iphtml METHOD=POST>
<B>Or, type in a title:</B> <INPUT NAME=title SIZE=20>
(for all titles, just put the cursor in this field
and hit ENTER)
</FORM>
</BODY>
</HTML>
<?
$dbh->disconnect;
!>//
<?
sub search_by_band {
#
# Note that I passed a reference to the database handle dbh.
# This means that, in order to reference it within this
# subroutine, I\"ll have to refer to it as $$dbh.
#
my $dbh = shift;
my $return = \"\";
#
# The \"distinct\" keyword in SQL will only return one row for
a set of
# identical matches. \"Order by\" will sort the
# returned set alphabetically.
#
my $SQL = <<\"EOT\";
select distinct artist
from albums
order by artist
EOT
my $cursor = $$dbh->prepare($SQL);
$cursor->execute;
$return .= \"<FORM ACTION=receive.iphtml METHOD=POST>\\n\";
$return .= \"<B>Pick an artist:</B><BR>\\n\";
$return .= \"<SELECT NAME=artist>\\n\";
my @fields;
while ( @fields = $cursor->fetchrow ) {
$return .= \"<OPTION>$fields[0]\\n\";
}
$return .= \"</SELECT><BR>\\n\";
$return .= \"<INPUT TYPE=SUBMIT NAME=artist_submit
VALUE=\\\"Go Search on This Artist!\\\">\\n\";
$return .= \"</FORM>\\n\";
}
sub search_by_year {
my $dbh = shift;
my $return = \"\";
#
# If COLUMN is defined as a date datum, then year(COLUMN)
will return only
# the year portion of the data in the column. \"Order by
COLUMN desc\"
# will reverse the usual sort order.
#
my $SQL = <<\"EOT\";
select distinct year(released)
from albums
order by released desc
EOT
my $cursor = $$dbh->prepare($SQL);
$cursor->execute;
$return .= \"<FORM ACTION=receive.iphtml METHOD=POST>\\n\";
$return .= \"<B>Or, pick a year:</B><BR>\\n\";
$return .= \"<SELECT NAME=year>\\n\";
my @fields;
while ( @fields = $cursor->fetchrow ) {
$return .= \"<OPTION>$fields[0]\\n\";
}
$cursor->finish;
$return .= \"</SELECT><BR>\\n\";
$return .= \"<INPUT TYPE=SUBMIT NAME=year_submit
VALUE=\\\"Go Search on This Year!\\\">\\n\";
$return .= \"</FORM>\\n\";
}
!>//
六、 用CGI.pm - receive.iphtml处理表单结果
<?
my $cgi = new CGI; # 利用 \"param\" 解码方法的优势
my $dbh = DBI->connect(\"DBI:mysql:test:localhost\", \"\",\"\",
{ PrintError => 0}) || die $DBI::errstr;
!>//
<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<HTML>
<HEAD>
<TITLE>Results from the Database Search</TITLE>
</HEAD>
<BODY>
<P>
<?=${\\( display_query_results(\\$dbh, \\$cgi) )}!>//
<P>
<A HREF=selection.iphtml>Return to the query page</A>
</BODY>
</HTML>
<?
$dbh->disconnect;
!>//
<?
sub display_query_results {
#
# 注意我将引用传递给数据库处理器dbh和
# cgi对象 - 这意味着要想在子程序中引用他们
# 我必须使用$$dbh和$$cgi.
#
my $dbh = shift;
my $cgi = shift;
my $return = \"\";
my $SQL;
if ( defined($$cgi->param(\"title\")) ) {
my $SQL = <<\"EOT\";
select title, artist, year(released)
from albums
where ucase(title) like ${ \\($$dbh->quote(uc($$cgi->
param(\"title\")) . \"%\") ) }
order by title, artist
EOT
#
# 在上述语句中我使用了更复杂的SQL。SQL不会
# 自动将返回的结果排序,但是利用
# \"order by\" 语句可以很容易地实现排序 - 只需设定你希望显示的列数
# 以及它们,的顺序优先级,\"Like\"可以匹配子程序 -
# 如果你提供了标题 \"abc,\" 则所有标题以\"abc\"开头的唱片
# 都会被返回。为了消除这种现象,我
# 在SQL中使用ucase(title),以及uc($$cgi->param(\"title\"),
将两个字符串都大写显示。
# %字符是一个通配符,很象UNIX中的*
# 文件名globbing.
#
my $cursor = $$dbh->prepare($SQL);
$cursor->execute;
$return .= \"<TABLE BORDER>\\n<TR><TH COLSPAN=3>\";
$return .= \"<B>Matches on the title search for:
<TT><I>${ \\($$cgi->param(\"title\") )}</I></TT></B></TH></TR>\";
$return .= \"<TR><TH>Title</TH><TH>Artist</TH><TH>
Year of Release</TH></TR>\\n\";
my @fields;
while ( @fields = $cursor->fetchrow ) {
$return .= \"<TR><TD>$fields[0]</TD><TD>$fields[1]
</TD><TD>$fields[2]</TD></TR>\\n\";
}
$cursor->finish;
$return .= \"</TABLE>\\n\";
} else {
if ( defined($$cgi->param(\"artist_submit\")) ) {
$SQL = <<\"EOT\";
select title, year(released)
from albums
where artist = ${ \\($$dbh->quote($$cgi->param(\"artist\"))) }
order by released desc, title
EOT
} elsif ( defined($$cgi->param(\"year_submit\")) ) {
$SQL = <<\"EOT\";
select artist, title
from albums
where year(released) = ${ \\($$dbh->quote($$cgi->param(\"year\"))) }
order by artist, title
EOT
}
my $cursor = $$dbh->prepare($SQL);
$cursor->execute;
$return .= \"<TABLE BORDER>\\n<TR><TH COLSPAN=2>\";
$return .= (defined($$cgi->param(\"artist_submit\"))?
(\"<B>Artist: <TT><I>\".
\"${ \\($$cgi->param(\"artist\")) }</I>\".
\"</TT></B></TH></TR>\\n<TR>\".
\"<TH>Album Title</TH>\".
\"<TH>Year of Release</TH></TR>\\n\"):
(\"<B>Year of Release: <TT><I>\".
\"${ \\($$cgi->param(\"year\")) }</I>\".
\"</TT></B></TH></TR>\\n<TR>\".
\"<TH>Artist</TH><TH>Album Title</TH>\".
\"</TR>\\n\"));
my @fields;
while ( @fields = $cursor->fetchrow ) {
$return .= \"<TR><TD>$fields[0]</TD>\";
$return .= \"<TD>$fields[1]</TD></TR>\\n\";
}
$cursor->finish;
$return .= \"</TABLE>\\n\";
}
$return;
}
!>//
本教程到此就结束了,但是它只是为了数据库编程的入门,而不是结束。我希望该教程能对你有所帮助。
发布人:netbull 来自:Linux数据库应用指南
在Linux可加载内核模块中探秘(7)
JSP学习笔记之一,与数据库联接
oftpd:安全的FTP守护程序
详述局域网中IP地址的设置
IPv6技术素描
请大家注意:2.4.x内核vfat中文文件名的支持有问题,内详。
如何在WINDOWS下运行UNIX程序和GNU程序
inux优势初探
Linux日志管理详解(下)
unix下c开发技巧点滴
Linux的基本概念
Linux和Windows 9X的资源共享
Sybase 11.0.3.3落户FreeBSD [二] 安装Linux仿真环境
对Linux的认识还存在哪些认识上的误区
修改默认输入法
站点导航
Linux教程
Php
Linux
非技术类
指令大全
Shell
安装启动
Xwindow
Kde
Gnome
输入法类
美化汉化
网络配置
存储备份
杂项工具
编程技术
网络安全
内核技术
速度优化
Apache
Email
Ftp服务
Cvs服务
代理服务
Samba
域名服务
网络过滤
其他服务
Nfs
Oracle
Dhcp
Mysql
Ldap
RedHat
赞助商链接