上傳|無組件 無組件上傳一直是困擾大家的一個問題。其實原理很簡單,核心就是分析字串。但是,實際操作時,卻困難重重。其中的關鍵問題還是大家往往對原理的剖析不夠深入,或者是因為過程過於繁瑣,導致bug不斷。一直以來,都想做一個完善的例子,只不過想想就頭痛,加上沒時間(借口,呵呵 ),所以沒有付諸行動。
今天就咬咬牙,給大家提供一個完整的無組件上傳的例子。因為本人耐性不好,所以咱們一點一點來,分幾天完成。未來的幾天,我會天天更新這個文檔,這個過程也是大家學習和提高的過程。
(完整的源碼和樣本,可以在這裡找到:http://www.2yup.com/asp/attach/A0000006.zip)
==============================================================
第一天:認識我們的解剖對象——資料
上傳檔案時,首先要知道我們得到的是什麼。下面是一個上傳檔案的表單,我們就從他開始。
<form action="doupload.asp" method=post enctype="multipart/form-data">
file1說明:<input type=text name=file1_desc>
file1<input type=file name=file1><br>
file2說明:<input type=text name=file2_desc>
file2<input type=file name=file2><br>
<input type=submit name=upload value=upload>
</form>
表單中enctype="multipart/form-data"的意思,是設定表單的MIME編碼。預設情況,這個編碼格式是application/x-www-form-urlencoded,不能用於檔案上傳;只有使用了multipart/form-data,才能完整的傳遞檔案資料,進行下面的操作(有興趣的朋友,可以自己試試看兩者的異同。方法很簡單,就是把這一句去掉)。現在,我們在表單中分別填入資料:
file1的說明 D:\我的 圖片\BACK046.GIF
file2的說明 D:\我的 圖片\BACK293.GIF
這裡用了中英文、空格混排。目的是讓例子更有一般性。我選的這兩個圖片分別是54和62位元組。大圖片的原理完全一樣,不過小圖片做例子更合適些,原理容易展現。
為了看到我們得到的資料,在doupload.asp裡,有這幾行代碼:
<%
formsize=request.totalbytes
formdata=request.binaryread(formsize)
response.BinaryWrite(formdata)
%>
很簡單,作用就是打出來傳過來的所有資料。如果不熟悉,你可以先研究一下request和response對象的這兩個方法。
提交表單,我們在ie裡面查看html源,得到:
-----------------------------7d22131090458
Content-Disposition: form-data; name="file1_desc"
file1μ??μ?÷
-----------------------------7d22131090458
Content-Disposition: form-data; name="file1"; filename="D:\?òμ? í???\BACK046.GIF"
Content-Type: image/gif
GIF89a‘ì?f?f3?ì???ì!ù,@?.á?o ;
-----------------------------7d22131090458
Content-Disposition: form-data; name="file2_desc"
file2μ??μ?÷
-----------------------------7d22131090458
Content-Disposition: form-data; name="file2"; filename="D:\?òμ? í???\BACK293.GIF"
Content-Type: image/gif
GIF89a(‘???YYYììì!ù,(@L€?j(·"j?N(34ˉ;
-----------------------------7d22131090458
Content-Disposition: form-data; name="upload"
upload
-----------------------------7d22131090458--
不用懷疑,這就是你從上一個“簡單”表單傳過來的東西。現在想想看,怎麼對付這一堆東西?是不是看上去有規律,又不知道從何下手?明天,咱們就分析一下這堆“圖片”,看看怎麼分離出我們要的內容。
==============================================================
第二天:分拆初步
睡了個好覺,大家腦子清醒多了吧?今天中午吃的火鍋,阿森納vs.鐵哥也沒看完,現在一腦子大油。。。
OK,咱們繼續研究這個枯燥的問題。首先,要找出規律。看上去似乎很簡單,就是用
-----------------------------7d22131090458
做分隔,這樣,每一個文本單元裡,都是
Content-Disposition: form-data; name="表單域的名字";
表單域的內容
而每一個檔案單元裡,都是
Content-Disposition: form-data; name="表單域的名字"; filename="檔案全路徑"
Content-Type: 檔案類型
檔案的二進位內容
那麼,是不是直接用
split(formdata,"-----------------------------7d22131090458")
就可以得到各個單元了呢?答案是否定的。首先,formdata不是字串而是二進位串,不能用split的方法;其次,這裡的7d22131090458並不固定,每次都會有變化,並不適合做分隔字元。所以,應該用一個更保險的辦法。想到沒?很簡單——就用formdata的第一行做分隔字元。只要用instrb函數得到分行符號的位置,然後用leftb或midb函數截取資料就行了。我們動手試試:
<%
' 二進位的斷行符號<return>
bncrlf=chrB(13) & chrB(10)
' 得到formdata
formsize=request.totalbytes
formdata=request.binaryread(formsize)
' 得到分隔字元
divider=leftB(formdata,clng(instrb(formdata,bncrlf))-1)
' 看看對不對?
response.BinaryWrite(divider)
%>
運行。。。成功了!得到了需要的divider。注意,這裡的字串函數都是針對位元據操作的,所以,用的是他們的二進位版,加了“b”(binary的首字母)——instrb,leftb(以後可能還出現rightb,midb,lenb。。等等)。畢竟,formdata是用“binaryread()”得到的嘛。好了,有的分隔字元,就可以得到資料了。我們從簡單的開始,先拿第一個單元出來看看,目標是得到表單網域名稱稱和資料。
<%
' 這是斷行符號<return>
bncrlf=chrB(13) & chrB(10)
' 得到資料
formsize=request.totalbytes
formdata=request.binaryread(formsize)
' 得到divider,分隔字元
divider=leftB(formdata,clng(instrb(formdata,bncrlf))-1)
' 起始位置
startpos = instrb(formdata,divider)+lenb(divider)+lenb(bncrlf)
' 終止位置,從起始位置開始到下一個divider
endpos = instrb(startpos, formdata, divider)-lenb(bncrlf)
part1 = midb(formdata, startpos, endpos-startpos)
response.BinaryWrite(part1)
%>
這一段有注釋,相信大家沒問題。如果對這些函數不瞭解,可以到http://www.2yup.com/asp/referrence/index.asp下載msdn參考看看vbscript的函數用法,對提高水平有很大協助。
這時候得到的結果可以通過查看產生的html源的方式看到:
Content-Disposition: form-data; name="file1_desc"
file1的說明