I am trying to upload a csv file then read it line by line and pass it to my Database. I have a issue on file upload I could see that whenever I upload a file an extra number gets added to a column in my csv and due to this my code fails. I could see that the file gets saved in the expected location and when I opened it I could see an extra number which I never added. What could be the reason for this?
Here is my code for uploading the CSV file and reading it and using a loop I'm iterating the values in the csv file and storing the values in my variables which is then passed to a method to store in DB.
<HTML>
<HEAD>
<!--#include file="clsUpload.asp"-->
<!-- #include file = "Bin/includes/GenFunctions.asp" -->
<!-- #include file = "Bin/includes/HeaderFooter.asp" -->
</HEAD>
<title>CMTL Entry File Upload</title>
<%showHeader%>
<BODY text="#000000" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<FORM ACTION = "clsUploadtest.asp" ENCTYPE="multipart/form-data" METHOD="POST">
File Name: <INPUT TYPE=FILE NAME="txtFile"><P>
<INPUT TYPE = "SUBMIT" NAME="cmdSubmit" VALUE="SUBMIT">
</FORM><P>
<%
'Declare the form variables
Dim intRecordId
Dim strRecordId
Dim strAction
Dim strInputDate
Dim strPayer
Dim strAmount
Dim strTransType
Dim strPayee
Dim strAddRemarks
Dim strComments
Dim strAccNo
Dim strPolicyNo
Dim strBranchConfDate
Dim strConfBy
Dim strSheetUpdDate
Dim strMailUpdDate
Dim strUploadTime
Dim strUploadId
Dim strStatus
Dim strLastMdfdDate
Dim strLastMdfdId
Dim lineData
Dim code
Dim name
Dim mail
Dim id
Dim price
Dim amount
Dim MyArray
Dim i
i = 0
set obj = Server.CreateObject("AC_FI.mMTL")
If err.number <> 0 Then
RaiseGenError objCMTL,"Error while creating the object "
Response.End
end if
set o = new clsUpload
if o.Exists("cmdSubmit") then
'get client file name without path
sFileSplit = split(o.FileNameOf("txtFile"), "\")
sFile = sFileSplit(Ubound(sFileSplit))
o.FileInputName = "txtFile"
o.FileFullPath = Server.MapPath(".") & "\entry\" & sFile
o.save
if o.Error = "" then
response.write "Success. File saved to " & o.FileFullPath
else
response.write "Failed due to the following error: " & o.Error
end if
set fso = Server.CreateObject("Scripting.FileSystemObject")
set fs = fso.OpenTextFile(Server.MapPath("entry/" & sFile), 1, False)
Do While Not fs.AtEndOfStream
lineData = fs.ReadLine
'lineData = replace(lineData,chr(13),",")
'lineData = replace(lineData,chr(34),"")
MyArray = Split(lineData , ",")
strRecordId=MyArray(0)
strInputDate=MyArray(1)
strPayer=MyArray(2)
strAmount=MyArray(3)
strTransType=MyArray(4)
strPayee=MyArray(5)
strAddRemarks=MyArray(6)
strComments=MyArray(7)
strAccNo=MyArray(8)
strPolicyNo=MyArray(9)
strBranchConfDate=MyArray(10)
strConfBy=MyArray(11)
strSheetUpdDate=MyArray(12)
strMailUpdDate=MyArray(13)
strUploadTime=MyArray(14)
strUploadId=MyArray(15)
strStatus=MyArray(16)
strRecordId = convertNullString(strRecordId)
strAction = convertNullString(strAction)
strInputDate = convertNullDate(strInputDate)
strPayer = convertNullString(strPayer)
strAmount = convertNullString(strAmount)
strTransType = convertNullString(strTransType)
strPayee = convertNullString(strPayee)
strAddRemarks = convertNullString(strAddRemarks)
strComments = convertNullString(strComments)
strAccNo = convertNullString(strAccNo)
strPolicyNo = convertNullString(strPolicyNo)
strBranchConfDate = convertNullDate(strBranchConfDate)
strConfBy = convertNullString(strConfBy)
strSheetUpdDate = convertNullDate(strSheetUpdDate)
strMailUpdDate = convertNullDate(strMailUpdDate)
strUploadTime = convertNullDate(strUploadTime)
strUploadId = convertNullString(strUploadId)
strStatus = convertNullString(strStatus)
intRecordId = obj.InsertData(strInputDate,strPayer,strAmount,strTransType,strPayee,strAddRemarks,_
strComments,strAccNo,strPolicyNo,strBranchConfDate,strConfBy,strSheetUpdDate,_
strMailUpdDate,strUploadTime,strUploadId,strStatus, pErrorcode)
i=i+1
Loop
fs.close()
set fs = nothing
set fso = nothing
end if
set o = nothing
%>
<%showFooter%>
</BODY>
</HTML>
this is the clsupload.asp file that I have used for file upload
<%
' ------------------------------------------------------------------------------
' Container of Field Properties
Class clsField
Public FileName
Public ContentType
Public Value
Public FieldName
Public Length
Public BinaryData
End Class
' ------------------------------------------------------------------------------
Class clsUpload
' ------------------------------------------------------------------------------
Private nFieldCount
Private oFields()
Private psFileFullPath
Private psError
Private psFileInputName
' ------------------------------------------------------------------------------
Public Property Get Count()
Count = nFieldCount
End Property
' ------------------------------------------------------------------------------
Public Default Property Get Field(ByRef asFieldName)
Dim lnLength
Dim lnIndex
lnLength = UBound(oFields)
If IsNumeric(asFieldName) Then
If lnLength >= asFieldName And asFieldName > -1 Then
Set Field = oFields(asFieldName)
Else
Set Field = New clsField
End If
Else
For lnIndex = 0 To lnLength
If LCase(oFields(lnIndex).FieldName) = LCase(asFieldName) Then
Set Field = oFields(lnIndex)
Exit Property
End If
Next
Set Field = New clsField
End If
End Property
' ------------------------------------------------------------------------------
Public Function Exists(ByRef avKeyIndex)
Exists = Not IndexOf(avKeyIndex) = -1
End Function
' ------------------------------------------------------------------------------
Public Property Get ValueOf(ByRef avKeyIndex)
Dim lnIndex
lnIndex = IndexOf(avKeyIndex)
if lnIndex = -1 Then Exit Property
ValueOf = oFields(lnIndex).Value
End Property
' ------------------------------------------------------------------------------
Public Property Get FileNameOf(ByRef avKeyIndex)
Dim lnIndex
lnIndex = IndexOf(avKeyIndex)
if lnIndex = -1 Then Exit Property
FileNameOf = oFields(lnIndex).FileName
End Property
' ------------------------------------------------------------------------------
Public Property Get LengthOf(ByRef avKeyIndex)
Dim lnIndex
lnIndex = IndexOf(avKeyIndex)
if lnIndex = -1 Then Exit Property
LengthOf = oFields(lnIndex).Length
End Property
' ------------------------------------------------------------------------------
Public Property Get BinaryDataOf(ByRef avKeyIndex)
Dim lnIndex
lnIndex = IndexOf(avKeyIndex)
if lnIndex = -1 Then Exit Property
BinaryDataOf = oFields(lnIndex).BinaryData
End Property
' ------------------------------------------------------------------------------
Private Function IndexOf(ByVal avKeyIndex)
Dim lnIndex
If avKeyIndex = "" Then
IndexOf = -1
ElseIf IsNumeric(avKeyIndex) Then
avKeyIndex = CLng(avKeyIndex)
If nFieldCount > avKeyIndex And avKeyIndex > -1 Then
IndexOf = avKeyIndex
Else
IndexOf = -1
End If
Else
For lnIndex = 0 To nFieldCount - 1
If LCase(oFields(lnIndex).FieldName) = LCase(avKeyIndex) Then
IndexOf = lnIndex
Exit Function
End If
Next
IndexOf = -1
End If
End Function
' ------------------------------------------------------------------------------
Public Property Let FileFullPath(sValue)
psFileFullPath = sValue
End Property
'___________________________________________________________________________________
Public Property Get FileFullPath()
FileFullPath = psFileFullPath
End Property
' ------------------------------------------------------------------------------
Public Property Let FileInputName(sValue)
psFileInputName = sValue
End Property
' -------------------- ----------------------------------------------------------
Public Function Save()
if psFileFullPath <> "" and psFileInputName <> "" then
'Save to connectionless client side recordset, write to stream,
'and persist stream.
'would think you should be able to write directly to
'stream without recordset, but I could not get that to work
On error resume next
binData = o.BinaryDataOf(psFileInputName)
set rs = server.createobject("ADODB.RECORDSET")
rs.fields.append "FileName", 205, LenB(binData)
rs.open
rs.addnew
rs.fields(0).AppendChunk binData
if err.number = 0 then
set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Open
objStream.Write rs.fields("FileName").value
objStream.SaveToFile psFileFullPath, 2
objStream.close
set objStream = Nothing
ENd if
rs.close
set rs = nothing
psError = Err.Description
else
psError = "One or more required properties (FileFullPath and/or FileInputName) not set"
End If
End Function
Public Property Get Error()
Error = psError
End Property
' ------------------------------------------------------------------------------
Public Property Get ContentTypeOf(ByRef avKeyIndex)
Dim lnIndex
lnIndex = IndexOf(avKeyIndex)
if lnIndex = -1 Then Exit Property
ContentTypeOf = oFields(lnIndex).ContentType
End Property
' ------------------------------------------------------------------------------
Private Sub Class_Terminate()
Dim lnIndex
For lnIndex = 0 To nFieldCount - 1
Set oFields(0) = Nothing
Next
End Sub
' ------------------------------------------------------------------------------
Private Sub Class_Initialize()
Dim lnBytes ' Bytes received from the client
Dim lnByteCount ' Number of bytes received
Dim lnStartPosition ' Position at which content begins
Dim lnEndPosition ' Position at which content ends
Dim loDic ' Contains properties of each
' specific field
' Local dictionary object(s)
' to be appended to class-scope
' dictionary object.
Dim lnBoundaryBytes ' Bytes contained within the current boundary
Dim lnBoundaryStart ' Position at which the current boundary begins
' within the lnBytes binary data.
Dim lnBoundaryEnd ' Position at which the current boundary ends
' within the lnBytes binary data.
Dim lnDispositionPosition
Dim lsFieldName ' Name of the current field being parsed from
' Binary Data
Dim lsFileName ' Name of the file within the current boundary
Dim lnFileNamePosition ' Location of file name within current boundary
Dim loField ' clsField Object
Dim lsValue ' Value of the current field
Dim lsContentType ' ContentType of the binary file (MIME Type)
' Initialize Fields
nFieldCount = 0
ReDim oFields(-1)
' Read the bytes (binary data) into memory
lnByteCount = Request.TotalBytes
lnBytes = Request.BinaryRead(lnByteCount)
'Get the lnBoundaryBytes
lnStartPosition = 1
lnEndPosition = InstrB(lnStartPosition, lnBytes, CStrB(vbCr))
If lnEndPosition >= lnStartPosition Then
lnBoundaryBytes = MidB(lnBytes, lnStartPosition, lnEndPosition - lnStartPosition)
End If
lnBoundaryStart = InstrB(1, lnBytes, lnBoundaryBytes)
' Loop until the BoundaryBytes begin with "--"
Do Until (lnBoundaryStart = InstrB(lnBytes, lnBoundaryBytes & CStrB("--")))
' All data within this boundary is stored within a local dictionary
' to be appended to the class-scope dictionary.
ReDim Preserve oFields(nFieldCount)
nFieldCount = nFieldCount + 1
Set loField = New clsField
lnDispositionPosition = InstrB(lnBoundaryStart, lnBytes, CStrB("Content-Disposition"))
' Get an object name
lnStartPosition = InstrB(lnDispositionPosition, lnBytes, CStrB("name=")) + 6
lnEndPosition = InstrB(lnStartPosition, lnBytes, CStrB(""""))
lsFieldName = CStrU(MidB(lnBytes, lnStartPosition, lnEndPosition - lnStartPosition))
loField.FieldName = lsFieldName
' Get the location fo the file name.
lnFileNamePosition = InstrB(lnBoundaryStart, lnBytes, CStrB("filename="))
lnBoundaryEnd = InstrB(lnEndPosition, lnBytes, lnBoundaryBytes)
'Test if object is a file
If Not lnFileNamePosition = 0 And lnFileNamePosition < lnBoundaryEnd Then
' Parse Filename
lnStartPosition = lnFileNamePosition + 10
lnEndPosition = InstrB(lnStartPosition, lnBytes, CStrB(""""))
lsFileName = CStrU(MidB(lnBytes,lnStartPosition,lnEndPosition-lnStartPosition))
loField.FileName = lsFileName
' Parse Content-Type
lnStartPosition = InstrB(lnEndPosition,lnBytes,CStrB("Content-Type:")) + 14
lnEndPosition = InstrB(lnStartPosition,lnBytes,CStrB(vbCr))
lsContentType = CStrU(MidB(lnBytes,lnStartPosition,lnEndPosition-lnStartPosition))
loField.ContentType = lsContentType
' Parse Content
lnStartPosition = lnEndPosition + 4
lnEndPosition = InstrB(lnStartPosition,lnBytes,lnBoundaryBytes)-2
lsValue = MidB(lnBytes,lnStartPosition,lnEndPosition-lnStartPosition)
loField.BinaryData = lsValue & CStrB(vbNull)
loField.Length = LenB(lsValue)
Else
' Parse Content
lnStartPosition = InstrB(lnDispositionPosition, lnBytes, CStrB(vbCr)) + 4
lnEndPosition = InstrB(lnStartPosition, lnBytes, lnBoundaryBytes) - 2
lsValue = CStrU(MidB(lnBytes,lnStartPosition,lnEndPosition-lnStartPosition))
loField.Value = lsValue
loField.Length = Len(lsValue)
End If
Set oFields(UBound(oFields)) = loField
'Loop to next object
lnBoundaryStart = InstrB(lnBoundaryStart + LenB(lnBoundaryBytes), lnBytes, lnBoundaryBytes)
Set loField = Nothing
Loop
End Sub
' ------------------------------------------------------------------------------
Private Function CStrU(ByRef psByteString)
Dim lnLength
Dim lnPosition
lnLength = LenB(psByteString)
For lnPosition = 1 To lnLength
CStrU = CStrU & Chr(AscB(MidB(psByteString, lnPosition, 1)))
Next
End Function
' ------------------------------------------------------------------------------
Private Function CStrB(ByRef psUnicodeString)
Dim lnLength
Dim lnPosition
lnLength = Len(psUnicodeString)
For lnPosition = 1 To lnLength
CStrB = CStrB & ChrB(AscB(Mid(psUnicodeString, lnPosition, 1)))
Next
End Function
' ------------------------------------------------------------------------------
End Class
' ------------------------------------------------------------------------------
%>
You can see that the file has an extra value added in it and code fails. I have no idea from where this value comes in each time I upload the file. The file in my local machine doesn't have that value. Can anyone help?
I've been stuck on this one for a few days with no progress. Using classic ASP, I need to take an uploaded .JPG file (from html form input type='file') and base64 encode it so that I can send it to a Java web service. The Java web service is simply storing the image (in a SQL image field) in a database. I figured converting to BASE64 was the best way to transfer the parameter in the xml. Here's what I have so far:
HTML:
<label>Upload Picture</label>
<input name="file" id="file" type="file" size=40 /> <br />
ASP:
Dim load
Set load = new Loader
load.initialize
Dim fileData
fileData = load.getFileData("file")
Dim fileName
fileName = LCase(load.getFileName("file"))
Dim fileSize
fileSize = load.getFileSize("file")
Dim objXML
Dim objNode
Dim strB64
Set objXML = Server.CreateObject("MSXML2.DomDocument.3.0")
Set objNode = objXML.createElement("base64")
objNode.dataType = "bin.base64" 'stores binary as base64 string
objNode.nodeTypedValue = fileData 'binary value
strB64 = objNode.Text
LOADER:
the loader is a lot of code (I can copy all of it here if needed). It essentially gets all the bytes from the request and parses them into a dictionary object. Here's how it gets the data:
Class Loader
Private dict
Private Sub Class_Initialize
Set dict = Server.CreateObject("Scripting.Dictionary")
End Sub
Public Sub Initialize
If Request.TotalBytes > 0 Then
Dim binData
binData = Request.BinaryRead(Request.TotalBytes)
getData binData
End If
End Sub
Public Function getFileData(name) '"file"
If dict.Exists(name) Then
getFileData = dict(name).Item("Value")
Else
getFileData = ""
End If
End Function
I can post the sub that parses and stores the binary in a dictionary if needed.
The above code gives this error:
msxml3.dll error '80004005'
Error parsing '????' as bin.base64 datatype.
on this line:
objNode.nodeTypedValue = fileData 'binary value
UPDATE:
Here's where the data is loaded to the dictionary:
Private Sub getData(rawData)
Dim separator
separator = MidB(rawData, 1, InstrB(1, rawData, ChrB(13)) - 1)
Dim lenSeparator
lenSeparator = LenB(separator)
Dim currentPos
currentPos = 1
Dim inStrByte
inStrByte = 1
Dim value, mValue
Dim tempValue
tempValue = ""
While inStrByte > 0
inStrByte = InStrB(currentPos, rawData, separator)
mValue = inStrByte - currentPos
If mValue > 1 Then
value = MidB(rawData, currentPos, mValue)
Dim begPos, endPos, midValue, nValue
Dim intDict
Set intDict = Server.CreateObject("Scripting.Dictionary")
begPos = 1 + InStrB(1, value, ChrB(34))
endPos = InStrB(begPos + 1, value, ChrB(34))
nValue = endPos
Dim nameN
nameN = MidB(value, begPos, endPos - begPos)
Dim nameValue, isValid
isValid = True
If InStrB(1, value, stringToByte("Content-Type")) > 1 Then
begPos = 1 + InStrB(endPos + 1, value, ChrB(34))
endPos = InStrB(begPos + 1, value, ChrB(34))
If endPos = 0 Then
endPos = begPos + 1
isValid = False
End If
midValue = MidB(value, begPos, endPos - begPos)
intDict.Add "FileName", trim(byteToString(midValue))
begPos = 14 + InStrB(endPos + 1, value, stringToByte("Content-Type:"))
endPos = InStrB(begPos, value, ChrB(13))
midValue = MidB(value, begPos, endPos - begPos)
intDict.Add "ContentType", trim(byteToString(midValue))
begPos = endPos + 4
endPos = LenB(value)
nameValue = MidB(value, begPos, ((endPos - begPos) - 1))
Else
nameValue = trim(byteToString(MidB(value, nValue + 5)))
End If
If isValid = True Then
intDict.Add "Value", nameValue
intDict.Add "Name", nameN
dict.Add byteToString(nameN), intDict
End If
End If
currentPos = lenSeparator + inStrByte
Wend
End Sub
Private Function stringToByte(toConv)
Dim tempChar, i
For i = 1 to Len(toConv)
tempChar = Mid(toConv, i, 1)
stringToByte = stringToByte & chrB(AscB(tempChar))
Next
End Function
Private Function byteToString(toConv)
dim i
For i = 1 to LenB(toConv)
byteToString = byteToString & chr(AscB(MidB(toConv,i,1)))
Next
End Function
I finally found something that works! Here's the link:
http://www.motobit.com/tips/detpg_binarytostring/
The issue I was having was that the data from the BinaryRead was multibyte data (which ASP doesn't play well with). MultiByte data must be converted To VT_UI1 | VT_ARRAY in order for the base64 encoding via the Dom Document Object (or nearly any other function - including loading to a stream). This can be achieved using an ADO recordset object as such:
Function MultiByteToBinary(MultiByte)
' 2000 Antonin Foller, http://www.motobit.com
' MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)
' Using recordset
Dim RS, LMultiByte, Binary
Const adLongVarBinary = 205
Set RS = CreateObject("ADODB.Recordset")
LMultiByte = LenB(MultiByte)
If LMultiByte>0 Then
RS.Fields.Append "mBinary", adLongVarBinary, LMultiByte
RS.Open
RS.AddNew
RS("mBinary").AppendChunk MultiByte & ChrB(0)
RS.Update
Binary = RS("mBinary").GetChunk(LMultiByte)
End If
MultiByteToBinary = Binary
End Function
Hopefully this will help someone else as well.
Let ADODB.Stream do your heavy lifting, this assumes you already have saved the file to disk. These are the functions for BASE64 I use, I'm not 100% sure where I originally got them.
private function readBytes(file)
dim inStream
' ADODB stream object used
set inStream = WScript.CreateObject("ADODB.Stream")
' open with no arguments makes the stream an empty container
inStream.Open
inStream.type= TypeBinary
inStream.LoadFromFile(file)
readBytes = inStream.Read()
end function
private function encodeBase64(bytes)
dim DM, EL
Set DM = CreateObject("Microsoft.XMLDOM")
' Create temporary node with Base64 data type
Set EL = DM.createElement("tmp")
EL.DataType = "bin.base64"
' Set bytes, get encoded String
EL.NodeTypedValue = bytes
encodeBase64 = EL.Text
end function
private function decodeBase64(base64)
dim DM, EL
Set DM = CreateObject("Microsoft.XMLDOM")
' Create temporary node with Base64 data type
Set EL = DM.createElement("tmp")
EL.DataType = "bin.base64"
' Set encoded String, get bytes
EL.Text = base64
decodeBase64 = EL.NodeTypedValue
end function
private Sub writeBytes(file, bytes)
Dim binaryStream
Set binaryStream = CreateObject("ADODB.Stream")
binaryStream.Type = adTypeBinary
'Open the stream and write binary data
binaryStream.Open
binaryStream.Write bytes
'Save binary data to disk
binaryStream.SaveToFile file, adSaveCreateOverWrite
End Sub
How to upload files from browser to server running classic ASP and detect, server side, if the files are valid pictures? For valid pictures, how to get their dimensions?
Usually file upload in classic ASP is done by third party components which come with a DLL file and requires registration on the server, sometimes also cost money. Needless to say many hosts won't allow third party components due to security reasons.
There are great many pure ASP upload scripts already, but they only take the file and save to server disk, no image detection whatsoever.
Below is my own script written for the above purpose but of course more answers are always welcome with alternatives or better ways.
Here is a single Class which handles file upload plus image detection. Use case will come below. Save this as-is, preferably as a new file, with .asp extension e.g. ShadowUpload.asp
Note: if you want to allow uploading images larger than 200kb, take a look in the answer to Request.BinaryRead(Request.TotalBytes) throws error for large files. (Failing to do so might result in "Operation not Allowed" error on the BinaryRead line.)
<%
'constants:
Const MAX_UPLOAD_SIZE=1500000 'bytes
Const MSG_NO_DATA="nothing to upload!"
Const MSG_EXCEEDED_MAX_SIZE="you exceeded the maximum upload size!"
Const SU_DEBUG_MODE=False
Class ShadowUpload
Private m_Request
Private m_Files
Private m_Error
Public Property Get GetError
GetError = m_Error
End Property
Public Property Get FileCount
FileCount = m_Files.Count
End Property
Public Function File(index)
Dim keys
keys = m_Files.Keys
Set File = m_Files(keys(index))
End Function
Public Default Property Get Item(strName)
If m_Request.Exists(strName) Then
Item = m_Request(strName)
Else
Item = ""
End If
End Property
Private Sub Class_Initialize
Dim iBytesCount, strBinData
'first of all, get amount of uploaded bytes:
iBytesCount = Request.TotalBytes
WriteDebug("initializing upload, bytes: " & iBytesCount & "<br />")
'abort if nothing there:
If iBytesCount=0 Then
m_Error = MSG_NO_DATA
Exit Sub
End If
'abort if exceeded maximum upload size:
If iBytesCount>MAX_UPLOAD_SIZE Then
m_Error = MSG_EXCEEDED_MAX_SIZE
Exit Sub
End If
'read the binary data:
strBinData = Request.BinaryRead(iBytesCount)
'create private collections:
Set m_Request = Server.CreateObject("Scripting.Dictionary")
Set m_Files = Server.CreateObject("Scripting.Dictionary")
'populate the collection:
Call BuildUpload(strBinData)
End Sub
Private Sub Class_Terminate
Dim fileName
If IsObject(m_Request) Then
m_Request.RemoveAll
Set m_Request = Nothing
End If
If IsObject(m_Files) Then
For Each fileName In m_Files.Keys
Set m_Files(fileName)=Nothing
Next
m_Files.RemoveAll
Set m_Files = Nothing
End If
End Sub
Private Sub BuildUpload(ByVal strBinData)
Dim strBinQuote, strBinCRLF, iValuePos
Dim iPosBegin, iPosEnd, strBoundaryData
Dim strBoundaryEnd, iCurPosition, iBoundaryEndPos
Dim strElementName, strFileName, objFileData
Dim strFileType, strFileData, strElementValue
strBinQuote = AsciiToBinary(chr(34))
strBinCRLF = AsciiToBinary(chr(13))
'find the boundaries
iPosBegin = 1
iPosEnd = InstrB(iPosBegin, strBinData, strBinCRLF)
strBoundaryData = MidB(strBinData, iPosBegin, iPosEnd-iPosBegin)
iCurPosition = InstrB(1, strBinData, strBoundaryData)
strBoundaryEnd = strBoundaryData & AsciiToBinary("--")
iBoundaryEndPos = InstrB(strBinData, strBoundaryEnd)
'read binary data into private collection:
Do until (iCurPosition>=iBoundaryEndPos) Or (iCurPosition=0)
'skip non relevant data...
iPosBegin = InstrB(iCurPosition, strBinData, AsciiToBinary("Content-Disposition"))
iPosBegin = InstrB(iPosBegin, strBinData, AsciiToBinary("name="))
iValuePos = iPosBegin
'read the name of the form element, e.g. "file1", "text1"
iPosBegin = iPosBegin+6
iPosEnd = InstrB(iPosBegin, strBinData, strBinQuote)
strElementName = BinaryToAscii(MidB(strBinData, iPosBegin, iPosEnd-iPosBegin))
'maybe file?
iPosBegin = InstrB(iCurPosition, strBinData, AsciiToBinary("filename="))
iPosEnd = InstrB(iPosEnd, strBinData, strBoundaryData)
If (iPosBegin>0) And (iPosBegin<iPosEnd) Then
'skip non relevant data..
iPosBegin = iPosBegin+10
'read file name:
iPosEnd = InstrB(iPosBegin, strBinData, strBinQuote)
strFileName = BinaryToAscii(MidB(strBinData, iPosBegin, iPosEnd-iPosBegin))
'verify that we got name:
If Len(strFileName)>0 Then
'create file data:
Set objFileData = New FileData
objFileData.FileName = strFileName
'read file type:
iPosBegin = InstrB(iPosEnd, strBinData, AsciiToBinary("Content-Type:"))
iPosBegin = iPosBegin+14
iPosEnd = InstrB(iPosBegin, strBinData, strBinCRLF)
strFileType = BinaryToAscii(MidB(strBinData, iPosBegin, iPosEnd-iPosBegin))
objFileData.ContentType = strFileType
'read file contents:
iPosBegin = iPosEnd+4
iPosEnd = InstrB(iPosBegin, strBinData, strBoundaryData)-2
strFileData = MidB(strBinData, iPosBegin, iPosEnd-iPosBegin)
'check that not empty:
If LenB(strFileData)>0 Then
objFileData.Contents = strFileData
'append to files collection if not empty:
Set m_Files(strFileName) = objFileData
Else
Set objFileData = Nothing
End If
End If
strElementValue = strFileName
Else
'ordinary form value, just read:
iPosBegin = InstrB(iValuePos, strBinData, strBinCRLF)
iPosBegin = iPosBegin+4
iPosEnd = InstrB(iPosBegin, strBinData, strBoundaryData)-2
strElementValue = BinaryToAscii(MidB(strBinData, iPosBegin, iPosEnd-iPosBegin))
End If
'append to request collection
m_Request(strElementName) = strElementValue
'skip to next element:
iCurPosition = InstrB(iCurPosition+LenB(strBoundaryData), strBinData, strBoundaryData)
Loop
End Sub
Private Function WriteDebug(msg)
If SU_DEBUG_MODE Then
Response.Write(msg)
Response.Flush
End If
End Function
Private Function AsciiToBinary(strAscii)
Dim i, char, result
result = ""
For i=1 to Len(strAscii)
char = Mid(strAscii, i, 1)
result = result & chrB(AscB(char))
Next
AsciiToBinary = result
End Function
Private Function BinaryToAscii(strBinary)
Dim i, result
result = ""
For i=1 to LenB(strBinary)
result = result & chr(AscB(MidB(strBinary, i, 1)))
Next
BinaryToAscii = result
End Function
End Class
Class FileData
Private m_fileName
Private m_contentType
Private m_BinaryContents
Private m_AsciiContents
Private m_imageWidth
Private m_imageHeight
Private m_checkImage
Public Property Get FileName
FileName = m_fileName
End Property
Public Property Get ContentType
ContentType = m_contentType
End Property
Public Property Get ImageWidth
If m_checkImage=False Then Call CheckImageDimensions
ImageWidth = m_imageWidth
End Property
Public Property Get ImageHeight
If m_checkImage=False Then Call CheckImageDimensions
ImageHeight = m_imageHeight
End Property
Public Property Let FileName(strName)
Dim arrTemp
arrTemp = Split(strName, "\")
m_fileName = arrTemp(UBound(arrTemp))
End Property
Public Property Let CheckImage(blnCheck)
m_checkImage = blnCheck
End Property
Public Property Let ContentType(strType)
m_contentType = strType
End Property
Public Property Let Contents(strData)
m_BinaryContents = strData
m_AsciiContents = RSBinaryToString(m_BinaryContents)
End Property
Public Property Get Size
Size = LenB(m_BinaryContents)
End Property
Private Sub CheckImageDimensions
Dim width, height, colors
Dim strType
'''If gfxSpex(BinaryToAscii(m_BinaryContents), width, height, colors, strType) = true then
If gfxSpex(m_AsciiContents, width, height, colors, strType) = true then
m_imageWidth = width
m_imageHeight = height
End If
m_checkImage = True
End Sub
Private Sub Class_Initialize
m_imageWidth = -1
m_imageHeight = -1
m_checkImage = False
End Sub
Public Sub SaveToDisk(strFolderPath, ByRef strNewFileName)
Dim strPath, objFSO, objFile
Dim i, time1, time2
Dim objStream, strExtension
strPath = strFolderPath&"\"
If Len(strNewFileName)=0 Then
strPath = strPath & m_fileName
Else
strExtension = GetExtension(strNewFileName)
If Len(strExtension)=0 Then
strNewFileName = strNewFileName & "." & GetExtension(m_fileName)
End If
strPath = strPath & strNewFileName
End If
WriteDebug("save file started...<br />")
time1 = CDbl(Timer)
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(strPath)
objFile.Write(m_AsciiContents)
'''For i=1 to LenB(m_BinaryContents)
''' objFile.Write chr(AscB(MidB(m_BinaryContents, i, 1)))
'''Next
time2 = CDbl(Timer)
WriteDebug("saving file took " & (time2-time1) & " seconds.<br />")
objFile.Close
Set objFile=Nothing
Set objFSO=Nothing
End Sub
Private Function GetExtension(strPath)
Dim arrTemp
arrTemp = Split(strPath, ".")
GetExtension = ""
If UBound(arrTemp)>0 Then
GetExtension = arrTemp(UBound(arrTemp))
End If
End Function
Private Function RSBinaryToString(xBinary)
'Antonin Foller, http://www.motobit.com
'RSBinaryToString converts binary data (VT_UI1 | VT_ARRAY Or MultiByte string)
'to a string (BSTR) using ADO recordset
Dim Binary
'MultiByte data must be converted To VT_UI1 | VT_ARRAY first.
If vartype(xBinary)=8 Then Binary = MultiByteToBinary(xBinary) Else Binary = xBinary
Dim RS, LBinary
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
LBinary = LenB(Binary)
If LBinary>0 Then
RS.Fields.Append "mBinary", adLongVarChar, LBinary
RS.Open
RS.AddNew
RS("mBinary").AppendChunk Binary
RS.Update
RSBinaryToString = RS("mBinary")
Else
RSBinaryToString = ""
End If
End Function
Function MultiByteToBinary(MultiByte)
'© 2000 Antonin Foller, http://www.motobit.com
' MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)
' Using recordset
Dim RS, LMultiByte, Binary
Const adLongVarBinary = 205
Set RS = CreateObject("ADODB.Recordset")
LMultiByte = LenB(MultiByte)
If LMultiByte>0 Then
RS.Fields.Append "mBinary", adLongVarBinary, LMultiByte
RS.Open
RS.AddNew
RS("mBinary").AppendChunk MultiByte & ChrB(0)
RS.Update
Binary = RS("mBinary").GetChunk(LMultiByte)
End If
MultiByteToBinary = Binary
End Function
Private Function WriteDebug(msg)
If SU_DEBUG_MODE Then
Response.Write(msg)
Response.Flush
End If
End Function
Private Function BinaryToAscii(strBinary)
Dim i, result
result = ""
For i=1 to LenB(strBinary)
result = result & chr(AscB(MidB(strBinary, i, 1)))
Next
BinaryToAscii = result
End Function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This routine will attempt to identify any filespec passed :::
'::: as a graphic file (regardless of the extension). This will :::
'::: work with BMP, GIF, JPG and PNG files. :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: Based on ideas presented by David Crowell :::
'::: (credit where due) :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah Copyright *c* MM, Mike Shaffer blah blah :::
'::: bh blah ALL RIGHTS RESERVED WORLDWIDE blah blah :::
'::: blah blah Permission is granted to use this code blah blah :::
'::: blah blah in your projects, as long as this blah blah :::
'::: blah blah copyright notice is included blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This function gets a specified number of bytes from any :::
'::: file, starting at the offset (base 1) :::
'::: :::
'::: Passed: :::
'::: flnm => Filespec of file to read :::
'::: offset => Offset at which to start reading :::
'::: bytes => How many bytes to read :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Private Function GetBytes(flnm, offset, bytes)
Dim startPos
If offset=0 Then
startPos = 1
Else
startPos = offset
End If
if bytes = -1 then ' Get All!
GetBytes = flnm
else
GetBytes = Mid(flnm, startPos, bytes)
end if
' Dim objFSO
' Dim objFTemp
' Dim objTextStream
' Dim lngSize
'
' Set objFSO = CreateObject("Scripting.FileSystemObject")
'
' ' First, we get the filesize
' Set objFTemp = objFSO.GetFile(flnm)
' lngSize = objFTemp.Size
' set objFTemp = nothing
'
' fsoForReading = 1
' Set objTextStream = objFSO.OpenTextFile(flnm, fsoForReading)
'
' if offset > 0 then
' strBuff = objTextStream.Read(offset - 1)
' end if
'
' if bytes = -1 then ' Get All!
' GetBytes = objTextStream.Read(lngSize) 'ReadAll
' else
' GetBytes = objTextStream.Read(bytes)
' end if
'
' objTextStream.Close
' set objTextStream = nothing
' set objFSO = nothing
End Function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: Functions to convert two bytes to a numeric value (long) :::
'::: (both little-endian and big-endian) :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Private Function lngConvert(strTemp)
lngConvert = clng(asc(left(strTemp, 1)) + ((asc(right(strTemp, 1)) * 256)))
end function
Private Function lngConvert2(strTemp)
lngConvert2 = clng(asc(right(strTemp, 1)) + ((asc(left(strTemp, 1)) * 256)))
end function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This function does most of the real work. It will attempt :::
'::: to read any file, regardless of the extension, and will :::
'::: identify if it is a graphical image. :::
'::: :::
'::: Passed: :::
'::: flnm => Filespec of file to read :::
'::: width => width of image :::
'::: height => height of image :::
'::: depth => color depth (in number of colors) :::
'::: strImageType=> type of image (e.g. GIF, BMP, etc.) :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
function gfxSpex(flnm, width, height, depth, strImageType)
dim strPNG
dim strGIF
dim strBMP
dim strType
dim strBuff
dim lngSize
dim flgFound
dim strTarget
dim lngPos
dim ExitLoop
dim lngMarkerSize
strType = ""
strImageType = "(unknown)"
gfxSpex = False
strPNG = chr(137) & chr(80) & chr(78)
strGIF = "GIF"
strBMP = chr(66) & chr(77)
strType = GetBytes(flnm, 0, 3)
if strType = strGIF then ' is GIF
strImageType = "GIF"
Width = lngConvert(GetBytes(flnm, 7, 2))
Height = lngConvert(GetBytes(flnm, 9, 2))
Depth = 2 ^ ((asc(GetBytes(flnm, 11, 1)) and 7) + 1)
gfxSpex = True
elseif left(strType, 2) = strBMP then ' is BMP
strImageType = "BMP"
Width = lngConvert(GetBytes(flnm, 19, 2))
Height = lngConvert(GetBytes(flnm, 23, 2))
Depth = 2 ^ (asc(GetBytes(flnm, 29, 1)))
gfxSpex = True
elseif strType = strPNG then ' Is PNG
strImageType = "PNG"
Width = lngConvert2(GetBytes(flnm, 19, 2))
Height = lngConvert2(GetBytes(flnm, 23, 2))
Depth = getBytes(flnm, 25, 2)
select case asc(right(Depth,1))
case 0
Depth = 2 ^ (asc(left(Depth, 1)))
gfxSpex = True
case 2
Depth = 2 ^ (asc(left(Depth, 1)) * 3)
gfxSpex = True
case 3
Depth = 2 ^ (asc(left(Depth, 1))) '8
gfxSpex = True
case 4
Depth = 2 ^ (asc(left(Depth, 1)) * 2)
gfxSpex = True
case 6
Depth = 2 ^ (asc(left(Depth, 1)) * 4)
gfxSpex = True
case else
Depth = -1
end select
else
strBuff = GetBytes(flnm, 0, -1) ' Get all bytes from file
lngSize = len(strBuff)
flgFound = 0
strTarget = chr(255) & chr(216) & chr(255)
flgFound = instr(strBuff, strTarget)
if flgFound = 0 then
exit function
end if
strImageType = "JPG"
lngPos = flgFound + 2
ExitLoop = false
do while ExitLoop = False and lngPos < lngSize
do while asc(mid(strBuff, lngPos, 1)) = 255 and lngPos < lngSize
lngPos = lngPos + 1
loop
if asc(mid(strBuff, lngPos, 1)) < 192 or asc(mid(strBuff, lngPos, 1)) > 195 then
lngMarkerSize = lngConvert2(mid(strBuff, lngPos + 1, 2))
lngPos = lngPos + lngMarkerSize + 1
else
ExitLoop = True
end if
loop
if ExitLoop = False then
Width = -1
Height = -1
Depth = -1
else
Height = lngConvert2(mid(strBuff, lngPos + 4, 2))
Width = lngConvert2(mid(strBuff, lngPos + 6, 2))
Depth = 2 ^ (asc(mid(strBuff, lngPos + 8, 1)) * 8)
gfxSpex = True
end if
end if
End Function
End Class
%>
Constants explained:
MAX_UPLOAD_SIZE - maximum size, in bytes, of all uploaded files. When exceeding that size the upload process is aborted and global error is set to the constant MSG_EXCEEDED_MAX_SIZE.
MSG_NO_DATA - when user does not choose any file to upload, global error will be set to that constant.
SU_DEBUG_MODE - when set to True the script will output various messages via Response.Write(), useful for debugging problems.
Simple use case: (full code)
<!-- #include file="ShadowUpload.asp" -->
<%
Dim objUpload
If Request("action")="1" Then
Set objUpload=New ShadowUpload
If objUpload.GetError<>"" Then
Response.Write("sorry, could not upload: "&objUpload.GetError)
Else
Response.Write("found "&objUpload.FileCount&" files...<br />")
For x=0 To objUpload.FileCount-1
Response.Write("file name: "&objUpload.File(x).FileName&"<br />")
Response.Write("file type: "&objUpload.File(x).ContentType&"<br />")
Response.Write("file size: "&objUpload.File(x).Size&"<br />")
Response.Write("image width: "&objUpload.File(x).ImageWidth&"<br />")
Response.Write("image height: "&objUpload.File(x).ImageHeight&"<br />")
If (objUpload.File(x).ImageWidth>200) Or (objUpload.File(x).ImageHeight>200) Then
Response.Write("image to big, not saving!")
Else
Call objUpload.File(x).SaveToDisk(Server.MapPath("Uploads"), "")
Response.Write("file saved successfully!")
End If
Response.Write("<hr />")
Next
Response.Write("thank you, "&objUpload("name"))
End If
End If
%>
<form action="<%=Request.ServerVariables( "Script_Name" )%>?action=1" enctype="multipart/form-data" method="POST">
File1: <input type="file" name="file1" /><br />
File2: <input type="file" name="file2" /><br />
File3: <input type="file" name="file3" /><br />
Name: <input type="text" name="name" /><br />
<button type="submit">Upload</button>
</form>
This demonstrates using most of the script features, to block non image files from uploading you can just have something like:
If objUpload.File(x).ImageWidth<0 Then
Response.Write("Not a valid image!")
Else
'proceed to save the file...
End If
Disclaimer: This was originally posted here seven years ago and as credited in the code itself, contains parts not written by me.
Note for clients using Chrome browser on android device:
For some reason, the standard <button> element of type submit appears not to work properly in Chrome for android. If you get complaints from clients about it, try changing this line in the form:
<button type="submit">Upload</button>
to this instead:
<input type="submit" value="Upload" />
Due to possible bug in the Chrome app for android, when using the phone's camera app to take a new image then trying to submit this image, it might fail. In such case just advice the client to use a different browser.
The code of #ShadowWizard is nice and run as a charme on a local machine, but I encountered uploading issues on a production server, then I rewrote the Class with a more robust parsing routine for the upload request.
The class can handle more errors right now and You can upload multiple files with a single INPUT element; save this as a new file and rename it as "uploadhelper.asp"
<%
Const MAX_UPLOAD_SIZE = 25000000 '25 MB
Const MSG_NO_DATA = "Nothing to upload."
Const MSG_EXCEEDED_MAX_SIZE = "You exceeded the maximum upload size."
Const MSG_BAD_REQUEST_METHOD = "Bad request method. Use the POST method."
Const MSG_BAD_ENCTYPE = "Bad encoding type. Use a ""multipart/form-data"" enctype."
Const MSG_ZERO_LENGTH = "Zero length request."
Class UploadHelper
Private m_Request
Private m_Files
Private m_Error
Public Property Get GetError
GetError = m_Error
End Property
Public Property Get FileCount
FileCount = m_Files.Count
End Property
Public Function File(index)
If m_Files.Exists(index) Then
Set File = m_Files(index)
Else
Set File = Nothing
End If
End Function
Public Default Property Get Item(strName)
If m_Request.Exists(strName) Then
Item = m_Request(strName)
Else
Item = ""
End If
End Property
Private Sub Class_Initialize
Dim iBytesCount, strBinData
'first of all, get amount of uploaded bytes:
iBytesCount = Request.TotalBytes
'abort if nothing there:
If iBytesCount = 0 Then
m_Error = MSG_NO_DATA
Exit Sub
End If
'abort if exceeded maximum upload size:
If iBytesCount > MAX_UPLOAD_SIZE Then
m_Error = MSG_EXCEEDED_MAX_SIZE
Exit Sub
End If
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
Dim CT, PosB, Boundary, PosE
CT = Request.ServerVariables("HTTP_Content_Type")
If LCase(Left(CT, 19)) = "multipart/form-data" Then
PosB = InStr(LCase(CT), "boundary=")
If PosB > 0 Then Boundary = Mid(CT, PosB + 9)
PosB = InStr(LCase(CT), "boundary=")
If PosB > 0 Then
PosB = InStr(Boundary, ",")
If PosB > 0 Then Boundary = Left(Boundary, PosB - 1)
End If
If iBytesCount > 0 And Boundary <> "" Then
Boundary = "--" & Boundary
Dim Head, Binary
Binary = Request.BinaryRead(iBytesCount)
'create private collections:
Set m_Request = Server.CreateObject("Scripting.Dictionary")
Set m_Files = Server.CreateObject("Scripting.Dictionary")
Call ParseRequest(Binary, Boundary)
Binary = Empty
Else
m_Error = MSG_ZERO_LENGTH
Exit Sub
End If
Else
m_Error = MSG_BAD_ENCTYPE
Exit Sub
End If
Else
m_Error = MSG_BAD_REQUEST_METHOD
Exit Sub
End If
End Sub
Private Sub Class_Terminate
Dim fileName
If IsObject(m_Request) Then
m_Request.RemoveAll
Set m_Request = Nothing
End If
If IsObject(m_Files) Then
For Each fileName In m_Files.Keys
Set m_Files(fileName)=Nothing
Next
m_Files.RemoveAll
Set m_Files = Nothing
End If
End Sub
Private Sub ParseRequest(Binary, Boundary)
Dim PosOpenBoundary, PosCloseBoundary, PosEndOfHeader, isLastBoundary
Boundary = StringToBinary(Boundary)
PosOpenBoundary = InStrB(Binary, Boundary)
PosCloseBoundary = InStrB(PosOpenBoundary + LenB(Boundary), Binary, Boundary, 0)
Dim HeaderContent, FieldContent, bFieldContent
Dim Content_Disposition, FormFieldName, SourceFileName, Content_Type
Dim TwoCharsAfterEndBoundary, n : n = 0
Do While (PosOpenBoundary > 0 And PosCloseBoundary > 0 And Not isLastBoundary)
PosEndOfHeader = InStrB(PosOpenBoundary + Len(Boundary), Binary, StringToBinary(vbCrLf + vbCrLf))
HeaderContent = MidB(Binary, PosOpenBoundary + LenB(Boundary) + 2, PosEndOfHeader - PosOpenBoundary - LenB(Boundary) - 2)
bFieldContent = MidB(Binary, (PosEndOfHeader + 4), PosCloseBoundary - (PosEndOfHeader + 4) - 2)
GetHeadFields BinaryToString(HeaderContent), Content_Disposition, FormFieldName, SourceFileName, Content_Type
Set objFileData = New FileData
objFileData.FileName = SourceFileName
objFileData.ContentType = Content_Type
objFileData.Contents = bFieldContent
objFileData.FormFieldName = FormFieldName
objFileData.ContentDisposition = Content_Disposition
Set m_Files(n) = objFileData
Set objFileData = Nothing
TwoCharsAfterEndBoundary = BinaryToString(MidB(Binary, PosCloseBoundary + LenB(Boundary), 2))
isLastBoundary = TwoCharsAfterEndBoundary = "--"
If Not isLastBoundary Then
PosOpenBoundary = PosCloseBoundary
PosCloseBoundary = InStrB(PosOpenBoundary + LenB(Boundary), Binary, Boundary)
End If
n = n + 1
Loop
End Sub
Private Function GetHeadFields(ByVal Head, Content_Disposition, Name, FileName, Content_Type)
Content_Disposition = LTrim(SeparateField(Head, "content-disposition:", ";"))
Name = (SeparateField(Head, "name=", ";"))
If Left(Name, 1) = """" Then Name = Mid(Name, 2, Len(Name) - 2)
FileName = (SeparateField(Head, "filename=", ";"))
If Left(FileName, 1) = """" Then FileName = Mid(FileName, 2, Len(FileName) - 2)
Content_Type = LTrim(SeparateField(Head, "content-type:", ";"))
End Function
Private Function SeparateField(From, ByVal sStart, ByVal sEnd)
Dim PosB, PosE, sFrom
sFrom = LCase(From)
PosB = InStr(sFrom, sStart)
If PosB > 0 Then
PosB = PosB + Len(sStart)
PosE = InStr(PosB, sFrom, sEnd)
If PosE = 0 Then PosE = InStr(PosB, sFrom, vbCrLf)
If PosE = 0 Then PosE = Len(sFrom) + 1
SeparateField = Mid(From, PosB, PosE - PosB)
Else
SeparateField = Empty
End If
End Function
Private Function BinaryToString(Binary)
dim cl1, cl2, cl3, pl1, pl2, pl3
Dim L
cl1 = 1
cl2 = 1
cl3 = 1
L = LenB(Binary)
Do While cl1<=L
pl3 = pl3 & Chr(AscB(MidB(Binary,cl1,1)))
cl1 = cl1 + 1
cl3 = cl3 + 1
if cl3>300 then
pl2 = pl2 & pl3
pl3 = ""
cl3 = 1
cl2 = cl2 + 1
if cl2>200 then
pl1 = pl1 & pl2
pl2 = ""
cl2 = 1
End If
End If
Loop
BinaryToString = pl1 & pl2 & pl3
End Function
Private Function StringToBinary(String)
Dim I, B
For I=1 to len(String)
B = B & ChrB(Asc(Mid(String,I,1)))
Next
StringToBinary = B
End Function
End Class
Class FileData
Private m_fileName
Private m_contentType
Private m_BinaryContents
Private m_AsciiContents
Private m_imageWidth
Private m_imageHeight
Private m_checkImage
Private m_formFieldName
Private m_contentDisposition
Public Property Get FormFieldName
FormFieldName = m_formFieldName
End Property
Public Property Let FormFieldName(sFieldName)
m_formFieldName = sFieldName
End Property
Public Property Get ContentDisposition
ContentDisposition = m_contentDisposition
End Property
Public Property Let ContentDisposition(sContentDisposition)
m_contentDisposition = sContentDisposition
End Property
Public Property Get FileName
FileName = m_fileName
End Property
Public Property Get ContentType
ContentType = m_contentType
End Property
Public Property Get ImageWidth
If m_checkImage=False Then Call CheckImageDimensions
ImageWidth = m_imageWidth
End Property
Public Property Get ImageHeight
If m_checkImage=False Then Call CheckImageDimensions
ImageHeight = m_imageHeight
End Property
Public Property Let FileName(ByVal strName)
strName = Replace(strName, "/", "\")
Dim arrTemp : arrTemp = Split(strName, "\")
m_fileName = arrTemp(UBound(arrTemp))
End Property
Public Property Let CheckImage(blnCheck)
m_checkImage = blnCheck
End Property
Public Property Let ContentType(strType)
m_contentType = strType
End Property
Public Property Let Contents(strData)
m_BinaryContents = strData
m_AsciiContents = RSBinaryToString(m_BinaryContents)
End Property
Public Property Get Size
Size = LenB(m_BinaryContents)
End Property
Private Sub CheckImageDimensions
Dim width, height, colors
Dim strType
'''If gfxSpex(BinaryToAscii(m_BinaryContents), width, height, colors, strType) = true then
If gfxSpex(m_AsciiContents, width, height, colors, strType) = true then
m_imageWidth = width
m_imageHeight = height
End If
m_checkImage = True
End Sub
Private Sub Class_Initialize
m_imageWidth = -1
m_imageHeight = -1
m_checkImage = False
End Sub
Public Sub SaveToDisk(strFolderPath, ByRef strNewFileName)
Dim strPath, objFSO, objFile
Dim i, time1, time2
Dim objStream, strExtension
strPath = strFolderPath&"\"
If Len(strNewFileName)=0 Then
strPath = strPath & m_fileName
Else
strExtension = GetExtension(strNewFileName)
If Len(strExtension)=0 Then
strNewFileName = strNewFileName & "." & GetExtension(m_fileName)
End If
strPath = strPath & strNewFileName
End If
time1 = CDbl(Timer)
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(strPath)
objFile.Write(m_AsciiContents)
'''For i=1 to LenB(m_BinaryContents)
''' objFile.Write chr(AscB(MidB(m_BinaryContents, i, 1)))
'''Next
time2 = CDbl(Timer)
objFile.Close
Set objFile=Nothing
Set objFSO=Nothing
End Sub
Private Function GetExtension(strPath)
Dim arrTemp
arrTemp = Split(strPath, ".")
GetExtension = ""
If UBound(arrTemp)>0 Then
GetExtension = arrTemp(UBound(arrTemp))
End If
End Function
Private Function RSBinaryToString(xBinary)
'Antonin Foller, http://www.motobit.com
'RSBinaryToString converts binary data (VT_UI1 | VT_ARRAY Or MultiByte string)
'to a string (BSTR) using ADO recordset
Dim Binary
'MultiByte data must be converted To VT_UI1 | VT_ARRAY first.
If vartype(xBinary)=8 Then Binary = MultiByteToBinary(xBinary) Else Binary = xBinary
Dim RS, LBinary
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
LBinary = LenB(Binary)
If LBinary>0 Then
RS.Fields.Append "mBinary", adLongVarChar, LBinary
RS.Open
RS.AddNew
RS("mBinary").AppendChunk Binary
RS.Update
RSBinaryToString = RS("mBinary")
Else
RSBinaryToString = ""
End If
End Function
Function MultiByteToBinary(MultiByte)
'© 2000 Antonin Foller, http://www.motobit.com
' MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)
' Using recordset
Dim RS, LMultiByte, Binary
Const adLongVarBinary = 205
Set RS = CreateObject("ADODB.Recordset")
LMultiByte = LenB(MultiByte)
If LMultiByte>0 Then
RS.Fields.Append "mBinary", adLongVarBinary, LMultiByte
RS.Open
RS.AddNew
RS("mBinary").AppendChunk MultiByte & ChrB(0)
RS.Update
Binary = RS("mBinary").GetChunk(LMultiByte)
End If
MultiByteToBinary = Binary
End Function
Private Function BinaryToAscii(strBinary)
Dim i, result
result = ""
For i=1 to LenB(strBinary)
result = result & chr(AscB(MidB(strBinary, i, 1)))
Next
BinaryToAscii = result
End Function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This routine will attempt to identify any filespec passed :::
'::: as a graphic file (regardless of the extension). This will :::
'::: work with BMP, GIF, JPG and PNG files. :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: Based on ideas presented by David Crowell :::
'::: (credit where due) :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah Copyright *c* MM, Mike Shaffer blah blah :::
'::: bh blah ALL RIGHTS RESERVED WORLDWIDE blah blah :::
'::: blah blah Permission is granted to use this code blah blah :::
'::: blah blah in your projects, as long as this blah blah :::
'::: blah blah copyright notice is included blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
'::: blah blah blah blah blah blah blah blah blah blah blah blah :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This function gets a specified number of bytes from any :::
'::: file, starting at the offset (base 1) :::
'::: :::
'::: Passed: :::
'::: flnm => Filespec of file to read :::
'::: offset => Offset at which to start reading :::
'::: bytes => How many bytes to read :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Private Function GetBytes(flnm, offset, bytes)
Dim startPos
If offset=0 Then
startPos = 1
Else
startPos = offset
End If
if bytes = -1 then ' Get All!
GetBytes = flnm
else
GetBytes = Mid(flnm, startPos, bytes)
end if
' Dim objFSO
' Dim objFTemp
' Dim objTextStream
' Dim lngSize
'
' Set objFSO = CreateObject("Scripting.FileSystemObject")
'
' ' First, we get the filesize
' Set objFTemp = objFSO.GetFile(flnm)
' lngSize = objFTemp.Size
' set objFTemp = nothing
'
' fsoForReading = 1
' Set objTextStream = objFSO.OpenTextFile(flnm, fsoForReading)
'
' if offset > 0 then
' strBuff = objTextStream.Read(offset - 1)
' end if
'
' if bytes = -1 then ' Get All!
' GetBytes = objTextStream.Read(lngSize) 'ReadAll
' else
' GetBytes = objTextStream.Read(bytes)
' end if
'
' objTextStream.Close
' set objTextStream = nothing
' set objFSO = nothing
End Function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: Functions to convert two bytes to a numeric value (long) :::
'::: (both little-endian and big-endian) :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Private Function lngConvert(strTemp)
lngConvert = clng(asc(left(strTemp, 1)) + ((asc(right(strTemp, 1)) * 256)))
end function
Private Function lngConvert2(strTemp)
lngConvert2 = clng(asc(right(strTemp, 1)) + ((asc(left(strTemp, 1)) * 256)))
end function
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'::: :::
'::: This function does most of the real work. It will attempt :::
'::: to read any file, regardless of the extension, and will :::
'::: identify if it is a graphical image. :::
'::: :::
'::: Passed: :::
'::: flnm => Filespec of file to read :::
'::: width => width of image :::
'::: height => height of image :::
'::: depth => color depth (in number of colors) :::
'::: strImageType=> type of image (e.g. GIF, BMP, etc.) :::
'::: :::
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
function gfxSpex(flnm, width, height, depth, strImageType)
dim strPNG
dim strGIF
dim strBMP
dim strType
dim strBuff
dim lngSize
dim flgFound
dim strTarget
dim lngPos
dim ExitLoop
dim lngMarkerSize
strType = ""
strImageType = "(unknown)"
gfxSpex = False
strPNG = chr(137) & chr(80) & chr(78)
strGIF = "GIF"
strBMP = chr(66) & chr(77)
strType = GetBytes(flnm, 0, 3)
if strType = strGIF then ' is GIF
strImageType = "GIF"
Width = lngConvert(GetBytes(flnm, 7, 2))
Height = lngConvert(GetBytes(flnm, 9, 2))
Depth = 2 ^ ((asc(GetBytes(flnm, 11, 1)) and 7) + 1)
gfxSpex = True
elseif left(strType, 2) = strBMP then ' is BMP
strImageType = "BMP"
Width = lngConvert(GetBytes(flnm, 19, 2))
Height = lngConvert(GetBytes(flnm, 23, 2))
Depth = 2 ^ (asc(GetBytes(flnm, 29, 1)))
gfxSpex = True
elseif strType = strPNG then ' Is PNG
strImageType = "PNG"
Width = lngConvert2(GetBytes(flnm, 19, 2))
Height = lngConvert2(GetBytes(flnm, 23, 2))
Depth = getBytes(flnm, 25, 2)
select case asc(right(Depth,1))
case 0
Depth = 2 ^ (asc(left(Depth, 1)))
gfxSpex = True
case 2
Depth = 2 ^ (asc(left(Depth, 1)) * 3)
gfxSpex = True
case 3
Depth = 2 ^ (asc(left(Depth, 1))) '8
gfxSpex = True
case 4
Depth = 2 ^ (asc(left(Depth, 1)) * 2)
gfxSpex = True
case 6
Depth = 2 ^ (asc(left(Depth, 1)) * 4)
gfxSpex = True
case else
Depth = -1
end select
else
strBuff = GetBytes(flnm, 0, -1) ' Get all bytes from file
lngSize = len(strBuff)
flgFound = 0
strTarget = chr(255) & chr(216) & chr(255)
flgFound = instr(strBuff, strTarget)
if flgFound = 0 then
exit function
end if
strImageType = "JPG"
lngPos = flgFound + 2
ExitLoop = false
do while ExitLoop = False and lngPos < lngSize
do while asc(mid(strBuff, lngPos, 1)) = 255 and lngPos < lngSize
lngPos = lngPos + 1
loop
if asc(mid(strBuff, lngPos, 1)) < 192 or asc(mid(strBuff, lngPos, 1)) > 195 then
lngMarkerSize = lngConvert2(mid(strBuff, lngPos + 1, 2))
lngPos = lngPos + lngMarkerSize + 1
else
ExitLoop = True
end if
loop
if ExitLoop = False then
Width = -1
Height = -1
Depth = -1
else
Height = lngConvert2(mid(strBuff, lngPos + 4, 2))
Width = lngConvert2(mid(strBuff, lngPos + 6, 2))
Depth = 2 ^ (asc(mid(strBuff, lngPos + 8, 1)) * 8)
gfxSpex = True
end if
end if
End Function
End Class
%>
Usage: create a new *.asp file with the following code to upload your files.
<!-- #include file="uploadhelper.asp" -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<form action="<%=Request.ServerVariables("SCRIPT_NAME")%>?cmd=upload" method="POST" enctype="multipart/form-data">
File: <input type="file" name="files[]" multiple>
<input type="submit" value="Upload">
</form>
<%
If Request("cmd")="upload" Then
Dim objUpload : Set objUpload = New UploadHelper
If objUpload.GetError <> "" Then
Response.Write("Warning: "&objUpload.GetError)
Else
Response.Write("found "&objUpload.FileCount&" files...<br />")
Dim x : For x = 0 To objUpload.FileCount - 1
Response.Write("form field name: "&objUpload.File(x).FormFieldName&"<br />")
Response.Write("content disposition: "&objUpload.File(x).ContentDisposition&"<br />")
Response.Write("file name: "&objUpload.File(x).FileName&"<br />")
Response.Write("file type: "&objUpload.File(x).ContentType&"<br />")
Response.Write("file size: "&objUpload.File(x).Size&"<br />")
Response.Write("image width: "&objUpload.File(x).ImageWidth&"<br />")
Response.Write("image height: "&objUpload.File(x).ImageHeight&"<br />")
If (objUpload.File(x).ImageWidth>1024) Or (objUpload.File(x).ImageHeight>1024) Then
Response.Write("the image is too big, file not saved!")
Else
Call objUpload.File(x).SaveToDisk(Server.MapPath("/public"), "")
Response.Write("file saved successfully!")
End If
Response.Write("<hr />")
Next
End If
End If
%>
</body>
</html>
As a PPS, the problem might be a little more basic than you might think. IIS has a limit of 200K for a BinaryRead() function call. Has anyone come into this problem while trying to implement this solution?
Why wasn't the BinaryRead() limitation mentioned anywhere in the initial documentation? I've been struggling with this for over an hour.
This link on StackOverflow explains it: Request.BinaryRead(Request.TotalBytes) throws error for large files