Upload a file via <input \input> in HTML form with VBA
Asked Answered
C

2

6

I am trying to upload a picture file to OCR Site, however, the PDF file doesn't get uploaded into the site.

I am using the following code to achieve it and below is the HTML segment :

Sub DownPDF()

    Dim FileName As String: FileName = "C:\Users\310217955\Documents\pdfdown\SGSSI001_HL1464_2011.pdf"
    Dim DestURL As String: DestURL = "https://www.newocr.com/"
    Dim FieldName As String: FieldName = "userfile"
    Call UploadFile(DestURL, FileName, FieldName)

End Sub


'******************* upload - begin
'Upload file using input type=file
Sub UploadFile(DestURL, FileName, FieldName)
  'Boundary of fields.
  'Be sure this string is Not In the source file
  Const Boundary = "---------------------------0123456789012"

  Dim FileContents, FormData
  'Get source file As a binary data.
  FileContents = GetFile(FileName)

  'Build multipart/form-data document
  FormData = BuildFormData(FileContents, Boundary, FileName, FieldName)

  'Post the data To the destination URL
  IEPostBinaryRequest DestURL, FormData, Boundary
End Sub

'Build multipart/form-data document with file contents And header info
Function BuildFormData(FileContents, Boundary, FileName, FieldName)
  Dim FormData, Pre, Po
  Const ContentType = "application/upload"

  'The two parts around file contents In the multipart-form data.
  Pre = "--" + Boundary + vbCrLf + mpFields(FieldName, FileName, ContentType)
  Po = vbCrLf + "--" + Boundary + "--" + vbCrLf

  'Build form data using recordset binary field
  Const adLongVarBinary = 205
  Dim RS: Set RS = CreateObject("ADODB.Recordset")
  RS.Fields.Append "b", adLongVarBinary, Len(Pre) + LenB(FileContents) + Len(Po)
  RS.Open
  RS.AddNew
    Dim LenData
    'Convert Pre string value To a binary data
    LenData = Len(Pre)
    RS("b").AppendChunk (StringToMB(Pre) & ChrB(0))
    Pre = RS("b").GetChunk(LenData)
    RS("b") = ""

    'Convert Po string value To a binary data
    LenData = Len(Po)
    RS("b").AppendChunk (StringToMB(Po) & ChrB(0))
    Po = RS("b").GetChunk(LenData)
    RS("b") = ""

    'Join Pre + FileContents + Po binary data
    RS("b").AppendChunk (Pre)
    RS("b").AppendChunk (FileContents)
    RS("b").AppendChunk (Po)
  RS.Update
  FormData = RS("b")
  RS.Close
  BuildFormData = FormData
End Function

'sends multipart/form-data To the URL using IE
Function IEPostBinaryRequest(URL, FormData, Boundary)
  'Create InternetExplorer
  Dim IE: Set IE = CreateObject("InternetExplorer.Application")

  'You can uncoment Next line To see form results
  IE.Visible = True

  'Send the form data To URL As POST multipart/form-data request
  IE.Navigate URL, , , FormData, _
    "Content-Type: multipart/form-data; boundary=" + Boundary + vbCrLf

  Do While IE.Busy Or IE.readyState <> 4
    Wait 1, "Upload To " & URL
  Loop

  'Get a result of the script which has received upload
  On Error Resume Next
  IEPostBinaryRequest = IE.document.body.innerHTML
  'IE.Quit
End Function

'Infrormations In form field header.
Function mpFields(FieldName, FileName, ContentType)
  Dim MPTemplate 'template For multipart header
  MPTemplate = "Content-Disposition: form-data; name=""{field}"";" + _
   " filename=""{file}""" + vbCrLf + _
   "Content-Type: {ct}" + vbCrLf + vbCrLf
  Dim Out
  Out = Replace(MPTemplate, "{field}", FieldName)
  Out = Replace(Out, "{file}", FileName)
  mpFields = Replace(Out, "{ct}", ContentType)
End Function


Sub Wait(Seconds, Message)
  On Error Resume Next
  CreateObject("wscript.shell").Popup Message, Seconds, "", 64
End Sub


'Returns file contents As a binary data
Function GetFile(FileName)
  Dim Stream: Set Stream = CreateObject("ADODB.Stream")
  Stream.Type = 1 'Binary
  Stream.Open
  Stream.LoadFromFile FileName
  GetFile = Stream.Read
  Stream.Close
End Function

'Converts OLE string To multibyte string
Function StringToMB(S)
  Dim I, B
  For I = 1 To Len(S)
    B = B & ChrB(Asc(Mid(S, I, 1)))
  Next
  StringToMB = B
End Function
'******************* upload - end

'******************* Support
'Basic script info
Sub InfoEcho()
  Dim Msg
  Msg = Msg + "Upload file using http And multipart/form-data" & vbCrLf
  Msg = Msg + "Copyright (C) 2001 Antonin Foller, PSTRUH Software" & vbCrLf
  Msg = Msg + "use" & vbCrLf
  Msg = Msg + "[cscript|wscript] fupload.vbs file url [fieldname]" & vbCrLf
  Msg = Msg + "  file ... Local file To upload" & vbCrLf
  Msg = Msg + "  url ... URL which can accept uploaded data" & vbCrLf
  Msg = Msg + "  fieldname ... Name of the source form field." & vbCrLf
  Msg = Msg + vbCrLf + CheckRequirements
  WScript.Echo Msg
  WScript.Quit
End Sub

'Checks If all of required objects are installed
Function CheckRequirements()
  Dim Msg
  Msg = "This script requires some objects installed To run properly." & vbCrLf
  Msg = Msg & CheckOneObject("ADODB.Recordset")
  Msg = Msg & CheckOneObject("ADODB.Stream")
  Msg = Msg & CheckOneObject("InternetExplorer.Application")
  CheckRequirements = Msg
'  MsgBox Msg
End Function

'Checks If the one object is installed.
Function CheckOneObject(oClass)
  Dim Msg
  On Error Resume Next
  CreateObject oClass
  If Err = 0 Then Msg = "OK" Else Msg = "Error:" & Err.Description
  CheckOneObject = oClass & " - " & Msg & vbCrLf
End Function

Here is the HTML segment.

<input name="userfile" id="userfile" type="file">
Cemetery answered 21/10, 2015 at 7:35 Comment(4)
1st, you're navigating to URL, but declared DestURL so the code should be: WebBrowser.Navigate DestURL. 2nd, look at the HTML source. The file selection box at that URL is in an iframe, so the input is really called fileUpload and resides at free-online-ocr.com/upload.aspx. Other controls on that page are programmatically created and hidden (eg __EVENTVALIDATION) and likely exist solely to prevent scripted automation of their free service. It may be that instead of sending the file as if a button were pressed, you may want to investigate automating the file selection process.Diwan
I looked at this again, and you have another issue. The link (OCR Site) in your description is to newocr.com, but the link in your code is to free-online-ocr.com. That makes it unclear which site you're actually trying to interface with and the code is drastically different depending on which site you actually intend to automate. Is this just some link building scheme for search engine rankings, or do you need to clean up your post?Diwan
its newocr.com, I did noticed that and reconfigured the code accordingly before I posted. sorry I used the wrong OCR Site here.Cemetery
wqweto.wordpress.com/2011/07/12/…Quintain
C
2

You can use ScriptUtils.ASPForm to accept uploaded files in ASP. ScriptUtils.ASPForm contains hi-performance, low resources consumption algorithm which can accept up to 2GB of data.

  1. There are some steps to upload file using http and multipart/form-data document. First of all we have to read file from a disk. We can use Scripting.FileSystemObject to read text data, or ADODB.Stream to read any file. The GetFile function does the work using ADODB.Stream.

  2. The second task we need to complete is a build of multipart/form-data document. The document contains from several fields separated by boundary. Each of the fields has its own header, which contains information about field name, file name and content-type of the source file. ADO Recordset object has a great method AppendChunk, which lets you join parts of multipart/form-data document (open boundary + headers + file contents + close boundary). You can see the code in BuildFormData function.

  3. Last task is send the multipart/form-data document as a post request to server with multipart/form-data Content-Type header. We can use at least two object to send POST request - XMLHttp or InternetExplorer. This script uses Navigate method of InternetExplorer.Application object. You can see the code in IEPostBinaryRequest function

please look into the below link for more information.

http://www.motobit.com/tips/detpg_uploadvbsie/

GetFile method is converting the file to UTF-8. Pdf will have more than 128 byte, you need to convert it to multi byte string

'Converts OLE string To multibyte stringFunction StringToMB(S)
  Dim I, B
  For I = 1 To Len(S)
    B = B & ChrB(Asc(Mid(S, I, 1)))
  Next
  StringToMB = B End Function

Please refer this page

http://www.mrexcel.com/forum/excel-questions/861695-using-xmlhttp-upload-file-api.html#post4192153

Coverlet answered 24/10, 2015 at 5:37 Comment(12)
Thank you so much, maybe you could elaborate a bit further regarding this?Cemetery
Thank you so much, but how can you but how can you send a multibyte data to the web browser?Cemetery
The link which i have provided contains detail solution.Coverlet
I am using the code from the link given in the link you sent me -> link, but the file still isn't getting uploaded.Cemetery
@R3uK Could you plz help adhil in this.Coverlet
Does anyone have an answer?Cemetery
@newjenn : I already offered the bounty, so I won't spend a lot of time on this (and I've never worked with this, I'm just interested to see how that could work). If you want the bounty, edit your answer to be more detailed or directly applied to the OP question so that he can understand. Have you a working solution? Because this not a "link only question" (flag qualification), but it is not really detailed either! Good luck with this! ;)Kasiekask
@Kasiekask I asked because i thought you knew the answer. Hope for the best. I am also don't know the exact solution.Coverlet
@newjenn : I don't know the exact, I might arrive to it with some work, but I'm pretty limited on time. The bounty is almost over, if you want the 50 points, please try to elaborate more (there is also a link that was post into the OP comments). good luck!Kasiekask
@Kasiekask I try to be elaborate. Hope some one get the infomtion and provide complete solution.Coverlet
@Kasiekask you are generous. ThanksCoverlet
Any body have complete solution? It look like example from http://www.motobit.com/tips/detpg_uploadvbsie/ do not work.Ameline
Y
0

I've spent several days experimenting with the same technique - using the Navigate method of the InternetExplorer.Application COM interface to upload a file.
The documentation for Navigate indicates that specifying the postdata parameter will trigger an HTTP POST, but in my experience the Content-Type is also a determining factor. Using Fiddler I found that it was consistently sending GET HTTP method instead of POST when Content-Type = multipart/form-data.

Sending the GET verb will tell the server to ignore any form data, and only process the URI.

This page indicates he had some success with the XMLHTTP object that allows finer control over the HTTP request. Here's some Powershell code that demonstrates this technique:

$http = (New-Object -ComObject "MSXML2.XMLHTTP") 
$http.Open("POST",$DestURL,$false)
$http.SetRequestHeader("Content-Type", "multipart/form-data; boundary=" + $boundary)
$http.Send($PostData) 
Yellowknife answered 3/1, 2017 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.