《无组件上传文件》

发表于:2007-06-30来源:作者:点击数: 标签:
The Upload Scriptbr All the content presented above has to be parsed. In VB or C++, this is quite obvious because many objects and methods are provided for that. To do this in VBScript, we have to use some functions provided by the language
The Upload Script<br>
All the content presented above has to be parsed. In VB or C++, this is quite obvious because many objects and methods are provided for that. To do this in VBScript, we have to use some functions provided by the language and get round the problem of unicode variant string used in VBScript. <br>
<br>
Vbscript Functions<br>
The raw data is in a binary format, so we have to use VBScript function designed to manage binary data. As we can consider the raw data as a string of bytes, the MidB, InstrB and LenB functions become very useful. We have to avoid classic VBScript strings, which are unicode strings not suitable for parsing single bytes. <br>
<br>
These are the only VBScript functions available to parse bytes. We still need a method to get a unicode string from the parsed data in order to use that string in the VBScript code. It should also be useful to have a function that converts unicode string to a bytes string in order to use that string as an argument in InstrB.<br>
<br>
I wrote two functions for that purpose, they are called getString() and getByteString(). They will be explained later in this article.<br>
<br>
Structure<br>
The parsed data are stored in VBScript Dictionary objects. Dictionary objects are hash table objects that store (key, item) pairs. This object is part of VBScript and ASP2.0. <br>
<br>
A first Dictionary object &quot; UploadRequest &quot; is defined. That dictionary object contains all the controls submitted by the upload form. Keys are the names of the controls and Items are themselves dictionary objects that contains information about the control:<br>
<br>
&nbsp;&nbsp;&nbsp;&quot;ControlName1&quot;, Dictionary control1<br>
&nbsp;&nbsp;&nbsp;&nbsp;&quot;ControlName2&quot;, Dictionary control2<br>
<br>
A Dictionary object that represents a control contains the following (key, item) pairs.<br>
<br>
&nbsp;&nbsp;&nbsp;&quot;Value&quot;, String or binary content<br>
&nbsp;&nbsp;&nbsp;&nbsp;&quot;FileName&quot;, Name of uploaded file<br>
&nbsp;&nbsp;&nbsp;&nbsp;&quot;ContentType&quot;, ContentType of uploaded file<br>
<br>
Combining all, we have for example:<br>
<br>
&nbsp;&nbsp;&nbsp;UploadRequest :<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;email&quot;, UploadControl 1 :&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Value&quot;, PhCollignon@email.com<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;blob&quot; , UploadControl 2 :<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;filename&quot;, C:/image/file.gif<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;ContentType&quot; : image/gif<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Value&quot; : GIF89ai…<br>
<br>
This is an &quot;object&quot; approach quite useful to aclearcase/" target="_blank" >ccess and use data afterwards.<br>
<br>
Parser<br>
Here is the code to parse, read and record upload controls. The process is done by a routine &quot;BuildUploadRequest&quot;; this routine takes only one argument that is the raw binary data RequestBin.<br>
<br>
Sub BuildUploadRequest(RequestBin)<br>
<br>
First we try to find the boundary. This boundary is useful to know when the loop on controls ends.<br>
<br>
&nbsp;&nbsp;&nbsp;‘’Get the boundary<br>
&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = 1<br>
&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;boundary = MidB(RequestBin,PosBeg,PosEnd-PosBeg)<br>
&nbsp;&nbsp;&nbsp;&nbsp;boundaryPos = InstrB(1,RequestBin,boundary)<br>
<br>
A problem is that InstrB needs byte strings as arguments. A function was written for that purpose: getByteString(String) method can convert the unicode VBScript string to a byte string. This function is described at the end of the code explanations.<br>
<br>
Let’s do a loop until we find the closing boundary.<br>
<br>
&nbsp;&nbsp;&nbsp;‘’Get all data inside the boundaries<br>
&nbsp;&nbsp;&nbsp;&nbsp;Do until (boundaryPos=InstrB(RequestBin,boundary & getByteString(&quot;--&quot;)))<br>
<br>
For each step in the loop, we process one control. All data about that control are saved in a dictionary object. A new dictionary object UploadControl is created at each loop.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Members variable of objects are put in a dictionary object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dim UploadControl<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set UploadControl = CreateObject(&quot;Scripting.Dictionary&quot;)<br>
<br>
We first get the name of the control, which can be found in the &quot; Content-Disposition &quot; header. The end of the name is delimited by the &quot; character or chr(34). <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Get an object name<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pos = InstrB(BoundaryPos,RequestBin,_<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getByteString(&quot;Content-Disposition&quot;))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pos = InstrB(Pos,RequestBin,getByteString(&quot;name=&quot;))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = Pos+6<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))<br>
<br>
Here we have to test if the control is a file type control or a text type control. If the control is a text type control, no other data than its name are provided. If the control is a file type control, we can get more information such as file name and Content-Type.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosFile=InstrB(BoundaryPos,RequestBin,getByteString(&quot;filename=&quot;))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBound = InstrB(PosEnd,RequestBin,boundary)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Test if object is of file type<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;&nbsp;PosFile&lt;&gt;0 AND (PosFile&lt;PosBound) Then<br>
<br>
If control is a file type control, we parse the path and file name and add them to the dictionary object of the control. The parsed file name is a string of bytes, it is necessary to convert it to unicode so that it can be used as a variant string variable. This is done by the getString() method defined at the end.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Get Filename, content-type and content of file<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = PosFile + 10<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileName = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Add filename to dictionary object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UploadControl.Add &quot;FileName&quot;, FileName<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pos = InstrB(PosEnd,RequestBin,getByteString(&quot;Content-Type:&quot;))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = Pos+14<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Add content-type to dictionary object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ContentType = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UploadControl.Add &quot;ContentType&quot;,ContentType<br>
<br>
Now we can get the core content of the file. The content does not have to be converted because it is a binary content. It should be saved to a file system or put as binary long object (blob) in a database.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Get content of object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = PosEnd+4<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,boundary)-2<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value = MidB(RequestBin,PosBeg,PosEnd-PosBeg)<br>
&nbsp;&nbsp;&nbsp;&nbsp;Else<br>
<br>
In the case of a text type control, there is no other data to parse than the content. The content is converted to a unicode string so that it can be used later in the VBScript code.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Get content of object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pos = InstrB(Pos,RequestBin,getByteString(chr(13)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosBeg = Pos+4<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosEnd = InstrB(PosBeg,RequestBin,boundary)-2<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))<br>
&nbsp;&nbsp;&nbsp;&nbsp;End If<br>
<br>
The content is added to the dictionary object. The key is set to &quot; Value &quot;, and the item is the content. That content can be either a string or a binary data depending on the type of the control.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Add content to dictionary object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UploadControl.Add &quot;Value&quot; , Value&nbsp;&nbsp;&nbsp;&nbsp;<br>
<br>
Finally, the dictionary object of the control is added to the global dictionary object. The key used is the name of the control. The item is the dictionary objet UploadControl we have just built.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Add dictionary object to main dictionary<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UploadRequest.Add name, UploadControl&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;‘’Loop to next object<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BoundaryPos=InstrB(BoundaryPos+LenB(boundary),RequestBin,boundary)<br>
&nbsp;&nbsp;&nbsp;&nbsp;Loop<br>
<br>
End Sub<br>
Byte-String Conversion Functions<br>
Here is the function used to convert a byte string to a unicode string.<br>
<br>
‘’Byte string to string conversion<br>
Function getString(StringBin)<br>
&nbsp;&nbsp;&nbsp;&nbsp;getString =&quot;&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;For intCount = 1 to LenB(StringBin)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getString = getString & chr(AscB(MidB(StringBin,intCount,1))) <br>
&nbsp;&nbsp;&nbsp;&nbsp;Next<br>
End Function<br>
<br>
Here is the function that converts a string to a byte string. This function is used to format arguments of the InstrB function. <br>
<br>
‘’String to byte string conversion<br>
Function getByteString(StringStr)<br>
&nbsp;&nbsp;&nbsp;&nbsp;For i = 1 to Len(StringStr)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char = Mid(StringStr,i,1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getByteString = getByteString & chrB(AscB(char))<br>
&nbsp;&nbsp;&nbsp;&nbsp;Next<br>
End Function<br>
<br>
Uses of Upload Script<br>
Here are sample uses of the upload script developed here. Samples files and code are provided with the download file of this article. Extract the zip file to a directory and configure a virtual directory for your web server. You can test and launch uploadForm.html from your browser.<br>
<br>
Calling the Script<br>
Here is the way to call the upload BuildUploadRequest method. You have first to define the global dictionary UploadRequest. Then you have to call the BuilUploadRequest method and pass to the request raw binary data in the argument.<br>
<br>
byteCount = Request.TotalBytes<br>
RequestBin = Request.BinaryRead(byteCount)<br>
Dim UploadRequest<br>
Set UploadRequest = CreateObject(&quot;Scripting.Dictionary&quot;)<br>
<br>
BuildUploadRequest&nbsp;&nbsp;RequestBin<br>
<br>
The data is parsed and saved in the dictionary object that you can retreive with Item() method. These item data can be stored in VBScript variables and used everywhere in the code. Data can simply be sent back as response to the client, used in ASP code, written to a file or put in a database field.<br>
<br>
Retrieving the Data<br>
The data of the UploadRequest object can be accessed by the Item(&quot;key&quot;) function. Let’s consider a scenario where you would like to access the value of the email control; this can be done by:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;email = UploadRequest.Item(&quot;email&quot;).Item(&quot;Value&quot;)<br>
<br>
As this is a text type control, content is a string and can be used as any other VBScript string. For binary data, content can be retrieved in the same way. <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;picture = UploadRequest.Item(&quot;blob&quot;).Item(&quot;Value&quot;)<br>
It is also possible to access other information like file name or content-type. They are text type controls.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;contentType = UploadRequest.Item(&quot;blob&quot;).Item(&quot;ContentType&quot;)<br>
&nbsp;&nbsp;&nbsp;&nbsp;filepathname = UploadRequest.Item(&quot;blob&quot;).Item(&quot;FileName&quot;)<br>
<br>
Using the Data in VBScript Code<br>
The uploaded data can be used in VBScript code as any other variable. They can, for example, be sent back as response to the client.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;Your email is : &lt;%=email%&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;File name of you picture is &lt;%=filepathname%&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;File type of your picture is &lt;%=contentType%&gt;<br>
<br>
Binary data can also be sent back to the client. A content-type has to be set and the binary data should be written with the BinaryWrite method.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;Response.ContentType = contentType<br>
&nbsp;&nbsp;&nbsp;&nbsp;Response.BinaryWrite picture<br>
<br>
Writing Uploaded Data to File<br>
In the case of a file type control, the goal is usually to store the binary data in a file or in a database field rather than sending them back to the client. This &quot;persistent&quot; feature is one of the main goals of file uploading. The FileSystem object can be used to store the uploaded file to the file system of the server.<br>
<br>
First let us create a FileSystem object:<br>
<br>
‘’Create FileSytemObject Component<br>
Set ScriptObject = Server.CreateObject(&quot;Scripting.FileSystemObject&quot;)<br>
<br>
Create a file in a directory with the fileSystem object. That directory can be absolute and refer directly to the file system (e.g. c:\temp). The directory can also be relative to a virtual directory defined on the web server. This virtual directory is mapped to the absolute directory with the mappath method and the PATH_INFO server variable.<br>
<br>
The Write method needs a unicode string as argument so we convert the byte array to a string. The Write method is responsible for converting that unicode string and writes it using ASCII format. This builds a file that contains the binary content of our original byte string. I have called that file ‘’ uploaded+filename ‘’, just for distinguishing the file, but you can choose whatever filename you like:<br>
<br>
‘’Create and Write to a File<br>
Set MyFile = ScriptObject.CreateTextFile(Server.mappath(Request.ServerVariables_<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&quot;PATH_INFO&quot;)) & &quot;uploaded&quot; & filename)<br>
For i = 1 to LenB(value)&nbsp;&nbsp;&nbsp;MyFile.Write chr(AscB(MidB(value, i, 1)))Next<br>
MyFile.Close<br>
Storing Uploaded Data to Database<br>
The data could also be stored in a database. The content-type should also be stored in the database to be able to display the data afterwards. You first have to establish a connection to your database, assuming you already have set up the appropriate DSN:<br>
<br>
Set conn = Server.CreateObject(&quot;ADODB.Connection&quot;)<br>
conn.open &quot;DSN=wroxdns&quot;,&quot;user&quot;,&quot;pass&quot;<br>
<br>
Then create a Recordset from that connection:<br>
<br>
sql = &quot;SELECT PHOTO, CONTENTTYPE FROM MYTABLE&quot;<br>
Set rs = Server.CreateObject(&quot;ADODB.Recordset&quot;)<br>
rs.Open sql, conn, 3, 3<br>
<br>
When the Recordset is created, you have to put the binary data in the blob field of the database:<br>
<br>
picturechunk =&nbsp;&nbsp;picture & chrB(0)<br>
rs.Fields(&quot;PICTURE&quot;).appendChunk picturechunk<br>
rs.Fields(&quot;CONTENTTYPE&quot;) = contentType<br>
rs.Update<br>
conn.close<br>
<br>
I had to get round a small bug in appendChunk method. In fact, I noticed that when my binary data had an odd number of bytes, the appendChunk method did not transfer the last byte! A solution was to add a chr(0) to be sure to transfer all the bytes. Maybe there is another solution for that, if so, let me know.<br>
<br>
To get the image from the database, use the same Recordset and send it back as response to the client with the right content type.<br>
<br>
Response.contentType = rs.Fields(&quot;CONTENTTYPE&quot;)<br>
size = rs.Fields(&quot;PICTURE&quot;).ActualSize<br>
blob = rs.Fields(&quot;PICTURE&quot;).GetChunk(size)<br>
Response.binarywrite blob<br>
Conclusion<br>
This article presents a complete VBScript solution to uploading files. This code is pure VBScript and is independent of third party products.<br>
<br>
It focuses first on the upload process (HTML form submission with the content type &quot; multipart/form-data &quot;). Then the uploading VBScript code is explained in detail. This starts with a brief recall of VBScript functions needed to manipulate strings and byte arrays. I then presented the code of the upload script and the structure of the uploaded data.<br>
<br>
Finally we showed several uses for this script, from simply using an uploaded variable in ASP code to the storage of an uploaded file in a database or in the file system. <br>

原文转自:http://www.ltesting.net