Have you ever wanted to upload files through a form and thought, 'I'd really like to use ASP, it surely has that capability, but the tutorial I used to learn ASP didn't mention how to do this.'? Have you looked around trying to find simple solutions but didn't want to wade through pages of complex code? Have you balked at paying for premade solutions that are probably overkill for your particular project?
I'd like to walk you through the basic steps right here. Yes, it is fairly easy, and yes you can do it all with only ASP. Is it straight forward? Not exactly, but if you know the basics of manipulating long strings and using the scripting.fileSystemObject then you can do it.
NoteMuch of this code has been adapted from an article from visualBuilder.com which uploads and displays files. I have made the code more linear and added the subroutine which saves the file.
Step 1: Set upFirst there are two things you need to get ready before you actually work on the upload. You need a form and you need a folder. By 'folder' I mean you need a folder for which the anonymous web user has permission to save files. I suggest this be a sub-folder off of your main web directory and that you not give IIS permission to execute scripts from this folder (to help prevent malicious code uploads). In my example I am using a folder called 'temp' right off of my root web directory.
By 'form' you may think I am being overly obvious, but there are actually a couple changes you may need to make to your basic form in order to accept file uploads. The first is a change in your form tag:
- <form
- action='upload.asp' method='post' enctype='multipart/form-data'>
Notice the 'enctype' attribute. If you don't have this attribute set to 'multipart/form-data' then only the name of the file will be sent to the handler, in my case named 'upload.asp'. Then of course you need an input of type='file' to accept the upload:
- <input type='file' name='myFileToUpload' accept='image/*'>
Notice the optional 'accept' attribute which you may use to filter out unacceptable file types. I have set this to accept only files with image MIME-types. This can of course be expanded or omitted completely. finish off your form in any other way you want, then continue on to the next step.
Step 2: Opening binary data posted through your formUnlike regular form inputs with which you have likely worked in the past, files are sent as binary data and can't be manipulated exactly as a string. Also, different browsers send these files in slightly different ways, so it is probably easiest to open up all of the data posted and search through it to find how the different inputs are separated, then try to figure out which is the file. Notice that as you work with binary data, you use functions that look a lot like string manipulation functions except they all end with the letter 'B'. They work just the same, but they are meant to handle binary data. Try this:
- <%
- Dim posi, allData, delimiter, newLineB
- 'put the whole form posted into 'allData'
- allData = request.BinaryRead(Request.TotalBytes)
- 'find the first new line character in allData
- newLineB = chrB(13) & chrB(10)
- posi = instrB(1, allData, newLineB)
- 'find the string which separates the different inputs
- delimiter = midB(allData, 1, posi-1)
- 'remove first delimiter and add a new line character to the end
- allData = midB(allData, posi + 2, lenB(allData) - lenB(delimiter) - 2 - 4)
- allData = allData & newLineB %>
Step 3: Find the file data:What you now have is a variable named 'delimiter' which holds the separator the browser used to separate different form inputs (When I tested this, I used firefox and I wrote this variable after translating it to text. It turned out to be a long series of dashes followed by a 13-digit number. I have no idea what it means) and one called 'allData' which has all of the rest of the data posted to the handler. If you were to translate this data to a string and write it to the screen it would look something like this:
- Content-Disposition: form-data; name='myTextInput'
- hello world
- -----------------------------4564239462453
- Content-Disposition: form-data; name='myFileToUpload'; filename='pic.jpg'
- Content-Type: image/jpeg
- *** a whole bunch of nonsense characters representing all the binary data of the file ***
- -----------------------------4564239462453
- Content-Disposition: form-data; name='submit'
- submit
- -----------------------------4564239462453--
So, how do I look through this? First notice that the first line of each input is the content disposition. this includes the file name, so don't throw it away. The second line lists the content type, but it is blank unless this input is a file. So I'm going to scroll through the inputs and discard them unless this second line has a content type. I'm going to use one function which converts binary data to the equivalent ascii characters, and a subroutine which saves the file.
- <!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'
- 'http://www.w3.org/TR/html4/loose.dtd'>
- <HTML><head><title>asp uploader</title></head><body>
- <%
- 'find the file input, discard all others
- dim lstart, lfinish, disposition, fileType, content
- do while lenB(allData) > 0 'we're going to whittle allData down to nothing
- lstart = 1
- lfinish = instrB(1, allData, newLineB)
- disposition = converter(midB(allData, lstart, lfinish - lstart))
- lstart = lfinish + 2
- If chr(ascB(midB(allData, lstart, 1))) = 'C' then 'this input is a file
- lfinish = instrB(lstart, allData, newLineB & newLineB)
- 'search for 2 new line characters, meaning the end of the
- 'content-type, saves it as fileType
- fileType = trim(converter(midB(allData, lstart, lfinish - lstart)))
- 'set the rest of this input as 'content'
- posi = instrB(allData, newLineB & delimiter & newLineB)
- content = midB(allData, lfinish + 4, posi-lfinish-4)
- 'display data for the file
- response.write '<b>Content Disposition</b><br>' & vbNewLine
- response.write disposition
- response.write '<br>' & vbNewLine
- response.write '<b>Content Type</b><br>' & vbNewline
- response.write fileType
- response.write '<br>' & vbNewLine
- response.write '<b>Content</b><br>'
- 'save file AND display it as either an <img> or <textarea>
- saveFile content, disposition, fileType
- Response.Write '<br>'
- Response.Write '<br>'& vbNewLine
- End If
- 'find the next delimiter in order to cut the first input from allData
- posi = instrB(1, allData, newLineB & delimiter & newLineB)
- allData = midB(allData, posi + 2 + lenB(delimiter) + 2)
- Loop
- Function converter(toConvert)
- Dim output
- Dim x
- x = 1
- output = '
- 'convert one character at a time to Ascii and add it to the output
- do while x <= lenB(toConvert)
- output = output & chr(ascB(midB(toConvert, x, 1)))
- x = x + 1
- loop
- converter = output
- end function
- sub saveFile(content, disp, typ)
- dim objFSO, objTXT, path, fileName
- 'build the path to save the file
- path = request.serverVariables('appl_physical_path') & 'temp'
- 'sometimes the filename has ' which affects how I save it
- if instr(disp, ') > 0 then
- fileName = mid(disp, instrRev(disp, '), len(disp)-instrRev(disp, '))
- else
- fileName = ' & mid(disp, instr(disp, 'filename=')+10, len(disp)-instr(disp, 'filename=')-10)
- end if
- path = path & fileName
- 'save file with normal FSO and textStream methods
- set objFSO = server.createObject('scripting.fileSystemObject')
- set objTXT = objFSO.openTextFile (path, 2, True)
- objTXT.write converter(content)
- response.write '<br>(File saved as: ' & path & ')<br>' & vbNewLine
- 'display the file
- if left(typ, 19) = 'Content-Type: image' then 'file is an image
- 'write an image tag to the browser
- response.write '<img src='/temp' & fileName & '>'&vbNewLine
- else 'file isn't an image
- 'write the contents of the file to a textarea in the browser
- response.write '<textarea rows='10' cols='50' editable='false'>'
- response.binaryWrite content
- response.write '</textarea>' & vbNewline
- end if
- end sub
- %>
- </body>
Notice that I convert the content of the file to ascii characters and use a textstream to save it. Yes this does work for binary files. I tested it with several image files. There is a separate object called an ADO.STREAM which is supposed to be used for moving around binary files, but I couldn't get it to work for this application, and since the plain ol' textstream works OK, I will leave it like this.
Please give me any comments. I look forward to any feedback.
Jared