Introduction
Browser-based (HTTP) file uploading is a great way to transfer arbitrary files
from a client machine to the Web server which adds another dimension to Web-based
applications. However, to enable this feature the client form should be submitted
using "multipart/form-data" encoding.
Unfortunately, the ASP Request.Form
object cannot be used with this
encoding type (currently). For this reason, many solutions have been provided by
third party components to solve this problem. However, most of these third
party components suffer from one or more of the following problems:
- Discarding other important form data which are not related to the uploaded file.
- No support for multiple file uploading.
- Inconsistent interface to the existing Request.Form interface.
- No support for chunk data reading from the uploaded file (helpful on uploading a large.
file into a BLOB field in a database using
AppendChunk
in an ADO Recordset
object).
For these reasons, I have developed a COM object that users can use instead of
Request.Form
in case of a "multipart/form-data" encoding.
While developing this COM object, I have tried to avoid falling into any of the
previous mentioned problems. However, the solution that I am providing will not
totally replace Request.Form
, rather it will be a complementary
solution that users can use incase of a "multipart/form-data"
encoding as I mentioned earlier. Users can still use Request.Form
for other encoding types, however.
What is multipart/form-data?
This "multipart/form-data" type of encoding is described in RFC1867 which describes how
file uploading should be implemented over HTTP protocol. To enable file uploading the form
enctype should be set to
multipart/form-data
and the method should be set to
post
.
Then the input tag should be of type
file
.
For the previous form here is the required code
<form method=post action=upload.asp enctype="multipart/form-data">
<input name=name value="Al-Mutairi, Fayez">
<input name=email value="fayezmm@yahoo.com">
<input name=file type=file>
<input name=submit type=submit value=Submit>
</form>
When the user clicks the submit button the web server will receive the following:
-----------------------------7d1f5a80420
Content-Disposition: form-data; name="name"
Al-Mutairi, Fayez
-----------------------------7d1f5a80420
Content-Disposition: form-data; name="email"
fayezmm@yahoo.com
-----------------------------7d1f5a80420
Content-Disposition: form-data; name="file"; filename="C:\folder_icon.gif"
Content-Type: image/gif
GIF89a2 2 �� ���������ff�UUUDDD33f""" , 2 2 @
��I��8�ͻ�H �" ��,�|]H�49 7�!� Գ[NG� ��Cq�l:��S�'@��fB�<��v
���
φC$
�+zN���n$u�/z-Vvc@*<,{bdd UX��lCb=?�#f|j�4fq���=>fo��������N
G���<_z�2�T����\R_-�����+�s��͊�Mю]*g֛5���Am����k�/�h���u�[���npʅ�"
�(���i�/ ��*�/ ;
-----------------------------7d1f5a80420
Content-Disposition: form-data; name="submit"
Submit
-----------------------------7d1f5a80420--
At this time when upload.asp started it cannot access the form data using Request.Form
So it should use a third party component for help. The component will read the previous request, parse it
and build a collection of items that can be accessed in a similar fashion to accessing Request.Form
items.
How To Use the Component
Let us build upload.asp using our MyRequest.Form
component
<%@ LANGUAGE="JScript%">
<%
var form = Server.CreateObject("MyRequest.Form");
form.Init();
Response.Write("Name =" + form("name"));
Response.Write("Email =" + form("email"));
var file = form.Item("file").Item(1);
Response.Write("FileName =" + file.FileName);
Response.Write("FileExt =" + file.FileExt);
Response.Write("FilePath =" + file.FilePath);
Response.Write("MimeType =" + file.ContentType);
Response.Write("FileSize =" + file.TotalBytes);
// ** To save into a file use Write method of the ADO Stream Object
var fileStream = Server.CreateObject("ADODB.Stream");
fileStream.Open();
fileStream.Type = adTypeBinary;
fileStream.Write(file.Value);
fileStream.SaveToFile(Server.MapPath("Uploaded Files") + "\\" + file.FileName, adSaveCreateOverWrite);
fileStream.Close();
// ** To save into a database use AppendChunk method of the Field Object of ADO Recordset
var cn = Server.CreateObject("ADODB.Connection");
var rs = Server.CreateObject("ADODB.Recordset");
cn.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("Database.mdb"));
rs.Open("Users", cn, adOpenForwardOnly, adLockOptimistic, adCmdTable);
rs.AddNew();
rs.Fields("id") = 1000;
rs.Fields("name") = form("name").Value;
rs.Fields("email") = form("email").Value;
rs.Fields("FileType") = file.ContentType;
rs.Fields("file").AppendChunk(file.Value);
rs.Update();
rs.Close();
%>
Interfaces
|
Here is the IForm Interface |
Method | Description |
Init(VARIANT varBinary) |
Initialize the form with posted data. varBinary is optional it is =Request.BinaryRead(Request.TotalBytes) |
Item(VARIANT Index, IListItem** ppItem) |
(Default method) Returns the ListItem object with the specified key either as the item name or index. |
Count(long* pVal) |
Number of listitem's objects. |
|
Here is the IListItem Interface |
Method | Description |
Value(VARIANT* pValue) |
(Default method) Item's value. |
Item(long lIndex, IItem** ppItem) |
Returns the Item object with the specified index. |
Count(long* pVal) |
Number of item's objects. |
Name(BSTR* pName) |
Item's name. |
|
Here is theIItem Interface |
Method | Description |
Value(VARIANT* pValue) |
(Default method) Return the value of the item. |
IsFile(BOOL *pVal) |
Return TRUE if the Item object is a file otherwise it returns FALSE. |
FileName(BSTR *pVal) |
The name of the uploaded file. AVALIABLE ONLY if object is a file. |
FilePath(BSTR *pVal) |
The path of the uploaded file. AVALIABLE ONLY if object is a file. |
FileExt(BSTR *pVal) |
The extension of the uploaded file. AVALIABLE ONLY if object is a file. |
ContentType(BSTR *pVal) |
The content-type (MIME TYPE) of the uploaded file. AVALIABLE ONLY if object is a file. |
TotalBytes(long *pVal) |
Size in bytes of the uploaded file. AVALIABLE ONLY if object is a file. |
GetChunk(long offset, long length, VARIANT* pChunk) |
Return a chunk of the file with the specified size and position. AVALIABLE ONLY if object is a file. |
|
Further Help
Additional help is supplied with the demo project zip file which includes documentation !
Special thanks to Xicoloko who wrote http://www.codeproject.com/asp/uploader.asp
which give me a push to also build my own component but this time (Complete).