Google
搜索WWW 博客内搜索
第一课.在ASP中使用数据库

ASP有一个最重要的功能,就是它可以让你非常轻松地连接数据库。通常都是和一个Access或者一个SQL数据库相连。因为Access是最容易起步的,同时,在你的机器上也许已经都装有Access了,所以,在下面的例子中,我们都将使用Access来做例子。一旦你学习了ASP和Access数据库连接的核心技术方法,当你开始使用SQL server的时候,你就会发现,两者所需要的关键技术是基本相同的。当你要连接数据库的时候,你需要在服务器上将这个数据库打开。你可以通过使用数据源名(DSN)或者通过在你的脚本语言中直接使用一个DSN-less连接的方法来连接和打开数据库。 创建一个数据源名(DSN) 你可以通过在控制面板中给你的数据库建立一个系统DSN来使你的数据库可以在ASP中连接使用。你可以在你的本地计算机上建立若干个DSN,每个DSN对应你使用的不同的数据库。在建立完DSN之后,你就可以在你的本地服务器上测试你的页面了。如果你的网站是由 ISP提供服务的,并且这个ISP支持ASP,那么很有可能它就会提供一个GUI接口,来给你的数据库创建一个DSN。 在Windows 95/98/NT中,打开控制面板(开始菜单->设置->控制面板),双击ODBC进入。 选择系统DSN,点击Add。 选择“Microsoft Access Driver”,点击结束。 填写数据源名。这是你给你的数据库起的名字,所以和一个alias是同样的操作。 在数据库选择中点击选择按钮,浏览系统中你创建的Access数据库所存放的位置。 点击OK 现在,新的DSN现在就会在系统DSN中显示,并且可以在你的本地服务器上使用了。连接数据库 让我们建立一个DSN-less连接,并且看看是如何连接数据库的。当你创建一个DSN的时候,你就已经存储了关于这个数据库的一些信息,所以你不需要在每次需要使用一些信息的时候重复它们,这些信息如:数据库类型、名称、存放地点和可选性、用户和密码。 要创建一个DSN-less连接,你就需要提供同样的信息。下面这个例子就显示了如何给一个叫products的数据库建立一个DSN-less连接: 第二行定义了数据库的驱动和物理路径。为了要使用一个DSN-less连接,你就需要知道实际的文件存放地点(绝对路径)。Server.MapPath给任何一个使用主机服务的人提供了一个简单的工作环境来查找出那些难于查到的实际访问路径。 如果我们已经建立了一个系统DSN,并命名为products,则连接码应该为: 现在,数据库就已经打开了,那么你可以做些什么呢?第一件事情当然就是阅读数据库中的一系列记录,并将它们放到你的页面中去。但是,在这之前,你需要一个recordset。 Recordset 一个recordset是存储在特殊数据库表上的所有信息。所以,当你打开这个recordset的时候,表中所有的行和列的内容都是可访问的。你需要打开这个recordeset,正如你需要打开数据库连接一样。它们的命令是相似的: Set objRec = Server.CreateObject ("ADODB.Recordset") objRec.Open "downloadable", strConnect, 0,1,2 这个语句就创建了一个名为downloadable表的recordset(objRec),这个表在products数据库的strConnect中定义。使用Recordset open, 我们就可以循环浏览这个表,并且可以将它的所有内容都显示到屏幕上。或者,我们可以测试特定字段的内容,也可以只将我们关注的内容写到屏幕上去。 每一列代表一个字段。所以,如果数据库表如下所示: Product ID SKU Name File 1 PR12345 Product A install_a.exe 2 PR12346 Product B Install_b.exe 那么,我们就有如下字段的内容:ProductID, SKU, Name, 和File。你的表很可能会有许多额外的字段内容,可能包含很多东西,如价格或者是产品(商品)描述。但是这个示意图可以给你提供最基本的数据库表的概念。填写recordset内容 使用recordset是非常容易的一件事情。如果你想要循环浏览数据库,并将所有的信息都打印到屏幕上显示,你可以按照下面来操作: While NOT objRec.EOF \\\\\\\' says to do this as long as we haven\\\\\\\'t reached the end of the file Response.WriteobjRec("ProductID") & ", " Response.WriteobjRec("SKU") & ", " Response.WriteobjRec("Name") & ", " Response.WriteobjRec("File") & " " objRec.MoveNext Wend ; 即使你没有如此使用过loop,你仍然可以通过阅读这个代码来将信息写到comma-delimited字符串里,并且当数据库表中创建了一个新行的时候,就重新创建一个新的行,来记录表中的那一行。你可以使用同样的方法将数据写到HTML表格中去。通过使用Response.Write添加你的TABLE标签,需要记住以下几点: 你的HTML 标签和引号中的内容。 如果你的标签或者内容使用了引号,注意使用双引号: . 使用&来连接变量和HTML/内容信息 选择recordset中的字段假设我们的products数据库同样包含一个叫OS的字段,假设这个字段是一个平台分界符。同样,让我们假设存储在这个字段的数据只能是如下的数据:Windows NT, Windows 95, Windows 98, Windows, Mac, Unix, 或者 Linux。 下面,我们就可以确认我们需要将哪个字段打印到屏幕上,而要忽略哪些那些字段。或者,我们可以选择哪些字段用一种格式,而另外的字段用其它的格式,如,使用不同的颜色。 使用一个简单的If...,循环就可以给我们提供更多的数据库控制权利。首先让我们来打印有关Windows NT产品的记录: Windows NT Products If objRec("OS") = "Windows NT" THEN \\\\\\\' specifies the criteria Response.Write "" & objRec("ProductID") & "" Response.Write "" & objRec("SKU") & "" Response.Write "" & objRec("Name") & "" Response.Write "" & objRec("File") & "" end if objRec.MoveNext Wend %> 添加一个记录 一旦你开始使用recordset和ASP了,你就会十分希望能够通过网络将数据添加到数据库中去。添加内容是非常重要的,如,当你需要你的网页浏览者留下它们的观点和看法,或者,当你想要进行管理更新的时候。 下面的代码打开了一个recordset,这个recordset是有关一个有着书本和它们作者名字的数据库表格。你可能曾经看到过这个,但是这次,最后三个说明书定义的指针类型是不同的:adOpenStatic, adLockOptimistic, adCmdTable: (如果你没有使用adovbs.inc的复制文件,第三行应该为:objRec.Open "books", bookdb, 3,3,2). recordset现在就准备好接收数据了,你只需要告诉它添加什么。在这个情况下,假设我们从表格中取出变量:strBookTitle和strBookAuthor。我们的table, books有两个字段,称作Title 和 Author,所以我们可以通过使用下面的语句来添加一个新的记录: strBookTitle和strBookAuthor代表值,通常被用户访问。如果你只是想测试add功能,你可以给title和author添加一个变量――只是需要记住使用引号。在你第一次使用它的时候,你可能会立即打开你的数据库,以确保更新的发生。 Recordset类型 在显示的objRec.Open例子中,你会发现在末尾有0,1,2的字样。这些数字代表不同的指针类型。你是用的类型依赖于你将使用它来干什么。例如,如果你不需要修改或增加任何的记录,你可以使用一个Lock类型。而当你计划要修改或者更新数据库的时候,你所选择的类型就会不同。 0,1,2 实际上代表: adOpenForwardOnly, adLockReadOnly, adCmdTable 当然,如果在你的服务器上已经有了adovbs.inc的备份,那么,你也可以不使用数字,直接使用这些单词。adovbs.inc 包括了这三个常量和其它常量的一个列表。


第二课.Oracle大文本在ASP中存取问题的解决

在我开发BS结构程序中,由于经常需要在ORACLE中处理一些容量较大的文本数据,所以经过反复测试终于用ASP成功解决了大文本数据在ORACLE下存取问题。
  
  一、运行环境:
  1、Microsoft Windows 2000 Server + IIS 5.0
2、Oracle8i中文标准版
  
  二、建立数据表:
  CREATE TABLE SYSTEM.TEST(
BLOB LONG,
ID NUMBER)
/
  三、源程序:
1、数据存入程序:test.asp
<%
'表单提交处理部分
'--------------------------------------------------
If request("ok")=1 then
'字符转换函数
function tansstr(sstr)
sstr=replace(sstr," "," ")
sstr=replace(sstr,chr(13) & chr(10),"<br>")
tansstr=sstr
end function
'提交数据赋值
a=lenb(request("text"))
b=len(request("text"))
c=tansstr(request("text"))
'打开数据库,打开test数据表以Rs为记录集
Set OraSession=CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase=OraSession.DbOpenDatabase("autop","system/manager",0)
Set rs=OraDatabase.CreateDynaset("select * from test order by id desc",0)
'求ID值
if rs.eof then
id=1
else
id=rs("id")+1
end if
'因为受SQL语句长度大小限制所以,以非SQL语句存入数据
'--------------------------------------------------------
'新建记录
rs.DbAddNew
'经典就在本句:以RS记录集的Fields对象的DbAppendChunk方法处理大字段存入问题。
rs.Fields("blob").DbAppendChunk(c)
'存入ID值
rs("id")=id
'刷新记录集
rs.DbUpdate
'显示结果部分
'---------------------------------------------------------
Response.write "数据已经存入数据库中。<br>"
Response.write "总计占用字符数: <font color=blue>" & formatnumber(b,2,-2,-2,-1) & "</font> 字<br>"
Response.write "总计占用字节数: <font color=blue>" & formatnumber(a,2,-2,-2,-1) & "</font> Byte<br>"
Response.write "<a href='view.asp'>请调阅……</a>"
'关闭数据连接。
rs.close
set rs=nothing
Set OraSession=nothing
Response.end
End If
%>
<html>
<body>
<form method="POST" action="test.asp">
<p><font color="#FF0000"><b>Oracle大字段在ASP中存取问题的解决:</b></font></p>
<p><textarea rows="13" name="text" cols="104"></textarea></p>
<p><input type="submit" value="存入" name="B1"></p>
<input type="hidden" name="ok" value="1">
</form>
</body>
</html>

  2、数据调出程序:view.asp
<%
'连接数据库,以只读方式打开数据表
Set OraSession=CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase=OraSession.DbOpenDatabase("autop","system/manager",0)
Set Rs=OraDatabase.DbCreateDynaset("select * from test order by id desc",4)
'赋初值:定义每次截取字节大小为1024byte,最大可以设为65280byte (64K)
Size=65280
I=0
Do
'以Rs记录集的Fields对象的DbGetChunk方法在循环中读出数据
Text=Rs.Fields("Blob").DbGetChunk(I*Size,Size)
Response.write Text
'求出每次取出数据的详细字节数
Text_Size=Lenb(Text)
I=I+1
'如果每次取出数据的详细字节数小于欲定义的截取字节大小则说明该条数据已经完毕,退出循环。
Loop until Text_Size<Size
'关闭数据连接
Set OraSession=nothing
%>

第二课.在ASP中使用Oracle数据库

Oracle是世界上用得最多的数据库之一,活动服务器网页(ASP)是一种被广泛用于创建动态网页的功能强大的服务器端脚本语言。许多ASP开发人员一直在考虑,能否在开发互联网应用、电子商务网站、互联网管理系统时结合使用ASP和Oracle数据库?这个问题的答案是肯定的,我们还可以使用VB访问Oracle数据库。在本篇文章中,我们将主要讨论如何使用ASP来处理Oracle数据库中数据的方法。
  在开始讨论这个问题前,我们需要了解几个背景知识,Oracle Objects for OLE就是其中之一。Oracle Objects for OLE是Oracle开发的一个中间件,它允许使用微软的OLE标准的客户端应用程序访问Oracle的数据库。也许会有读者说,我们也可以使用ODBC访问Oracle的数据库。当然,可以使用ODBC访问Oracle数据库,但我认为,Oracle Objects for OLE比ODBC更安全,而且完全支持PL/SQL。PL/SQL是Oracle对SQL命令集的扩展,开发人员能够利用它对非结构化的SQL命令块进行流控制和逻辑设计。如果安装的是Oracle8i数据库,我相信你已经在使用Oracle Objects for OLE。如果还没有使用Oracle Objects for OLE,可以从Oracle的网站上下载它。
  另外,我们还需要了解Oracle针对Visual Basic开发的二个对象和一个接口:OraSession、OraDynaset对象和OraDatabase接口。OraSession对象管理应用程序的OraDatabase、OraConnection和OraDynaset,它是由ASP的CreateObject而不是Oracle Objects for OLE创建的一个对象。OraDatabase接口向Oracle数据库表示表现用户对话,并为SQL、PL/SQL的执行提供方法。它们每个都有一些属性和方法。例如,OraDynaset对象有BOF、EOF、Bookmark、Connection等属性以及AddNew、Update、Delete、Edit、Refresh、Clone等10个方法。
  下面我们就开始切入主题,讨论如何使用ASP处理Oracle数据库中的数据。
   准备工作
  我们需要什么样的环境和工具?
  1)我使用了Oracle8i、IIS5.0、Windows2000专业版作为应用程序的开发和运行环境。
  2)在Oracle数据库中建立一个名字为MYTABLE1或类似的表。
ID (type: number)
User Name(type: varchar2)
Phone(type: varchar2)
Email(type: varchar2)
100
Colin Tong
999-999-8888
colinjava@hotmail.com
111
John White
888-888-8888
johnw@yahoo.com
101
Don Wod
416-333-3344
donwod@test.com
数据的访问和存取
   1) Instantiate OO4O Object, OraSession and interface OraDatabase for connecting to ORACLE.
   1)初始化Oracle Objects for OLE、OraSession对象和OraDatabase接口,为连接ORACLE数据库作准备。
  首先,使用CreateObject创建OraSession对象,然后通过打开一个与Oracle的连接创建OraDatabase对象,如下所示:
<%
Set OraSession = CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase = OraSession.OpenDatabase("", _
"username/password", Cint(0))
%>

   “username”和“password”是你所使用的关系数据库的用户名和口令。
   2)创建OraDynaset对象执行SQL命令。我们可以使用CreateDynaset或DbCreateDynaset创建记录集。
<%
'execute SQL
Set OraDynaset = OraDatabase.DbCreateDynaset( _
"select * from mytable1", cint(0))
%>

  3)存取数据并删除创建的对象。
<%
Do While(OraDynaset.EOF = FALSE)
Response.write(OraDynaset.Fields("ID"))
Response.write(OraDynaset.Fields("UserName"))
... others ...
... ...
OraDynaset.MoveNext
Loop
'remove OraSession
Set OraSession = Nothing
%>

   编辑数据记录
   我们将使用OraDynaset的方法实现对数据记录的编辑。
   1)使用SQL语句创建OraDynaset对象。
<%
'创建ID= fID的记录的OraDynaset对象。
Set OraDynaset = OraDatabase.CreateDynaset(_
"select * from MYTABLE1 where ID= "& fID, cint(0))
%>

  fID是想插入更更新的记录的ID值。
   2)执行OraDynaset更新或添加数据记录。
<%
'使用Edit方法更新ID=fID记录的域。
'或使用AddNew插入一个新记录
OraDynaset.Edit
OraDynaset.Fields("Phone").Value = fPhone
OraDynaset.Update

' 删除创建的对话
Set OraSession = Nothing
%>
删除数据记录
   如果已经真正地理解了我们在上面讨论的一些方法(Edit、Update和AddNew),也许有的读者已经知道该如何在Oracle数据库中删除记录了。
<%
'删除所有符合上面条件的记录
OraDynaset.Delete
%>

  在Oracle8i中搜索和更新数据记录的代码
  1)搜索
<%
'RetriveRecProc.asp -使用ASP的Oracle Objects for OLE更新数据记录%>
<%
'定义作为OLE对象的变量
Dim OraSession
Dim OraDatabase
Dim OraDynaset'创建OraSession对象
Set OraSession = CreateObject("OracleInProcServer.XOraSession")'通过打开Oracle数据库的一个连接创建OraDatabase对象
'一定要使用自己的用户名和口令访问Oracle数据库
Set OraDatabase = OraSession.OpenDatabase("", "user/password", _
Cint(0))
'创建OraDynaset对象执行SQL语句
Set OraDynaset = OraDatabase.DbCreateDynaset(_
"select * from mytable1", cint(0))
%>
<html><body>
<H3>Retrieve All Records in MYTABLE1 Table ( in Oracle)
Using oo4o</H3>
<table border=1 ID="Table1">
<%
Do While(OraDynaset.EOF = FALSE)
Response.Write("<tr><td>")
Response.write(OraDynaset.Fields("ID"))
Response.Write("</td><td>")
Response.write(OraDynaset.Fields("UserName"))
Response.Write("</td><td>")
Response.write(OraDynaset.Fields("Phone"))
Response.Write("</td><td>")
Response.write(OraDynaset.Fields("Email"))
Response.Write("</td></tr>")
OraDynaset.MoveNext
Loop
'删除OraSession
Set OraSession = Nothing
%>
</table>
<a href="javascript:window.history.go(-1)">
Back previous Page</a> |
<a href="index.html"> Back home Page</a>
</body></html>

  2)更新
<%
'UpdateRecProc.asp -使用ASP的Oracle Objects for OLE更新数据记录
%>
<%
'定义作为OLE对象的变量。
Dim OraSession
Dim OraDatabase
Dim OraDynaset
'从提交的表格中获取字段值
fID = request.form("ID")
fUserName = request.form("UserName")
fPhone = request.form("Phone")
fEmail = request.form("Email")
'创建OraSession对象
Set OraSession = CreateObject("OracleInProcServer.XOraSession")
'通过打开Oracle数据库的一个连接创建OraDatabase对象
Set OraDatabase = OraSession.OpenDatabase("", "user/password", _
Cint(0))
'创建ID= fID的记录的OraDynaset对象
Set OraDynaset = OraDatabase.CreateDynaset(_
"select * from MYTABLE1 where ID= "& fID, cint(0))
'使用Edit方法更新ID=fID记录的字段
Do While(OraDynaset.EOF = FALSE)
OraDynaset.Edit
OraDynaset.Fields("UserName").Value = fUserName
OraDynaset.Fields("Phone").Value = fPhone
OraDynaset.Fields("Email").Value = fEmail
OraDynaset.Update
OraDynaset.MoveNext
Loop
%>
<html><body>
<H3>Update A Record in MYTABLE1 Table (Oracle) Using oo4o</H3>
The record (ID=<%=fID%>) has been updated successfully!<br>
You can view the result <a href="RetrieveAllRec.asp"> here</a>
<p>
<a href="javascript:window.history.go(-1)"> Back previous Page</a>
&bnsp;&bnsp;
<a href="javascript:window.history.go(-2)"> Back home Page</a>
<%
'删除OraSession对象
Set OraSession = Nothing
%>
</body荆?html>

  至此,我们已经讨论了如何在ASP代码中使用Oracle Objects for OLE来处理Oracle数据库中的数据。
   使用 存储过程
   我们已经讨论了如何在ASP中访问Oracle数据库,所有的SQL语句都可以嵌入在ASP网页中。如果在ASP中使用存储过程,将更能够更有效地处理数据。我建议读者除在ASP中嵌入SQL语句外,还应当使用PL/SQL存储过程。在Oracle数据库中创建存储过程已经超出了本文章的范围,在这里就不再进行介绍了。
   ASP和Oracle数据库是二种比较流行的技术,都有相当广泛的用户群,如果能够有机地将二者结合起来,将能够给工作带来许多方便,希望这篇文章能够起到抛砖引玉的作用,使读者能够更好地探索将这二种技术结合使用的途径。

 
第五课.随机访问Recordset的一条记录

假设这个数据表有一个唯一的ID字段,并至少有一条记录。随机存取其中一条记录的方法是非常简单的,可以分为四步:
1、取得记录总数n。
2、把所有的ID号存储到一个数组中
3、产生一个不大于n的随机数m
4、从数组中取出第m个ID号,查询数据表,取得记录数据。
  下面是部分代码:
$#@60;%
set conn = Server.CreateObject(‘ADODB.Connection‘)
conn.open ‘$#@60;conn string$#@62;‘
‘ ***** (step 1) *****
set rs = conn.execute(‘Select count(id) from someTable‘)
rCount = rs(0)
‘ ***** (step 2) *****
set rs = conn.execute(“select id from someTable”)
cnt = 1
dim RRs
redim RRs(rCount)
do while not rs.eof
RRs(cnt) = rs(0)
cnt = cnt + 1
rs.movenext
loop
‘ ***** (step 3) *****
randomize
currentRR = cLng(rnd*rCount+0.5)
ID = RRs(currentRR)
‘ ***** (step 4) *****
sql = “select otherfield from someTable where id=” & ID
set rs = conn.execute(sql)
response.write “ID # ” & ID & “ = ” & rs(0)
rs.close: set rs = nothing
conn.close: set conn = nothing
%$#@62;

  对于SQL Server,还有更加有效率的方法。比如设计两个存储过程。我这里只是阐明一些思路,并希望这种思路可以同时用在Access和SQL Server中。

第六课.ADO 存取数据库时如何分页显示

∈裁词?ADO 存取数据库时的分页显示?如果你使用过目前众多网站上的电子公告板程序的话,那你应该会知道电子公告板程序为了提高页面的读取速度,一般不会将所有的帖子全部在一页中罗列出来,而是将其分成多页显示,每页显示一定数目的帖子数,譬如 20 条。想不想了解如何实现分页显示?请看本文!
  《动态网站设计十八般武艺 --ASP 篇》一文从第一期至今已和朋友们一起度过了大半个年头,相信通过在这一段时间中的学习、实践到再学习、再实践,大家已经能够熟练运用 ASP 的内建对象、 ActiveX 组件去编写一些基本的 ASP 应用程序。从我收到的朋友们的来信中可以明显的感觉到,大家的 ASP 功力正不断地提升。最近很多朋友来信希望我写一些 ASP 在现实运用中的实例。因此,从本期开始我决定将《动态网站设计十八般武艺 --ASP 篇》的定位从介绍和学习 ASP 基础知识转向到 ASP 实际运行的探讨和深化。应朋友们的要求,在本期中我将给大家着重谈一谈“ADO 存取数据库时如何分页显示”的问题。
  什么是 ADO 存取数据库时的分页显示?如果你使用过目前众多网站上的电子公告板程序的话,那你应该会知道电子公告板程序为了提高页面的读取速度,一般不会将所有的帖子全部在一页中罗列出来,而是将其分成多页显示,每页显示一定数目的帖子数,譬如 20 条。这就是数据库查询的分页显示,如果你还不明白,去看看 yahoo 等搜索引擎的查询结果就会明白了。
  那么究竟如何才能做到将数据库的查询结果分页显示呢?其实方法有很多,但主要有两种:
  一、将数据库中所有符合查询条件的记录一次性的都读入 recordset 中,存放在内存中,然后通过 ADO Recordset 对象所提供的几个专门支持分页处理的属性: PageSize( 页大小 )、 PageCount( 页数目 ) 以及 AbsolutePage( 绝对页 ) 来管理分页处理。
  二、根据客户的指示,每次分别从符合查询条件的记录中将规定数目的记录数读取出来并显示。
  两者的主要差别在于前者是一次性将所有记录都读入内存然后再根据指示来依次做判断分析从而达到分页显示的效果,而后者是先根据指示做出判断并将规定数目的符合查询条件的记录读入内存,从而直接达到分页显示的功能。
  我们可以很明显的感觉到,当数据库中的记录数达到上万或更多时,第一种方法的执行效率将明显低于第二种方法,因为当每一个客户查询页面时都要将所有符合条件的记 娣旁诜衿髂诖嬷校缓笤诮蟹忠车却恚绻庇谐? 100 个的客户在线查询,那么 ASP 应用程序的执行效率将大受影响。但是,当服务器上数据库的记录数以及同时在线的人数并不是很多时,两者在执行效率上是相差无几的,此时一般就采用第一种方法,因为第一种方法的 ASP 程序编写相对第二种方法要简单明了得多。
  在这里作者就以我们常见的 ASP BBS 程序为例,来给大家分析一下如何在 BBS 程序里实现分页显示功能,由于我们一般使用的 BBS 程序的数据库记录数和同时访问的人数都不会太多,所以以下程序实例是使用的先前所介绍的第一种分页显示方法。
   进行 ADO 存取数据库时的分页显示,其实就是对 Recordset 的记录进行操作。所以我们首先必须了解 Reordset 对象的属性和方法:
   BOF 属性:目前指标指到 RecordSet 的第一笔。
   EOF 属性:目前指标指到 RecordSet 的最后一笔。
   Move 方法:移动指标到 RecordSet 中的某一条记录。
   AbsolutePage 属性:设定当前记录的位置是位于哪一页 AbsolutePosition 属性:目前指标在 RecordSet 中的位置。
   PageCount 属性:显示 Recordset 对象包括多少“页”的数据。
   PageSize 属性:显示 Recordset 对象每一页显示的记录数。
   RecordCount 属性:显示 Recordset 对象记录的总数。
   下面让我们来详细认识一下这些重要的属性和方法
   一、 BOF 与 EOF 属性
   通常我们在 ASP 程序中编写代码来检验 BOF 与 EOF 属性,从而得知目前指标所指向的 RecordSet 的位置,使用 BOF 与 EOF 属性,可以得知一个 Recordset 对象是否包含有记录或者得知移动记录行是否已经超出该 Recordset 对象的范围。
   如:
[url=mailto:$#@60]$#@60[/url]
; % if not rs.eof then ...
[url=mailto:%$#@62]%$#@62[/url]
;
  
[url=mailto:$#@60]$#@60[/url]
; % if not (rs.bof and rs.eof)
[url=mailto:%$#@62]%$#@62[/url]
;
  若当前记录的位置是在一个 Recordset 对象第一行记录之前时, BOF 属性返回 true,反之则返回 false。
  若当前记录的位置是在一个 Recordset 对象最后一行记录之后时, EOF 属性返回 true,反之则返回 false。
  BOF 与 EOF 都为 False:表示指标位于 RecordSet 的当中。
  BOF 为 True:目前指标指到 RecordSet 的第一笔记录。 EOF 为 True:目前指标指到 RecordSet 的最后一笔记录。
  BOF 与 EOF 都为 True:在 RecordSet 里没有任何记录。
  二、 Move 方法
  您可以用 Move 方法移动指标到 RecordSet 中的某一笔记录,语法如下:
  rs.Move NumRecords,Start
  这里的“rs”为一个对象变量,表示一个想要移动当当前记录位置的 Recordset 对象;“NumRecords”是一个正负数运算式,设定当前记录位置的移动数目;“start”是一个可选的项目,用来指定记录起始的标签。
   所有的 Recordset 对象都支持 Move 方法,如果 NumRecords 参数大于零,当前记录位置向末尾的方向移动;如果其小于零,则当前记录位置向开头的方向移动;如果一个空的 Recordset 对象调用 Move 方法,将会产生一个错误。
   MoveFirst 方法:将当前记录位置移至第一笔记录。
   MoveLast 方法:将当前记录位置移至最后一笔记录。
   MoveNext 方法:将当前记录位置移至下一笔记录。 MovePrevious 方法:将当前记录位置移至上一笔记录。
   Move [n] 方法:移动指标到第 n 笔记录, n 由 0 算起。
  三、 AbsolutePage 属性
  AbsolutePage 属性设定当前记录的位置是位于哪一页的页数编号;使用 PageSize 属性将 Recordset 对象分割为逻辑上的页数,每一页的记录数为 PageSize( 除了最后一页可能会有少于 PageSize 的记录数 )。这里必须注意并不是所有的数据提供者都支持此项属性,因此使用时要小心。
  与 AbsolutePosition 属性相同, AbsolutePage 属性是以 1 为起始的,若当前记录为 Recordset 的第一行记录, AbsolutePage 为 1。可以设定 AbsolutePage 属性,以移动到一个指定页的第一行记录位置。
  四、 AbsolutePosition 属性
  若您需要确定目前指标在 RecordSet 中的位置,您可以用 AbsolutePosition 属性。
  AbsolutePosition 属性的数值为目前指标相对於第一笔的位置,由 1 算起,即第一笔的 AbsolutePosition 为 1。
  注意 , 在存取 RecordSet 时,无法保证 RecordSet 每次都以同样的顺序出现。
  若要启用 AbsolutePosition,必须先设定为使用用户端 cursor( 指针 ), asp 码如下:
  rs2.CursorLocation = 3
  五、 PageCount 属性
  使用 PageCount 属性,决定 Recordset 对象包括多少“页”的数据。这里的“页”是数据记录的集合,大小等于 PageSize 属性的设定,即使最后一页的记录数比 PageSize 的值少,最后一页也算是 PageCount 的一页。必须注意也并不是所有的数据提供者都支持此项属性。
  六、 PageSize 属性
  PageSize 属性是决定 ADO 存取数据库时如何分页显示的关键,使用它就可以决定多少记录组成一个逻辑上的“一页”。设定并建立一个页的大小,从而允许使用 AbsolutePage 属性移到其它逻辑页的第一条记录。 PageSize 属性能随时被设定。
  七、 RecordCount 属性
  这也是一个非常常用和重要的属性,我们常用 RecordCount 属性来找出一个 Recordset 对象包括多少条记录。如:
[url=mailto:$#@60]$#@60[/url]
; % totle=RS.RecordCount
[url=mailto:%$#@62]%$#@62[/url]
;
  在了解了 Recordset 对象的以上属性和方法后,我们来考虑一下,如何运用它们来达到我们分页显示的目的。首先,我们可以为 PageSize 属性设置一个值,从而指定从记录组中取出的构成一个页的行数;然后通过 RecordCount 属性来确定记录的总数;再用记录总数除以 PageSize 就可得到所显示的页面总数;最后通过 AbsolutePage 属性就能完成对指定页的访问。好象很并不复杂呀,下面让我们来看看程序该如何实现呢?
  我们建立这样一个简单的 BBS 应用程序,它的数据库中分别有以下五个字段:“ID”,每个帖子的自动编号;“subject”,每个帖子的主题;“name”,加帖用户的姓名;“email”,用户的电子邮件地址;“postdate”,加帖的时间。数据库的 DSN 为“bbs”。我们将显示帖子分页的所有步骤放在一个名为“ShowList()”的过程中,方便调用。程序如下:
----BBS 显示帖子分页----
[url=mailto:$#@60]$#@60[/url]
; % Sub ShowList()
[url=mailto:%$#@62]%$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
; %
PgSz=20 设定开关,指定每一页所显示的帖子数目,默认为20帖一页
Set Conn = Server.CreateObject("ADODB.Connection")
Set RS = Server.CreateObject("ADODB.RecordSet")
sql = "SELECT * FROM message order by ID DESC"
查询所有帖子,并按帖子的ID倒序排列
Conn.Open "bbs"
RS.open sql,Conn,1,1
If RS.RecordCount=0 then
response.write "
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:P$#@62;$#@60]P$#@62;$#@60[/url]
;
[url=mailto:center$#@62]center$#@62[/url]
;对不起,数据库中没有相关信息!
[url=mailto:$#@60]$#@60[/url]
; /center$#@62;$#@60; /P$#@62;"
else
RS.PageSize = Cint(PgSz) 设定PageSize属性的值
Total=INT(RS.recordcount / PgSz * -1)*-1 计算可显示页面的总数
PageNo=Request("pageno")
if PageNo="" Then
PageNo = 1
else
PageNo=PageNo+1
PageNo=PageNo-1
end if
ScrollAction = Request("ScrollAction")
if ScrollAction = " 上一页 " Then
PageNo=PageNo-1
end if
if ScrollAction = " 下一页 " Then
PageNo=PageNo+1
end if
if PageNo
[url=mailto:$#@60]$#@60[/url]
; 1 Then
PageNo = 1
end if
n=1
RS.AbsolutePage = PageNo
Response.Write "
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:CENTER$#@62]CENTER$#@62[/url]
;"
position=RS.PageSize*PageNo
pagebegin=position-RS.PageSize+1
if position
[url=mailto:$#@60]$#@60[/url]
; RS.RecordCount then
pagend=position
else
pagend= RS.RecordCount
end if
Response.Write "
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:P$#@62;$#@60]P$#@62;$#@60[/url]
; font
[url=mailto:color=Navy$#@62;$#@60]color=Navy$#@62;$#@60[/url]
;
[url=mailto:B$#@62]B$#@62[/url]
;数据库查询结果:$#@60; /B$#@62;"
Response.Write "(共有"&RS.RecordCount &"条符合条件的信息,显示"&pagebegin&"-"&pagend&")$#@60; /font$#@62;$#@60; /p$#@62;"
Response.Write "
[url=mailto:$#@60]$#@60[/url]
; TABLE WIDTH=600 BORDER=1 CELLPADDING=4 CELLSPACING=0
[url=mailto:BGCOLOR=#FFFFFF$#@62]BGCOLOR=#FFFFFF$#@62[/url]
;"
Response.Write "
[url=mailto:$#@60]$#@60[/url]
; TR
[url=mailto:BGCOLOR=#5FB5E2$#@62;$#@60]BGCOLOR=#5FB5E2$#@62;$#@60[/url]
; FONT
[url=mailto:SIZE=2$#@62;$#@60]SIZE=2$#@62;$#@60[/url]
;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
;
[url=mailto:B$#@62]B$#@62[/url]
;主题
[url=mailto:$#@60]$#@60[/url]
; /B$#@62;$#@60; /TD$#@62;$#@60;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
;
[url=mailto:B$#@62]B$#@62[/url]
;用户
[url=mailto:$#@60]$#@60[/url]
; /B$#@62;$#@60; /TD$#@62;$#@60;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
;
[url=mailto:B$#@62;Email$#@60]B$#@62;Email$#@60[/url]
; /B$#@62;$#@60; /TD$#@62;$#@60;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
;
[url=mailto:B$#@62]B$#@62[/url]
;发布日期
[url=mailto:$#@60]$#@60[/url]
; /B$#@62;$#@60; /TD$#@62;$#@60; /FONT$#@62;$#@60; TR
[url=mailto:BGCOLOR=#FFFFFF$#@62]BGCOLOR=#FFFFFF$#@62[/url]
;"
Do while not (RS is nothing)
RowCount = RS.PageSize
Do While Not RS.EOF and rowcount
[url=mailto:$#@62]$#@62[/url]
; 0
If n=1 then
Response.Write "
[url=mailto:$#@60]$#@60[/url]
; TR
[url=mailto:BGCOLOR=#FFFFFF$#@62]BGCOLOR=#FFFFFF$#@62[/url]
;"
ELSE
Response.Write "
[url=mailto:$#@60]$#@60[/url]
; TR
[url=mailto:BGCOLOR=#EEEEEE$#@62]BGCOLOR=#EEEEEE$#@62[/url]
;"
End If
n=1-n
[url=mailto:%$#@62]%$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
; span style="font-size:9pt"
[url=mailto:$#@62;$#@60]$#@62;$#@60[/url]
; A
[url=view.asp?key=$#@60]href=view.asp?key=$#@60[/url]
; % =RS("ID")%$#@62;$#@62;$#@60; % =RS("subject")%$#@62;$#@60; /A$#@62;$#@60; /span$#@62;$#@60; /td$#@62;
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
; span style="font-size:9pt"
[url=mailto:$#@62;$#@60]$#@62;$#@60[/url]
; % =RS("name")%$#@62;$#@60; /A$#@62;$#@60; /span$#@62;$#@60; /td$#@62;
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
; span style="font-size:9pt"
[url=mailto:$#@62;$#@60]$#@62;$#@60[/url]
; a href="
[url=mailto:$#@60]mailto:$#@60[/url]
; % =RS("email")%$#@62;"
[url=mailto:$#@62;$#@60]$#@62;$#@60[/url]
; % =RS("email")%$#@62;$#@60; /a$#@62;$#@60; /span$#@62;
[url=mailto:$#@60]$#@60[/url]
; /TD$#@62;
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:TD$#@62;$#@60]TD$#@62;$#@60[/url]
; span style="font-size:9pt"
[url=mailto:$#@62;$#@60]$#@62;$#@60[/url]
; % =RS("postdate")%$#@62;$#@60; /span$#@62;
[url=mailto:$#@60]$#@60[/url]
; /td$#@62;
[url=mailto:$#@60]$#@60[/url]
; /TR$#@62;
[url=mailto:$#@60]$#@60[/url]
; %
RowCount = RowCount - 1
RS.MoveNext
Loop
set RS = RS.NextRecordSet
Loop
Conn.Close
set rs = nothing
set Conn = nothing
[url=mailto:%$#@62]%$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
; /TABLE$#@62;
[url=mailto:$#@60]$#@60[/url]
; FORM METHOD=GET ACTION="list.asp"
[url=mailto:$#@62]$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
; INPUT TYPE="HIDDEN" NAME="pageno" VALUE="
[url=mailto:$#@60]$#@60[/url]
; % =PageNo
[url='mailto:%$#@62;]%$#@62;"$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
; %
if PageNo
[url=mailto:$#@62]$#@62[/url]
; 1 Then
response.write "
[url=mailto:$#@60]$#@60[/url]
; INPUT TYPE=SUBMIT NAME=ScrollAction VALUE= 上一页
[url=mailto:$#@62]$#@62[/url]
;"
end if
if RowCount = 0 and PageNo
[url=mailto:$#@60]$#@60[/url]
;
[url=mailto:$#@62;Total]$#@62;Total[/url]
then
response.write "
[url=mailto:$#@60]$#@60[/url]
; INPUT TYPE=SUBMIT NAME=ScrollAction VALUE= 下一页
[url=mailto:$#@62]$#@62[/url]
;"
end if
response.write "
[url=mailto:$#@60]$#@60[/url]
; /FORM$#@62;"
End if
[url=mailto:%$#@62]%$#@62[/url]
;
[url=mailto:$#@60]$#@60[/url]
; % End Sub
[url=mailto:%$#@62]%$#@62[/url]
;
  相信大家都应该能完全读懂上面的程序,因此作者就不在此详细解释了。值得注意的是在这段程序中运用了一个小技巧
[url=mailto:$#@60]$#@60[/url]
; INPUT TYPE="HIDDEN" NAME="pageno" VALUE="
[url=mailto:$#@60]$#@60[/url]
; % =PageNo
[url='mailto:%$#@62;]%$#@62;"$#@62[/url]
;,这是用来在每次调用该 ASP 文件时传递数据的“暗道”,由于我们需要在每次调用程序时传递代表当前页码的参数,可能大家会想到使用 session,但是从节省系统资源和通用性来讲,用这样一个隐藏的 form 来传递数据将会达到更好的效果。
  好了,又到了说再见的时候了,如果你没完全看懂本篇中所列的程序,那你必须加把油,看一看 VbScript 的语法;如果你还有某些疑问,可以“妹儿”我,我将尽力解答;如果你有什么更好的建议也千万要来信告诉我哦 :)


第七课.用纯ASP代码实现图片上传并存入数据库中

用ASP编写网站应用程序时间长了,难免会遇到各式各样的问题,其中
  关于如何上传文件到服务器恐怕是遇见最多的问题了,尤其是上传图片,比如你想要在自己的社区里面实现类似网易虚拟社区提供的“每日一星”的功能,就要提供给网友上传照片的功能。上传图片文件到服务器可以使用各种免费的文件上传组件,使用起来功能虽然很强大,但是由于很多情况下,我们只能使用免费的支持ASP的空间或者租用别人的虚拟空间,对于第一种情况,我们根本就没有可能来使用文件上传组件;至于第二种情况,我们也要付出不少的“银子”才可以。除非你拥有自己的虚拟主机,你就可以随便的在服务器上面安装自己所需要的组件,这种情况对于大多数人来说是可望而不可及的。那我们就没有办法了吗?呵呵,答案是肯定的(当然是肯定的了,要不然我也没法写出这篇文章啊)。下面就让我们一起来使用纯ASP代码来实现图片的上传以及保存到数据库的功能(顺便也实现显示数据库中的图片到网页上的功能)。
  首先我们先来熟悉一下将要使用的对象方法。我们用来获取上一个页面传递过来的数据一般是使用Request对象。同样的,我们也可以使用Request对象来获取上传上来的文件数据,使用的方法是Request.BinaryRead()。而我们要从数据库中读出来图片的数据显示到网页上面要用到的方法是:
  Request.BinaryWrite()。在我们得到了图片的数据,要保存到数据库中的时候,不可以直接使用Insert语句对数据库进行操作,而是要使用ADO的AppendChunk方法,同样的,读出数据库中的图片数据,要使用GetChunk方法。各个方法的具体语法如下:
* Request.BinaryRead语法:
variant = Request.BinaryRead(count)
参数
variant
返回值保存着从客户端读取到数据。
count
指明要从客户端读取的数据量大小,这个值小于或者等于使用方法
Request.TotalBytes得到的数据量。
* Request.BinaryWrite语法:
Request.BinaryWrite data
参数
data
要写入到客户端浏览器中的数据包。
* Request.TotalBytes语法:
variant = Request.TotalBytes
参数
variant
返回从客户端读取到数据量的字节数。
* AppendChunk语法
将数据追加到大型文本、二进制数据 Field 或 Parameter 对?
object.AppendChunk Data
参数
object Field 或 Parameter 对象
Data 变体型,包含追加到对象中的数据。
说明
  使用 Field 或 Parameter 对象的 AppendChunk 方法可将长二进制或字符数据填写到对象中。在系统内存有限的情况下,可以使用 AppendChunk 方法对长整型值进行部分而非全部的操作。
* GetChunk语法
返回大型文本或二进制数据 Field 对象的全部或部分内容 。
variable = field.GetChunk( Size )
返回值
返回变体型。
参数
Size 长整型表达式,等于所要检索的字节或字符数。
说明
  使用 Field 对象的 GetChunk 方法检索其部分或全部长二进制或字符数据。在系统内存有限的情况下,可使用 GetChunk 方法处理部分而非全部的长整型值。
GetChunk 调用返回的数据将赋给“变量”。如果 Size 大于剩余的数据,则
GetChunk 仅返回剩余的数据而无需用空白填充“变量”。如果字段为空,则
GetChunk 方法返回 Null。
  每个后续的 GetChunk 调用将检索从前一次 GetChunk 调用停止处开始的数据。但是,如果从一个字段检索数据然后在当前记录中设置或读取另一个字段的值,ADO 将认为已从第一个字段中检索出数据。如果在第一个字段上再次调用 GetChunk 方法,ADO 将把调用解释为新的 GetChunk 操作并从记录的起始处开始读取。如果其他 Recordset 对象不是首个 Recordset 对象的副本,则访问其中的字段不会破坏 GetChunk 操作。如果 Field 对象的 Attributes 属性中的 adFldLong 位设置为 True,则可以对该字段使用 GetChunk 方法。如果在 Field 对象上使用 Getchunk 方法时没有当前记录,将产生错误 3021(无当前记录)。接下来,我们就要来设计我们的数据库了,作为测试我们的数据库结构如下(Access97):
字段名称    类型    描述
  id    自动编号   主键值
img OLE对象   用来保存图片数据 
对于在MS SQL Server7中,对应的结构如下:
字段名称    类型    描述
  id     int(Identity) 主键值
img   image     用来保存图片数据 
  现在开始正式编写我们的纯ASP代码上传部分了,首先,我们有一个提供给用户的上传界面,可以让用户选择要上传的图片。代码如下
(upload.htm):
$#@60;html$#@62;
$#@60;body$#@62;
$#@60;center$#@62;
   $#@60;form name="mainForm" enctype="multipart/form-data"
action="process.asp" method=post$#@62;
    $#@60;input type=file name=mefile$#@62;$#@60;br$#@62;
   $#@60;input type=submit name=ok value="OK"$#@62;
   $#@60;/form$#@62;
$#@60;/center$#@62;
$#@60;/body$#@62;
$#@60;/html$#@62;

  注意代码中黑色斜体的部分,一定要在Form中有这个属性,否则,将无法得到上传上来的数据。
  接下来,我们要在process.asp中对从浏览器中获取的数据进行必要的处理,因为我们在process.asp中获取到的数据不仅仅包含了我们想要的上传上来的图片的数据,也包含了其他的无用的信息,我们需要剔除冗余数据,并将处理过的图片数据保存到数据库中,这里我们以Access97为例。具体代码如下(process.asp):
$#@60;%
response.buffer=true
formsize=request.totalbytes
formdata=request.binaryread(formsize)
bncrlf=chrB(13) & chrB(10)
divider=leftB(formdata,clng(instrb(formdata,bncrlf))-1)
datastart=instrb(formdata,bncrlf & bncrlf)+4
dataend=instrb(datastart+1,formdata,divider)-datastart
mydata=midb(formdata,datastart,dataend)
set connGraph=server.CreateObject("ADODB.connection")
connGraph.ConnectionString="driver={Microsoft Access Driver (*.mdb)};DBQ=" &
server.MapPath("images.mdb") & ";uid=;PWD=;"
connGraph.Open
set rec=server.createobject("ADODB.recordset")
rec.Open "SELECT * FROM [images] where id is null",connGraph,1,3
rec.addnew
rec("img").appendchunk mydata
rec.update
rec.close
set rec=nothing
set connGraph=nothing
%$#@62;

  好了,这下我们就把上传来的图片保存到了名为images.mdb的数据库中了,剩下的工作就是要将数据库中的图片数据显示到网页上面了。一般在HTML中,显示图片都是使用$#@60;IMG$#@62;标签,也就是$#@60;IMG SRC="图片路径"$#@62;,但是我们的图片是保存到了数据库中,“图片路径”是什么呢?呵呵,其实这个SRC属性除了指定路径外,也可以这样使用哦:
$#@60;IMG SRC="showimg.asp?id=xxx"$#@62;

  所以,我们所要做的就是在showimg.asp中从数据库中读出来符合条件的数据,并返回到SRC属性中就可以了,具体代码如下(showimg.asp):
$#@60;%
set connGraph=server.CreateObject("ADODB.connection")
connGraph.ConnectionString="driver={Microsoft Access Driver (*.mdb)};DBQ=" &
server.MapPath("images.mdb") & ";uid=;PWD=;"
connGraph.Open
set rec=server.createobject("ADODB.recordset")
strsql="select img from images where id=" & trim(request("id"))
rec.open strsql,connGraph,1,1
Response.ContentType = "image/*"
Response.BinaryWrite rec("img").getChunk(7500000)
rec.close
set rec=nothing
set connGraph=nothing
%$#@62;

  注意在输出到浏览器之前一定要指定Response.ContentType = "image/*",以便正常显示图片。
  最后要注意的地方是,我的process.asp中作的处理没有考虑到第一页(upload.htm)中还有其他数据,比如$#@60;INPUT type=tesxt name=userid$#@62;等等,如果有这些项目,你的process.asp就要注意处理掉不必要的数据。怎么样,其实上传图片并保存到数据库很简单吧,这样再也不用为自己的空间无法使用各类的上传组件发愁了吧。还等什么?赶快试一试吧。

第八课.ASP进阶教程Ⅷ:数据库版本的留言簿

在前面我们介绍了文件版本的留言簿,现在我们不妨来设想一下:如果留言文件里面的留言很多,而你又急于想寻找其中的某条留言时,这时打开txt留言文件,对着一段段的留言记录,你敢担保你不会当场晕倒吗?而且文件留言簿最令人讨厌还远不只是这个原因,更气人的是:譬如你已经找到了你要找的留言,而且是非要将其删除不可(当然是因为那段留言竟毫不留情地往你脸上抹黑的缘由啦),那么此时其余想对你大发赞赏之言的朋友,就会因为你正在做留言删除的操作而不能留言了。看,这有多可惜!不过,你也无须叹气,虽然留言文件不能供多人共用,但是改成数据库来管理留言记录,当你在做删除留言的期间,访问者的留言还是可以加进来的。既然数据库留言簿能对你的系统如此照顾入微,我们现在就事不宜迟,立即来揭开她的庐山真面目。
至于如何建立自已的数据库版本的留言簿,我们还是通过分步骤的方法来说明吧。要编写一个数据库版本的留言簿,我们大致可以从以下三个步骤来完成。
步骤一:使用Access先建立用来存放留言的数据表。(当然,如果你想使你的数据库能很好地工作在高需求、高质量的Web应用程序的客户-服务器数据库,而且无论是在性能还是在可靠性上都能经受得起严格的考验,那么你最好是用服务器等级的数据库,如:SQL server、Oracle等。对于非服务器等级的数据库,我推荐使用Access中文版来建立。凡是用Access来建立的数据表,都是以.mdb为后缀名,如:book0.mdb。)
Access的界面非常友好,操作也非常简便,相信聪明的读者们,即使以往从未用过Access的,只要动手试试,也定能很快对其驽驾自如,所以我在这里也就不再赘述(当然也不排除有那么几分懒惰的成份)。
步骤二:设计一个留言表单的网页也同样是不可或缺的。(如:guestbook0.htm)。
步骤三:又到编写处理留言的ASP程序了。(我们可以将下述代码COPY下来,然后另存为manage0a.asp文件。)
$#@60; !--#include file="adovbs.inc" --$#@62;

调用adovbs.inc文件,所谓inc 文件顾名思义是include file的意思,adovbs.inc是IIS/PWS所提供的文件,存放着ADO相关常数的定义,使用inc文件可以使我们的程序,增加可读性,更易于开发和维护。
$#@60; % Function SqlStr( data )
SqlStr = "" & Replace( data ", "" ) & ""
End Function

这里用了SqlStr函数,其作用是将数据中的一个单引号改成两个单引号,并且在前后加上单引号。之所以要用该函数是由于上网者输入的数据必须以用单引号括起来的形式输入的数据与Insert Into命令组合在一起,但是如果用户输入的数据含有单引号,则输入的数据将会产生错误,因此输入的数据必须经过SqlStr的切换(将单引号切换成两个单引号)才是正确的。
Name = Request("Name")
Tel=Request("Tel")
Email = Request("Email")
Subject = Request("Subject")
Memo = Request("Memo")

从留言表单取得数据
If Name = "" Or Tel="" Or Email = "" Or Subject = "" Or Memo = "" Then Response.Write "输入框不能为空白!"
Response.End
End If

检查表单的各输入框是否有信息输入,若留有空输入框没填则显示说明信息:"输入框不能为空白!" 并停止执行下面的程序。
Set conn = Server.CreateObject("ADODB.Connection")

用Server.CreateObject取得对象ADODB.Connection。因为在ASP中,如果要访问数据必须首先创建与数据库的链接,因此建立连接是存取Web数据库不可缺少的步骤,执行以上语句之后,conn便是一个Connection对象。
DBPath = Server.MapPath("book0.mdb")

通过调用服务器对象的MapPath方法来获取book0.mdb的完整路径。
conn.Open "driver={Microsoft Access Driver (*.mdb)};dbq=" & DBPath

因为我们想打开的是Access(.mdb)数据库,所以我们要透过Access的ODBC驱动程序{Microsoft Access Driver (*.mdb)}来存取数据库,dbp参数则是用来指定想打开的数据库文件,因为它必须是完整路径名称,所以我们上一语句用了Server.MapPath 函数 。
Name = Left( Name, 40 )
Tel = Left(Tel,10)
Email = Left( Email, 80 )
Subject = Left( Subject, 127 )

截短输入到各字段里数据的长度,以避免因输入到某一字段中的数据超长而引发的错误,当然假如我们将数据库book0.mdb中的各字段的数据类型都有设为“备注”,我们则再无需担心上网者所输入的数据有多长。
sql = "Insert Into GuestBook (姓名, 电话, Email, 主题, 留言) Values( "
sql = sql & SqlStr(Name) & ", "
sql = sql & SqlStr(Tel) & ", "
sql = sql & SqlStr(Email) & ", "
sql = sql & SqlStr(Subject) & ", "
sql = sql & SqlStr(Memo) & ")"

在"guestbook"数据表中增加一个数据记录,然后把其中的各字段 (姓名, 电话, Email, 主题, 留言)分别设置成从留言表单上取下的对应的数据。
conn.Execute sql
执行sql指令。
%$#@62;

第九课.ASP+Access的安全隐患及对策

随着Internet的发展,Web技术日新月异。继通用网关接口(CGI)之后,“ASP”(Active Server Pages)作为一种典型的服务器端网页设计技术,被广泛地应用在网上银行、电子商务、搜索引擎等各种互联网应用中。同时Access数据库作为微软推出的以标准JET为引擎的桌面型数据库系统,由于具有操作简单、界面友好等特点,具有较大的用户群体。因此ASP+Access成为许多中小型网上应用系统的首选方案。但ASP+Access解决方案在为我们带来便捷的同时,也带来了不容忽视的安全问题。
ASP+Access的安全隐患ASP+Access解决方案的主要安全隐患来自Access数据库的安全性,其次在于ASP网页设计过程中的安全漏洞。
1.Access数据库的存储隐患
在ASP+Access应用系统中,如果获得或者猜到Access数据库的存储路径和数据库名,则该数据库就可以被下载到本地。例如:对于网上书店的Access数据库,人们一般命名为book.mdb、store.mdb等,而存储的路径一般为“URL/database”或干脆放在根目录(“URL/”)下。这样,只要在浏览器地址栏中敲入地址:“URL/database/store.mdb”,就可以轻易地把store.mdb下载到本地的机器中。
2.Access数据库的解密隐患
由于Access数据库的加密机制非常简单,所以即使数据库设置了密码,解密也很容易。该数据库系统通过将用户输入的密码与某一固定密钥进行异或来形成一个加密串,并将其存储在*.mdb文件中从地址“&H42”开始的区域内。由于异或操作的特点是“经过两次异或就恢复原值”,因此,用这一密钥与*.mdb文件中的加密串进行第二次异或操作,就可以轻松地得到Access数据库的密码。基于这种原理,可以很容易地编制出解密程序。
由此可见,无论是否设置了数据库密码,只要数据库被下载,其信息就没有任何安全性可言了。
3.源代码的安全隐患
由于ASP程序采用的是非编译性语言,这大大降低了程序源代码的安全性。任何人只要进入站点,就可以获得源代码,从而造成ASP应用程序源代码的泄露。
4.程序设计中的安全隐患
ASP代码利用表单(form)实现与用户交互的功能,而相应的内容会反映在浏览器的地址栏中,如果不采用适当的安全措施,只要记下这些内容,就可以绕过验证直接进入某一页面。例如在浏览器中敲入“……page.asp?x=1”,即可不经过表单页面直接进入满足“x=1”条件的页面。因此,在设计验证或注册页面时,必须采取特殊措施来避免此类问题的发生。
提高数据库的安全性由于Access数据库加密机制过于简单,因此,如何有效地防止Access数据库被下载,就成了提高ASP+Access解决方案安全性的重中之重。
1.非常规命名法
防止数据库被找到的简便方法是为Access数据库文件起一个复杂的非常规名字,并把它存放在多层目录下。例如,对于网上书店的数据库文件,不要简单地命名为“book.mdb”或“store.mdb”,而是要起个非常规的名字,例如:
faq19jhsvzbal.mdb,再把它放在如./akkjj16t/kjhgb661/acd/avccx55 之类的深层目录下。这样,对于一些通过猜的方式得到Access数据库文件名的非法访问方法起到了有效的阻止作用。
2.使用ODBC数据源
在ASP程序设计中,应尽量使用ODBC数据源,不要把数据库名直接写在程序中,否则,数据库名将随ASP源代码的失密而一同失密。例如: DBPath = Server.MapPath(“./akkjj16t/
kjhgb661/acd/avccx55/faq19jhsvzbal.mdb ”)
conn.Open “driver={Microsoft Access Driver (*.mdb)};dbq=” & DBPath 可见,即使数据库名字起得再怪异,隐藏的目录再深,ASP源代码失密后,数据库也很容易被下载下来。如果使用ODBC数据源,就不会存在这样的问题了:
conn.open “ODBC-DSN名”
对ASP页面进行加密为有效地防止ASP源代码泄露,可以对ASP页面进行加密。一般有两种方法对ASP页面进行加密。一种是使用组件技术将编程逻辑封装入DLL之中;另一种是使用微软的Script Encoder对ASP页面进行加密。笔者认为,使用组件技术存在的主要问题是每段代码均需组件化,操作比较烦琐,工作量较大;而使用Script Encoder对ASP页面进行加密,操作简单、收效良好。
Script Encoder方法具有许多优点:
1.HTML仍具有很好的可编辑性。Script Encoder只加密在HTML页面中嵌入的ASP代码,其他部分仍保持不变,这就使得我们仍然可以使用FrontPage或Dreamweaver等常用网页编辑工具对HTML部分进行修改、完善,只是不能对ASP加密部分进行修改,否则将导致文件失效。
2.操作简单。只要掌握几个命令行参数即可。Script Encoder的运行程序是screnc.exe,其使用方法如下:
screnc [/s] [/f] [/xl] [/l defLanguage ] [/e defExtension] inputfile outputfile
其中的参数含义如下:
s:屏蔽屏幕输出;
f:指定输出文件是否覆盖同名输入文件;
xl:是否在.asp文件的顶部添加@Language指令;
l:defLanguag指定缺省的脚本语言;
e:defExtension 指定待加密文件的扩展名。
3.可以批量加密文件。使用Script Encoder可以对当前目录中的所有的ASP 文件进行加密,并把加密后的文件统一输出到相应的目录中。例如:
screnc *.asp c:\temp
4. Script Encoder是免费软件。该加密软件可以从微软网站下载:
http://msdn.microsoft.com/script ... oad/x86/sce10en.exe。下载后,运行安装即可。
利用Session对象进行注册验证
为防止未经注册的用户绕过注册界面直接进入应用系统,可以采用Session对象进行注册验证。Session对象最大的优点是可以把某用户的信息保留下来,让后续的网页读取。例如,要设计如图1所示的注册页面。
设计要求用户注册成功后系统启动hrmis.asp?page=1页面。如果不采用Session对象进行注册验证,则用户在浏览器中敲入“URL/hrmis.asp?page=1”即可绕过注册界面,直接进入系统。利用Session对象可以有效阻止这一情况的发生。相关的程序代码如下:
“hrmis” Or Password  
“password” Then
Response.Write “账号错误!”
Response.End
End If
'将Session 对象设置为通过验证状态
Session(“Passed”) = True
%>
进入应用程序后,首先进行验证:

posted on 2007-03-16 20:57 求勿求 阅读(550) 评论(0)  编辑 收藏 引用 所属分类: IT歧途
只有注册用户登录后才能发表评论。