分享
 
 
 

用ASP和VBScript上载文件(一)

王朝asp·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

青苹果电脑工作室

从浏览器上载文件是从客户机向服务器传递文件的一个简易方法。从第三代浏览器Netscape和 Microsoft起,多数浏览器都可以向服务器上载文件,而不需要向用户提供特殊的访问方式或软件。

一些ASP组件是为文件上载而设计的,例如:

Posting Acceptor

( Microsoft SiteServer的一部分),

AspSmartUpload(Advantys),

AspUpload (PersistsSoftware),

SA-FileUpSoftware Artisants)

本文的开始将告诉你关于创建这类组件的信息,而这些组件通常使用VB、C++或Java。

这些组件的问题在于它们是第三方产品而非标准ASP的一部分。作为第三方组件,必须在服务器上进行安装。这就意味着必须在服务器上复制DLL并注册。大多数的主机系统不允许在他们的服务器上进行这样的设置,因为有可能发生配置问题(尤其是虚拟主机)。第二个缺点是它们大部分不是免费的,不提供源代码,也就不能根据需要进行定制。

因此我需要编写VBScript代码来解决文件上载的问题。这不是一个必然的选择,因为VBScript是一种脚本语言,只能使用variants数据类型,并且不能提供许多管理二进制数据和字节数组的内置函数。

要理解上载的过程,首先要知道数据用HTTP协议从浏览器发送到服务器的方式。这就意味着要理解“ multipart/form-data” (多部分/格式-数据)的表单提交。

上载表单

通常情况下,使用HTML表单从浏览器向服务器传递数据。这个表单中可能包含文本域、检验框、按钮以及上载文件的文件类型控制。使用者用自己的数据填充并将这个表提交给服务器。

表单元素中的 enctype 属性规定了传递给服务器的表数据集编码的内容类型。enctype 属性的默认值是“application/x-www-form-urlencoded”,但当向服务器传送大量文本、包含非ASCII字符或二进制数的数据时,这个默认类型就不能胜任了。这时,文件上载提交表单时应使用“multipart/form-data”内容类型。

一个“multipart/form-data”信息包含一系列部件,每个部件都可能包含:

一个Content-Disposition(内容-处理)头,其值为"form-data" ;一个规定控制名的name(名称)属性。

对于一个文件类型控制,一个部件可能包含更多信息:

在客户机上规定原始路径和文件名的filename(文件名)属性;所发送的二进制数据控制的Content-Type (内容-类型)头。

在这些头的后面跟随着控制的二进制或文本内容。

以下例子说明“multipart/form-data”的编码,客户机的浏览器应有这个表单:

如果这个表单被提交,在服务器上可读到这些请求:

-----------------------------7cf87224d2020a

Content-Disposition: form-data; name="email"

PhCollignon@email.com

-----------------------------7cf87224d2020a

Content-Disposition: form-data; name="blob"; filename="c:\image.gif"

Content-Type: image/pjpeg

-----------------------------7cf87224d2020a

Content-Disposition: form-data; name="Enter"

Submit Query

-----------------------------7cf87224d2020a--

当那个内容作为响应被传送回客户机时就会被显示出来。应该用Request.binaryRead 和Response.binaryWrite 方法读和写二进制数据。

〈%

Response.BinaryWrite(Request.BinaryRead(Request.TotalBytes))

%〉

可以看到响应的各部分用分界线来划分:

-----------------------------7cf87224d2020a

最后一个分界线后面跟随的是’ -- ’ 。

每一个控制都有一个Content-Disposition 。name属性识别由HTML表发送的控制(email、blob和Enter)。 对于一个文件类型控制(blob),

文件名也是Content-Disposition 头的一部分,Content-Type 头给出二进制 数据的内容类型。

上载脚本

上面所有内容都必须经过分解。在VB 或 C++中, 这非常明显,因为为此提供了许多对象和方法。在VBScript 中,必须使用语言所提供的一些函数,并要解决VBScript中使用的双字节编码的变量字符串的问题。

VBScript函数

原始数据是二进制格式,所以必须使用专为管理二进制数据而设计的VBScript函数。因为我们将原始数据作为一个字节的字符串来考虑, 所以 MidB、InstrB 和 LenB 函数就有用了。 但是要避免VBScript的classic字符串,因为它们是双字节编码的字符串,不适宜分解成单字节。

这些是VBScript函数中仅有的用来分解字节的函数。还需要一个方法,从被分解的数据中得到双字节编码的字符串,这样就可以使用VBScript编码中的字符串了。为了在InstrB中把字符串作为一个自变量使用,还需要一个函数,把双字节字符串转换成单字节字符串。

为了我写了两个函数,getString() 和 getByteString(),稍后再对此进行解释。

结构

分解的数据被存储在VBScript Dictionary 对象中。 Dictionary 对象是hash 表对象,它存储(key, item)对。它是VBScript和ASP2.0的一部分。

定义第一个Dictionary 对象 " UploadRequest " 。这个对象包含由上载表提交的所有控制。Key是控制的名字,Item则是对象中所包含的控制的信息:

"ControlName1", Dictionary control1

"ControlName2", Dictionary control2

代表一个控制的Dictionary 对象包含着下面的(key, item) 对:

"Value", String or binary content

"FileName", Name of uploaded file

"ContentType", ContentType of uploaded file

把这些结合起来,就有以下例子:

UploadRequest : "email", UploadControl 1 : "Value", PhCollignon@email.com

"blob" , UploadControl 2 : "filename", C:/image/file.gif "ContentType" :

image/gif "Value" : GIF89ai?

这个对象对于以后存取和使用数据非常有用。

分解

这里是分解、读和记录上载控制的代码。这个过程用"BuildUploadRequest"程序来完成,这个程序只有一个自变量,就是原始二进制数据RequestBin。

Sub BuildUploadRequest(RequestBin)

首先要找到分界线,通过分界线可以知道控制循环何时结束。

’Get the boundary PosBeg = 1 PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))

boundary = MidB(RequestBin,PosBeg,PosEnd-PosBeg) boundaryPos = InstrB(1,RequestBin,boundary)

有一个问题是InstrB需要单字节字符串作为自变量。为此写了一个函数:getByteString(String) ,此方法可以把VBScript的双字节字符串转换成单字节字符串。在代码解释的最后再描述这个函数。

在找到结束分界线之前进行下列循环:

’Get all data inside the boundaries

Do until (boundaryPos=InstrB(RequestBin,boundary & getByteString("--")))

循环中的每一步都处理一个控制。有关这一控制的所有数据都保存在dictionary对象中。每一个循环创建一个新的dictionary对象UploadControl。

’Members variable of objects are put in a dictionary object Dim UploadControl

Set UploadControl = CreateObject("Scripting.Dictionary")

首先从" Content-Disposition " 头中找到控制的名字。名字的结尾用"字符或chr(34)划分。

’Get an object name Pos = InstrB(BoundaryPos,RequestBin,getByteString("Content-Disposition"))

Pos = InstrB(Pos,RequestBin,getByteString("name=")) PosBeg = Pos+6 PosEnd

= InstrB(PosBeg,RequestBin,getByteString(chr(34))) Name = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))

现在测试控制是文件类控制还是文本类控制。如果是文本类控制,除了它的名字以外没有其它任何数据。 如果是文件类控制,就会得到一些额外信息,如文件名和Content-Type。

PosFile=InstrB(BoundaryPos,RequestBin,getByteString("filename=")) PosBound

= InstrB(PosEnd,RequestBin,boundary) ’Test if object is of file type If

PosFile〈〉0 AND (PosFile〈PosBound)

Then 如果是控制是文件类控制,就将路径和文件名进行分解,并将他们填加到控制的dictionary 对象中。分解后的文件名是一个单字节字符串,要将它转换成双字节字符串才能作为variant字符串变量使用。这通过最后定义的getString()方法来实现:

’Get Filename, content-type and content of file PosBeg = PosFile + 10 PosEnd

= InstrB(PosBeg,RequestBin,getByteString(chr(34))) FileName = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))

’Add filename to dictionary object UploadControl.Add "FileName", FileName

Pos = InstrB(PosEnd,RequestBin,getByteString("Content-Type:")) PosBeg =

Pos+14 PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13))) ’Add content-type

to dictionary object ContentType = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))

UploadControl.Add "ContentType",ContentType 现在就可以得到文件的核心内容了。这个内容不需要转换,因为它是二进制的。可以将它存入一个文件系统或作为一个二进制长对象(blob)放入数据库中。

’Get content of object PosBeg = PosEnd+4 PosEnd = InstrB(PosBeg,RequestBin,boundary)-2

Value = MidB(RequestBin,PosBeg,PosEnd-PosBeg)

Else 如果是文本类控制,除了内容以外就没有其它数据需要分解。内容要转换成为双字节字符串,以便将来用 在VBScript代码中。

’Get content of object Pos = InstrB(Pos,RequestBin,getByteString(chr(13)))

PosBeg = Pos+4 PosEnd = InstrB(PosBeg,RequestBin,boundary)-2 Value = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))

End If

将内容加入dictionary对象中。将key设置成 " Value ",那么item 就是内容。根据控制类型的不同,内容可以是字符串或二进制数据。

’Add content to dictionary object

UploadControl.Add "Value" , Value

最后将控制的dictionary 对象加入一个全程dictionary 对象中。使用的key 是控制的名字。item 是刚刚创建的dictionary对象,名为UploadControl。

’Add dictionary object to main dictionary UploadRequest.Add name, UploadControl

’Loop to next object BoundaryPos=InstrB(BoundaryPos+LenB(boundary),RequestBin,boundary)

Loop End Sub

字节-字符串转换函数

下面是将双字节字符串转换成单字节字符串的函数。

’Byte string to string conversion Function getString(StringBin) getString

="" For intCount = 1 to LenB(StringBin) getString = getString & chr(AscB(MidB(StringBin,intCount,1)))

Next End Function 下面是将字符串转换成单字节字符串的函数,它用来格式化InstrB函数的自变量。

’String to byte string conversion Function getByteString(StringStr) For

i = 1 to Len(StringStr) char = Mid(StringStr,i,1) getByteString = getByteString

& chrB(AscB(char)) Next End Function

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有