top
Loading...
多文件上傳組件
p>(因為我還沒完成我的組件,不保證文章中的代碼的正確性.)上傳多文件(Sander Duivestein)介紹這是我寫的一個上傳文件的activex的組件.這個組件是使用winsocket控件調用FTP提交文件.它僅僅工作在Ie3.02或更高的版本,但有些客戶端使用Netscape,因此不得不找另外的解決方案.但我搜索Internet和若干新聞組時,發現不止我一個有這樣的要求.在1999.3.11,看到啦Doug Dean的一篇15Seconds的文章(關于用VB asp組件上傳文件)給我啦一個很好的提示.

Doug Dean的組件簡單并且易用.但他說,然而,多元件的上傳問題沒解決?因而仍然有一些工作要完成.

在我開始做自己的組件以前,我想知道其他類似控件提供什么樣的功能.因此我看啦另外3個著名的組件:the upload component of Software Artisans, the upload component of ASPUpload,and the Microsoft Posting Acceptor.

通過比較這些組件我覺的我的組件應該滿足下列要求:

提交文件的HTML表單對asp組件應該是一黑盒子.也就是說組件能接受各種表單元件并能得到表單元件的名字和值.它應能提供一個上傳路徑,并且限制大小.組件應該能處理多個的文件.組件應該有一錯誤處理程序.組件應該性能很好.組件應該能在NC中象IE一樣工作.保存文件進入數據庫.僅允許某組用能上載文件.這些對我來說是有相當的挑戰.解決問題首先我要創建一HTML文件,它包含兩個元件:一簡單的文本框,一文件框.這里給出下列代碼:1:Upload.htm

$#@60;HTML$#@62;$#@60;HEAD$#@62;$#@60;TITLE$#@62;Upload$#@60;/TITLE$#@62;$#@60;/HEAD$#@62;$#@60;BODY$#@62;$#@60;FORM NAME="frmUpload" METHOD="Post" ENCTYPE="multipart/form-data" ACTION="Upload.asp"$#@62; $#@60;TABLE$#@62;$#@60;TR$#@62;$#@60;TD$#@62;Author$#@60;/TD$#@62;$#@60;TD$#@62;$#@60;INPUT TYPE="text" NAME="txtAuthor"$#@62;$#@60;/TD$#@62;$#@60;/TR$#@62;$#@60;TR$#@62;$#@60;TD$#@62;File$#@60;/TD$#@62;$#@60;TD$#@62;$#@60;INPUT TYPE="file" NAME="txtFileName"$#@62;$#@60;/TD$#@62;$#@60;/TR$#@62;$#@60;TR$#@62;$#@60;TD COLSPAN="2" ALIGN="right"$#@62;$#@60;INPUT TYPE="Submit" VALUE="Upload"$#@62;$#@60;/TD$#@62;$#@60;/TR$#@62;$#@60;/TABLE$#@62;$#@60;/FORM$#@62;$#@60;/BODY$#@62;$#@60;/HTML$#@62;

使用ENCTYPE="multipart/form-data"使表單能夠提交一文件.我們也需要一文件接收文件.2: oad.asp$#@60;%@ Language=VBScript %$#@62;

$#@60;%Option explicitResponse.Buffer = TrueOn Error Resume Next

If Request.ServerVariables("REQUEST_METHOD") = "POST" Then

Dim objUpload

Dim lngMaxFileBytes

Dim strUploadPath

Dim varResult

lngMaxFileBytes = 10000

strUploadPath = "c:inetpubwwwrootupload"

Set objUpload = Server.CreateObject("pjUploadFile.clsUpload")

If Err.Number $#@60;$#@62; 0 Then

Response.Write "The component wasnt registered"

Else

varResult = objUpload.DoUpload (lngMaxFileBytes, strUploadPath)

Set objUpload = NothingDim i

For i = 0 to UBound(varResult,1)

Response.Write varResult(i,0) & " : " & varResult(i,1) & "$#@60;br$#@62;"

Next

End If

End If%$#@62;

在這里設置下面兩個變量:lngMaxFileBytes - 文件最大字節數,和 strUploadPath -文件上傳位置.我也增加了錯誤處理程序檢查是否裝入組件在網服務器上適當注冊.這是我做的處理唯一的一個錯誤.如果任何另外的錯誤發生,可以再加入處理它.最后,再聲明varReturn.這變量用來接受組件的返回值.這返回值應該包含所有的表單元件名字和他們的值.你能看見FOR NEXT loop中的程序,這返回值必須是一數組.

這是比較容易的部分.現在我們必須創造一ActiveX組件,用來處理提交的表單.打開vb6,選擇一ActiveX項目(參閱步驟1:)

步驟1:創造一ActiveX dll項目

首先,先添加一個引用,在菜單條上選定添加引用項,選中Active Server Pages Object library.(參閱步驟2).

步驟2:工程引用

通過這個庫我們能使用asp的request的請求對象.為保證能使用,要用如下代碼:

Option Explicit

Private MyScriptingContext As ScriptingContextPrivate MyRequest As RequestPrivate MyResponse As Request

Public Sub OnStartPage(PassedScriptingContext As ScriptingContext)

Set MyScriptingContext = PassedScriptingContext

Set MyRequest = MyScriptingContext.Request

Set MyResponse = MySriptingContext.ResponseEnd Sub

為什么我們需要ASP庫?通過request對象我們能得到由upload.htm傳來的http數據流.在那里為什么有一個"但是"?當我們嘗試讀表單字段名字和相對的值,例如,Request.Form("txtTitle"),但我們就不能讀出余下的發送給我們的原始數據.因此我們使用Request.TotalBytes和Request.BinaryRead讀取發送的數據.

下面是我從Doug Dean得到的代碼:

''''' VARIABLES ''''''''''''''''''''''''''''''

Dim varByteCount

Dim binArray() As Byte

''''' BYTE COUNT OF RAW FORM DATA ''''''''''''

varByteCount = MyRequest.TotalBytes

''''''''''''''''''''''''''''''''''''''''''''''

''''' PLACE RAW DATA INTO BYTE ARRAY '''''''''

ReDim binArray(varByteCount)

binArray = MyRequest.BinaryRead(varByteCount)

Doug Dean將數據放入一個二進制的數組,它當然工作的很好.但是當我到想得到表單的名字和值時,我遇見一個問題,例如,我們想要提交包含5個文本框和一個文件框的HTML表單.提交的文件有100K的大小(=102,400字節)的限制.現在我們收到102,400字節.所有的這些字節將進一個二進制的數組.當我們想要分開時,表單元件名,他們的值,我們通過全部數組的循環.我們必須循環6次,因為我們提交了6個表單元件.它工作的很好,但是性能下降.

因此我們需要找到另一種方法從http header中提取數據.當瀏覽MSDN庫,我發現答案.我們必須使用Unicode!!!與Unicode我們能把數據放進一個vb的variant,它包含字符串.

因此我的代碼看起來像這:

Option Explicit

Private MyScriptingContext As ScriptingContextPrivate MyRequest As RequestPrivate MyResponse As Request

Public Sub OnStartPage(PassedScriptingContext As ScriptingContext)

Set MyScriptingContext = PassedScriptingContext

Set MyRequest = MyScriptingContext.Request

Set MyResponse = MySriptingContext.ResponseEnd Sub

Public Function DoUpload (ByVal lngMaxFileBytes As Long, _

ByVal strUploadPath As String) As Variant

Dim varByteCount As VariantDim varHTTPHeader As Variant

Count total bytes in HTTP-headervarByteCount = MyRequest.TotalBytes

Conversion of bytes to UnicodevarHTTPHeader = StrConv(MyRequest.BinaryRead(varByteCount), vbUnicode)

Write HTTPHeaderMyResponse.Write varHTTPHeader

Function End

現在讓我們測試這些代碼的.為這測試我使用用了一個.txt文件"warp11.txt"那包含的下面一句話:"Warp11 builds state-of-the-art applications at the speed of light."

我們提交的表單看起來像這:

這是上傳組件寫入我們的瀏覽器的內容:

-----------------------------7cf28c330254 Content-Disposition: form-data; name="txtAuthor" Sander Duivestein -----------------------------7cf28c330254 Content-Disposition: form-data; name="txtFileName"; filename="C:DownloadWarp11.txt" Content-Type: text/plain Warp11 builds state-of-the-art applications at the speed of light. -----------------------------7cf28c330254

正如你所見的,這僅僅是一字符串,我們能識別這個字符串.當一HTML form通過multipart/form-data MME提交,表單數據被分成幾部分.表單數據的每部分是由分界符分開:"-----------------------------7cf28c330254".通過這個分界符我們能有一串不同的字符串.在上傳應用程序中,我們使用這個分界符劃分表單數據,因此我們把這界線字符串放在變量varDelimeter.我們增加下列代碼執行這個功能:

Dim varDelimeter As VariantvarDelimeter = LeftB(varHTTPHeader, 76)

首先,我們想要知道的上傳了多少個表單元件.因此我們必須做一計數器:

Dim intFormFieldCounter As Integer

Count formfieldsintFormFieldCounter = Len(varHTTPHeader) - Len(Replace(varHTTPHeader, "; name=", Mid("; name=", 2)))

當我們知道表單元件的數目時,我們能通過對varHTTPHeader進行循環查找,然后我們能分別得到列表單元件的名字和他們的值.當我們查找某一表單域名稱和值時,我們想要這些保存這些.存儲這些值,我們簡單地創造一個兩維的數組:

Dim intFormFieldCounter As Integer

Count formfieldsintFormFieldCounter = Len(varHTTPHeader) - Len(Replace(varHTTPHeader, "; name=", Mid("; name=", 2)))

其次,我們想要返回這些值到upload.asp文件.這就是為什么我們使用數組變體型的類型.Variant是ASP能理解的唯一的數組類型.現在列出表單元件和他們的名字.首先,我們創造一循環:

Begin parsing formfield names and valuesFor i = 0 To intFormFieldCounter - 1

然后我們決定第一表單元件將開始的位置:

Determine where FormFieldName startslngFormFieldNameStart = InStrB(lngFormFieldNameStart + 1, varHTTPHeader, "; name=" & Chr(34))

我們現在找到表單元件結束的地方:

Determine where FormFieldName endslngFormFieldNameEnd = InStrB(lngFormFieldNameStart + _Len(StrConv("; name=" & Chr(34), vbUnicode)), varHTTPHeader, Chr(34)) _+ Len(StrConv(Chr(34), vbUnicode))

如果我們有表單元件開始和結束的位置,我們能過濾出表單元件的名稱:

Filter FormFieldNamestrFormFieldName = MidB(varHTTPHeader, lngFormFieldNameStart, lngFormFieldNameEnd - lngFormFieldNameStart)

Remove "; name=" from stringstrFormFieldName = Replace(strFormFieldName, "; name=", vbNullString)

remove quotes from stringstrFormFieldName = Replace(strFormFieldName, Chr(34), vbNullString)

在表單元件名字后面有一個";",通過它,我們就能找到它的類型.如果是這樣,我們就能處理文件,不同的是我們正在處理一文本字段.因此建立一個IF THEN判斷.

Check for fileIf MidB(varHTTPHeader, lngFormFieldNameEnd, 2) = ";" Then

當看我們的HEADER,我們能發現正準備進行的循環的條件是False.這意味著我們正在處理文本字段.現在就能找到我們的表單元件對應的值了.首先我們必須找到表單元件的值開始的地方:

Else

Determine where formfieldvalue startslngFormFieldValueStart = lngFormFieldNameEnd

第二,和以前一樣,我們必須發現我們的表單域值結束的地方:

Determine where formfieldvalue endslngFormFieldValueEnd = InStrB(lngFormFieldValueStart, varHTTPHeader, varDelimeter)

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗