<%
当表单里既有文本域又有文件域的时候,我们必须把表单的编码类型设置成"multipart/form-data"类型
这时候上传上来的编码文件并不能直接取出文本域的值和文件域的二进制数据,这就需要拆分表单域
在上传上来的数据流中在每个表单域间都有一个随机的分隔符,这个分隔符是在同一个流中不变的,不同的流分隔符不变,
这个分隔符在流的最开头,并且以一个chrb(13) + chrb(10)结束,知道这个后我们就可以用这个分隔符来遍历拆分表单域了.
对于文件域,我们要解析字段名,文件名,文件类型和文件内容,域名是以"name="为前导,并包含在一对双引号中,文件名的值是以"filename="为前导,也包含在双引号里,其中包含文件的全路径和文件名,紧跟着后面又是一对回车换行府(chrb(13) +chrb(10)),字符串"content-type:"和两对回车换行之间的内容为文件类型字符串,两对回车换行后到一对回车换行之间的数据为文件内容
对于文本域,我们只要解析他的值就可以了,域的名称是以"name="之后,用双引号包着,两对回车换行后到以一对回车换行开始的域分隔符之间为该文本域的值
当然上传上来的流是二进制格式,在操作的时候需要用一些操作二进制的函数,而不是平时用的操作字符串的函数,比如说leftb,midb,instrb等,下面就是算法的实现
class getpost
private bdatastr,separationstr,wawa_stream 提交的信息,表单域间分隔字符
类初始化
private sub class_initialize
set wawa_stream=createobject("adodb.stream") 创建全局流
wawa_stream.mode=3 读写模式
wawa_stream.type=1 二进制读取模式
wawa_stream.open 打开流
bdatastr=request.binaryread(request.totalbytes)获取上传的所有数据
wawa_stream.write bdatastr 读取数据
separationstr=leftb(bdatastr,clng(instrb(bdatastr,chrb(13) + chrb(10)))-1) 分隔字符串
end sub
类的析构函数,卸载全局流对象
private sub class_terminate
wawa_stream.close
set wawa_5xsoft_stream=nothing
end sub
返回file型表单域的值(二进制)
public function getfile (fieldname)
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34)))
datastart = instrb(l1,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) +4
datalng = instrb(datastart,bdatastr,separationstr) – datastart -2
getfile =midb(bdatastr,datastart,datalng)
end function
返回文件的类型
public function getfiletype (fieldname)
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34)))
datastart = instrb(l1,bdatastr,getbinary("content-type:")) + 13
datalng = instrb(datastart,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) – datastart
getfiletype =gettext(midb(bdatastr,datastart,datalng))
end function
返回文件的原始路径
public function getfilepath (fieldname)
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34)))
datastart = instrb(l1,bdatastr,getbinary("filename=")) + 9
datalng = instrb(datastart,bdatastr,chrb(13) + chrb(10)) – datastart
getfilepath = gettext(midb(bdatastr,datastart+1,datalng-2)) 去掉最左边和最右边的双引号,不知道为什么右边的双引号要减去2
end function
返回原始文件的后缀名
function getextendname(fieldname)
filename = getfilepath(fieldname)
if isnull(filename) or filename="" then
getextendname=""
exit function
end if
getextendname = mid(filename,instrrev(filename, "."))
end function
返回file型表单域的值(二进制)
public function getfilesize (fieldname)
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34)))
datastart = instrb(l1,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) +4
datalng = instrb(datastart,bdatastr,separationstr) – datastart -2
getfilesize = datalng
end function
从二进制字符串里取出表单域的值(字符串)
public function retfieldtext (fieldname)
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34)))
datastart = instrb(l1,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) +4
datalng = instrb(datastart,bdatastr,separationstr) – datastart -2
retfieldtext =gettext(midb(bdatastr,datastart,datalng))
end function
返回一个时间和随机数连接后的字符串,用于构建文件名
function getrandstr()
dim rannum
randomize
rannum = int(90000*rnd)+10000
getrandstr = year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&rannum
end function
将二进制外码系列转换成vb字符串
private function gettext (str1r)
dim s,t,t1,i
s = "":t="":t1=""
for i =1 to lenb(str1r)
t= ascb(midb(str1r,i,1)) 按字节取出外码
if not(t > 127) then 字节高位为0,表示英文字符
s = s + chr(t)
else
i = i +1 当为汉字时,取第二个字节
t1 = ascb(midb(str1r,i,1))
s = s + chr(t * 256 + t1) 将汉字两字节外码组合成ansi码
end if
next
gettext = s
end function
将字符串转换为二进制系列
private function getbinary(str1)
dim t2,t1
for i = 1 to len(str1)
t1 = cstr(hex(asc(mid(str1,i,1))))
if len(t1)=2 then
t2 = t2 + chrb(clng("&h" + trim(t1)))
else
t2 = t2 + chrb(clng("&h") + mid(trim(t1),1,2))
t2 = t2 + chrb(clng("&h") + mid(trim(t1),3,2))
end if
next
getbinary = t2
end function
将上传的文件保存在服务器的硬盘上
public function savetofile (fieldname,fullpath)
dim dr 定义创建一个流
savetofile=""
if trim(fullpath)="" or filename="" then exit function 检测参数是否有真实数据
if right(fullpath,1)="/" then exit function 检测路径的正确性
set dr=createobject("adodb.stream")
dr.mode=3 读写模式
dr.type=1 二进制模式
dr.open 打开
dim l1,datastart,datalng
l1 = instrb(bdatastr,getbinary("name=" + chr(34) +fieldname +chr(34))) 获取file域的位置
datastart = instrb(l1,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) +4 实体数据的开始位置
datalng = instrb(datastart,bdatastr,chrb(13) + chrb(10) + chrb(13) + chrb(10)) – datastart 实体数据的大小
wawa_stream.position=datastart-1 设置全局流的游标,因为全局流和全局数据bdatastr对应的
wawa_stream.copyto dr,datalng 从全局流里获取数据
dr.savetofile fullpath,2 保存在指定位置
dr.close 关闭流
set dr=nothing 析构流
savetofile=mid(filename,instrrev(filename, "\")+1) 返回上传文件的文件名
end function
end class
%>
<!– conn.asp文件里有数据库连接字符串并打开数据库 –>
<!–#include file="conn.asp" –>
<!– getpost.asp文件包含上面的getpost类 –>
<!–#include file="getpost.asp" –>
<%
为了测试这个类,我们写个html表单(在index.asp文件里),里面有两个文本域txt1,txt2,两个文件域file1,file2,我们再建立一个数据库,里面有4个字段,id,txt1,txt2,file1,file2,类型分别为文本,文本,文本,ole格式,表名为mytable
set o = new getpost
response.write("file1的原始路径是:" & o.getfilepath ("file1") & "<br>")
response.write("file1的文件类型是:" & o.getfiletype ("file1") & "<br>")
response.write("file1的原始文件扩展文件名:" & o.getextendname ("file1") & "<br>")
response.write("file1的原始文件大小:" & o.getfilesize ("file1") & "字节<br>")
filename=server.mappath("upload")& "\" & o.getrandstr()& o.getextendname("file1")
response.write("file1上传后的位置:" & filename & "<br>")
dim file1name
file1name=o.savetofile ("file1",filename)
response.write (filename & "上传成功<br>")
dim rs,sql
set rs = server.createobject("adodb.recordset")
sql = "select txt1,txt2,file1,file2 from mytable"
rs.open sql,conn,1,3
rs.addnew
rs("txt1")= o.retfieldtext("txt1")
rs("txt2")= o.retfieldtext("txt2")
rs("file1") = file1name
rs("file2").appendchunk o.getfile("file2") 把file2上传的文件直接写到数据库里
rs.update
rs.close
set rs=nothing
call closedata() 关闭数据库
response.redirect("index.asp")
%>