/html5/freeASPUpload.asp

http://github.com/khaneh/Orders · ASP · 402 lines · 304 code · 63 blank · 35 comment · 13 complexity · 15a3f9bc4d9f6169a191b489aa0d982b MD5 · raw file

  1. <%
  2. ' For examples, documentation, and your own free copy, go to:
  3. ' http://www.freeaspupload.net
  4. ' Note: You can copy and use this script for free and you can make changes
  5. ' to the code, but you cannot remove the above comment.
  6. 'Changes:
  7. 'Aug 2, 2005: Add support for checkboxes and other input elements with multiple values
  8. 'Jan 6, 2009: Lars added ASP_CHUNK_SIZE
  9. 'Sep 3, 2010: Enforce UTF-8 everywhere; new function to convert byte array to unicode string
  10. const DEFAULT_ASP_CHUNK_SIZE = 200000
  11. const adModeReadWrite = 3
  12. const adTypeBinary = 1
  13. const adTypeText = 2
  14. const adSaveCreateOverWrite = 2
  15. Class FreeASPUpload
  16. Public UploadedFiles
  17. Public FormElements
  18. Private VarArrayBinRequest
  19. Private StreamRequest
  20. Private uploadedYet
  21. Private internalChunkSize
  22. Private Sub Class_Initialize()
  23. Set UploadedFiles = Server.CreateObject("Scripting.Dictionary")
  24. Set FormElements = Server.CreateObject("Scripting.Dictionary")
  25. Set StreamRequest = Server.CreateObject("ADODB.Stream")
  26. StreamRequest.Type = adTypeText
  27. StreamRequest.Open
  28. uploadedYet = false
  29. internalChunkSize = DEFAULT_ASP_CHUNK_SIZE
  30. End Sub
  31. Private Sub Class_Terminate()
  32. If IsObject(UploadedFiles) Then
  33. UploadedFiles.RemoveAll()
  34. Set UploadedFiles = Nothing
  35. End If
  36. If IsObject(FormElements) Then
  37. FormElements.RemoveAll()
  38. Set FormElements = Nothing
  39. End If
  40. StreamRequest.Close
  41. Set StreamRequest = Nothing
  42. End Sub
  43. Public Property Get Form(sIndex)
  44. Form = ""
  45. If FormElements.Exists(LCase(sIndex)) Then Form = FormElements.Item(LCase(sIndex))
  46. End Property
  47. Public Property Get Files()
  48. Files = UploadedFiles.Items
  49. End Property
  50. Public Property Get Exists(sIndex)
  51. Exists = false
  52. If FormElements.Exists(LCase(sIndex)) Then Exists = true
  53. End Property
  54. Public Property Get FileExists(sIndex)
  55. FileExists = false
  56. if UploadedFiles.Exists(LCase(sIndex)) then FileExists = true
  57. End Property
  58. Public Property Get chunkSize()
  59. chunkSize = internalChunkSize
  60. End Property
  61. Public Property Let chunkSize(sz)
  62. internalChunkSize = sz
  63. End Property
  64. 'Calls Upload to extract the data from the binary request and then saves the uploaded files
  65. Public Sub Save(path)
  66. Dim streamFile, fileItem, filePath
  67. if Right(path, 1) <> "\" then path = path & "\"
  68. if not uploadedYet then Upload
  69. For Each fileItem In UploadedFiles.Items
  70. filePath = path & fileItem.FileName
  71. Set streamFile = Server.CreateObject("ADODB.Stream")
  72. streamFile.Type = adTypeBinary
  73. streamFile.Open
  74. StreamRequest.Position=fileItem.Start
  75. StreamRequest.CopyTo streamFile, fileItem.Length
  76. streamFile.SaveToFile filePath, adSaveCreateOverWrite
  77. streamFile.close
  78. Set streamFile = Nothing
  79. fileItem.Path = filePath
  80. Next
  81. End Sub
  82. public sub SaveOne(path, num, byref outFileName, byref outLocalFileName)
  83. Dim streamFile, fileItems, fileItem, fs
  84. set fs = Server.CreateObject("Scripting.FileSystemObject")
  85. if Right(path, 1) <> "\" then path = path & "\"
  86. if not uploadedYet then Upload
  87. if UploadedFiles.Count > 0 then
  88. fileItems = UploadedFiles.Items
  89. set fileItem = fileItems(num)
  90. outFileName = fileItem.FileName
  91. outLocalFileName = GetFileName(path, outFileName)
  92. Set streamFile = Server.CreateObject("ADODB.Stream")
  93. streamFile.Type = adTypeBinary
  94. streamFile.Open
  95. StreamRequest.Position = fileItem.Start
  96. StreamRequest.CopyTo streamFile, fileItem.Length
  97. streamFile.SaveToFile path & outLocalFileName, adSaveCreateOverWrite
  98. streamFile.close
  99. Set streamFile = Nothing
  100. fileItem.Path = path & filename
  101. end if
  102. end sub
  103. Public Function SaveBinRequest(path) ' For debugging purposes
  104. StreamRequest.SaveToFile path & "\debugStream.bin", 2
  105. End Function
  106. Public Sub DumpData() 'only works if files are plain text
  107. Dim i, aKeys, f
  108. response.write "Form Items:<br>"
  109. aKeys = FormElements.Keys
  110. For i = 0 To FormElements.Count -1 ' Iterate the array
  111. response.write aKeys(i) & " = " & FormElements.Item(aKeys(i)) & "<BR>"
  112. Next
  113. response.write "Uploaded Files:<br>"
  114. For Each f In UploadedFiles.Items
  115. response.write "Name: " & f.FileName & "<br>"
  116. response.write "Type: " & f.ContentType & "<br>"
  117. response.write "Start: " & f.Start & "<br>"
  118. response.write "Size: " & f.Length & "<br>"
  119. Next
  120. End Sub
  121. Public Sub Upload()
  122. Dim nCurPos, nDataBoundPos, nLastSepPos
  123. Dim nPosFile, nPosBound
  124. Dim sFieldName, osPathSep, auxStr
  125. Dim readBytes, readLoop, tmpBinRequest
  126. 'RFC1867 Tokens
  127. Dim vDataSep
  128. Dim tNewLine, tDoubleQuotes, tTerm, tFilename, tName, tContentDisp, tContentType
  129. tNewLine = String2Byte(Chr(13))
  130. tDoubleQuotes = String2Byte(Chr(34))
  131. tTerm = String2Byte("--")
  132. tFilename = String2Byte("filename=""")
  133. tName = String2Byte("name=""")
  134. tContentDisp = String2Byte("Content-Disposition")
  135. tContentType = String2Byte("Content-Type:")
  136. uploadedYet = true
  137. on error resume next
  138. ' Copy binary request to a byte array, on which functions like InstrB and others can be used to search for separation tokens
  139. readBytes = internalChunkSize
  140. VarArrayBinRequest = Request.BinaryRead(readBytes)
  141. VarArrayBinRequest = midb(VarArrayBinRequest, 1, lenb(VarArrayBinRequest))
  142. Do Until readBytes < 1
  143. tmpBinRequest = Request.BinaryRead(readBytes)
  144. if readBytes > 0 then
  145. VarArrayBinRequest = VarArrayBinRequest & midb(tmpBinRequest, 1, lenb(tmpBinRequest))
  146. end if
  147. Loop
  148. StreamRequest.WriteText(VarArrayBinRequest)
  149. StreamRequest.Flush()
  150. if Err.Number <> 0 then
  151. response.write "<br><br><B>System reported this error:</B><p>"
  152. response.write Err.Description & "<p>"
  153. response.write "The most likely cause for this error is the incorrect setup of AspMaxRequestEntityAllowed in IIS MetaBase. Please see instructions in the <A HREF='http://www.freeaspupload.net/freeaspupload/requirements.asp'>requirements page of freeaspupload.net</A>.<p>"
  154. Exit Sub
  155. end if
  156. on error goto 0 'reset error handling
  157. nCurPos = FindToken(tNewLine,1) 'Note: nCurPos is 1-based (and so is InstrB, MidB, etc)
  158. If nCurPos <= 1 Then Exit Sub
  159. 'vDataSep is a separator like -----------------------------21763138716045
  160. vDataSep = MidB(VarArrayBinRequest, 1, nCurPos-1)
  161. 'Start of current separator
  162. nDataBoundPos = 1
  163. 'Beginning of last line
  164. nLastSepPos = FindToken(vDataSep & tTerm, 1)
  165. Do Until nDataBoundPos = nLastSepPos
  166. nCurPos = SkipToken(tContentDisp, nDataBoundPos)
  167. nCurPos = SkipToken(tName, nCurPos)
  168. sFieldName = ExtractField(tDoubleQuotes, nCurPos)
  169. nPosFile = FindToken(tFilename, nCurPos)
  170. nPosBound = FindToken(vDataSep, nCurPos)
  171. If nPosFile <> 0 And nPosFile < nPosBound Then
  172. Dim oUploadFile
  173. Set oUploadFile = New UploadedFile
  174. nCurPos = SkipToken(tFilename, nCurPos)
  175. auxStr = ExtractField(tDoubleQuotes, nCurPos)
  176. ' We are interested only in the name of the file, not the whole path
  177. ' Path separator is \ in windows, / in UNIX
  178. ' While IE seems to put the whole pathname in the stream, Mozilla seem to
  179. ' only put the actual file name, so UNIX paths may be rare. But not impossible.
  180. osPathSep = "\"
  181. if InStr(auxStr, osPathSep) = 0 then osPathSep = "/"
  182. oUploadFile.FileName = Right(auxStr, Len(auxStr)-InStrRev(auxStr, osPathSep))
  183. if (Len(oUploadFile.FileName) > 0) then 'File field not left empty
  184. nCurPos = SkipToken(tContentType, nCurPos)
  185. auxStr = ExtractField(tNewLine, nCurPos)
  186. ' NN on UNIX puts things like this in the stream:
  187. ' ?? python py type=?? python application/x-python
  188. oUploadFile.ContentType = Right(auxStr, Len(auxStr)-InStrRev(auxStr, " "))
  189. nCurPos = FindToken(tNewLine, nCurPos) + 4 'skip empty line
  190. oUploadFile.Start = nCurPos+1
  191. oUploadFile.Length = FindToken(vDataSep, nCurPos) - 2 - nCurPos
  192. If oUploadFile.Length > 0 Then UploadedFiles.Add LCase(sFieldName), oUploadFile
  193. End If
  194. Else
  195. Dim nEndOfData, fieldValueUniStr
  196. nCurPos = FindToken(tNewLine, nCurPos) + 4 'skip empty line
  197. nEndOfData = FindToken(vDataSep, nCurPos) - 2
  198. fieldValueuniStr = ConvertUtf8BytesToString(nCurPos, nEndOfData-nCurPos)
  199. If Not FormElements.Exists(LCase(sFieldName)) Then
  200. FormElements.Add LCase(sFieldName), fieldValueuniStr
  201. else
  202. FormElements.Item(LCase(sFieldName))= FormElements.Item(LCase(sFieldName)) & ", " & fieldValueuniStr
  203. end if
  204. End If
  205. 'Advance to next separator
  206. nDataBoundPos = FindToken(vDataSep, nCurPos)
  207. Loop
  208. End Sub
  209. Private Function SkipToken(sToken, nStart)
  210. SkipToken = InstrB(nStart, VarArrayBinRequest, sToken)
  211. If SkipToken = 0 then
  212. Response.write "Error in parsing uploaded binary request. The most likely cause for this error is the incorrect setup of AspMaxRequestEntityAllowed in IIS MetaBase. Please see instructions in the <A HREF='http://www.freeaspupload.net/freeaspupload/requirements.asp'>requirements page of freeaspupload.net</A>.<p>"
  213. Response.End
  214. end if
  215. SkipToken = SkipToken + LenB(sToken)
  216. End Function
  217. Private Function FindToken(sToken, nStart)
  218. FindToken = InstrB(nStart, VarArrayBinRequest, sToken)
  219. End Function
  220. Private Function ExtractField(sToken, nStart)
  221. Dim nEnd
  222. nEnd = InstrB(nStart, VarArrayBinRequest, sToken)
  223. If nEnd = 0 then
  224. Response.write "Error in parsing uploaded binary request."
  225. Response.End
  226. end if
  227. ExtractField = ConvertUtf8BytesToString(nStart, nEnd-nStart)
  228. End Function
  229. 'String to byte string conversion
  230. Private Function String2Byte(sString)
  231. Dim i
  232. For i = 1 to Len(sString)
  233. String2Byte = String2Byte & ChrB(AscB(Mid(sString,i,1)))
  234. Next
  235. End Function
  236. Private Function ConvertUtf8BytesToString(start, length)
  237. StreamRequest.Position = 0
  238. Dim objStream
  239. Dim strTmp
  240. ' init stream
  241. Set objStream = Server.CreateObject("ADODB.Stream")
  242. objStream.Charset = "utf-8"
  243. objStream.Mode = adModeReadWrite
  244. objStream.Type = adTypeBinary
  245. objStream.Open
  246. ' write bytes into stream
  247. StreamRequest.Position = start+1
  248. StreamRequest.CopyTo objStream, length
  249. objStream.Flush
  250. ' rewind stream and read text
  251. objStream.Position = 0
  252. objStream.Type = adTypeText
  253. strTmp = objStream.ReadText
  254. ' close up and return
  255. objStream.Close
  256. Set objStream = Nothing
  257. ConvertUtf8BytesToString = strTmp
  258. End Function
  259. End Class
  260. Class UploadedFile
  261. Public ContentType
  262. Public Start
  263. Public Length
  264. Public Path
  265. Private nameOfFile
  266. ' Need to remove characters that are valid in UNIX, but not in Windows
  267. Public Property Let FileName(fN)
  268. nameOfFile = fN
  269. nameOfFile = SubstNoReg(nameOfFile, "\", "_")
  270. nameOfFile = SubstNoReg(nameOfFile, "/", "_")
  271. nameOfFile = SubstNoReg(nameOfFile, ":", "_")
  272. nameOfFile = SubstNoReg(nameOfFile, "*", "_")
  273. nameOfFile = SubstNoReg(nameOfFile, "?", "_")
  274. nameOfFile = SubstNoReg(nameOfFile, """", "_")
  275. nameOfFile = SubstNoReg(nameOfFile, "<", "_")
  276. nameOfFile = SubstNoReg(nameOfFile, ">", "_")
  277. nameOfFile = SubstNoReg(nameOfFile, "|", "_")
  278. End Property
  279. Public Property Get FileName()
  280. FileName = nameOfFile
  281. End Property
  282. 'Public Property Get FileN()ame
  283. End Class
  284. ' Does not depend on RegEx, which is not available on older VBScript
  285. ' Is not recursive, which means it will not run out of stack space
  286. Function SubstNoReg(initialStr, oldStr, newStr)
  287. Dim currentPos, oldStrPos, skip
  288. If IsNull(initialStr) Or Len(initialStr) = 0 Then
  289. SubstNoReg = ""
  290. ElseIf IsNull(oldStr) Or Len(oldStr) = 0 Then
  291. SubstNoReg = initialStr
  292. Else
  293. If IsNull(newStr) Then newStr = ""
  294. currentPos = 1
  295. oldStrPos = 0
  296. SubstNoReg = ""
  297. skip = Len(oldStr)
  298. Do While currentPos <= Len(initialStr)
  299. oldStrPos = InStr(currentPos, initialStr, oldStr)
  300. If oldStrPos = 0 Then
  301. SubstNoReg = SubstNoReg & Mid(initialStr, currentPos, Len(initialStr) - currentPos + 1)
  302. currentPos = Len(initialStr) + 1
  303. Else
  304. SubstNoReg = SubstNoReg & Mid(initialStr, currentPos, oldStrPos - currentPos) & newStr
  305. currentPos = oldStrPos + skip
  306. End If
  307. Loop
  308. End If
  309. End Function
  310. Function GetFileName(strSaveToPath, FileName)
  311. 'This function is used when saving a file to check there is not already a file with the same name so that you don't overwrite it.
  312. 'It adds numbers to the filename e.g. file.gif becomes file1.gif becomes file2.gif and so on.
  313. 'It keeps going until it returns a filename that does not exist.
  314. 'You could just create a filename from the ID field but that means writing the record - and it still might exist!
  315. 'N.B. Requires strSaveToPath variable to be available - and containing the path to save to
  316. Dim Counter
  317. Dim Flag
  318. Dim strTempFileName
  319. Dim FileExt
  320. Dim NewFullPath
  321. dim objFSO, p
  322. Set objFSO = CreateObject("Scripting.FileSystemObject")
  323. Counter = 0
  324. p = instrrev(FileName, ".")
  325. FileExt = mid(FileName, p+1)
  326. strTempFileName = left(FileName, p-1)
  327. NewFullPath = strSaveToPath & "\" & FileName
  328. Flag = False
  329. Do Until Flag = True
  330. If objFSO.FileExists(NewFullPath) = False Then
  331. Flag = True
  332. GetFileName = Mid(NewFullPath, InstrRev(NewFullPath, "\") + 1)
  333. Else
  334. Counter = Counter + 1
  335. NewFullPath = strSaveToPath & "\" & strTempFileName & Counter & "." & FileExt
  336. End If
  337. Loop
  338. End Function
  339. %>