Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

file upload gives invalid procedure call on Win 2003

Status
Not open for further replies.

POSAPAY

IS-IT--Management
Jul 27, 2001
192
HU
Hi All,

Hoping someone could point me in the right direction here.
I moved a classic asp website from an old WinNT4 to Windows2003 server, and the good old asp file upload doesn't work now for some reason.

The error I get is: "Invalid procedure call or argument"

The code is:
Code:
Set oFS = Server.CreateObject("Scripting.FileSystemObject")
If Not oFS.FolderExists(sPath) Then Exit Sub

Set oFile = oFS.CreateTextFile(sPath & FileName, True)
		
For nIndex = 1 to LenB(FileData)
  oFile.Write Chr(AscB(MidB(FileData,nIndex,1)))
Next

oFile.Close

It does create a file, but no data in it.
The error line is the one starting with "oFile.Write..."

I've been trying this and that for two weeks now, and can't come up with an answer or a more narrow reason behind the error message.

Anyone with any ideas? perhaps a function/method no longer supported in Win2k3?

Thnx,
-Peter
 
[0] The way the octet stream got saved to file can work for a limited subset of data as binary. For quite a bit of more general data such images or else, it won't work and will fail to handle some control characters...

[1] If in case some general file be uploaded to server, it would be better handled by stream object (of adodb). Like this.
[tt]
[green]'givens:
' FileData (byte array)
' sFile (path including trailing backslash)
' FileName[/green]

set ostream=server.createobject("adodb.stream")
with ostream
.type=1 'adTypeBinary=1
.open
.write FileData
.position=0
.savetofile sFile & FileName, 2 'adSaveCreateOverWrite=2
.flush
.close
end with
set ostream=nothing
[/tt]
 
Hi tsuji,
Thanks for your help, but after implementing it, I'm now getting this error:

"ADODB.Stream error '800a0bb9'

Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another. "

What does this mean?
-peter
 
[2] What would be data type of FileData? In order for the original post to work at least partially, it should be Byte().
[tt] response.write typename(FileData) & "<br />"[/tt]
 
tsuji,

the response I got is: String

 
[3] If that is of type String, then the device of chr(ascb(midb())) in the original post is even more misguided. In the case the string is already loaded in the memory buffer, you can read it and save to a file of selected encoding, say utf-8, hereinbelow, because the range of characters is much uncertain in the internet arena and it is better not to get caught in the area.
[tt]
[green]'givens:
' FileData (String type)
' sFile (path including trailing backslash)
' FileName[/green]

set ostream=server.createobject("adodb.stream")
with ostream
.type=2 'adTypeText=2
.open
.writetext FileData 'opt default adWriteChar=0
.position=0
.charset="UTF-8"
.savetofile sFile & FileName, 2 'adSaveCreateOverWrite=2
.close
end with
set ostream=nothing
[/tt]
 
Ok, this change did not create an error, but I'm uploading a jpg, and once uploaded, I try to view it on a webpage and the file seems to be corrupt.

To avoid anything auto linking, I'll break it into two pieces here:
The domain...

the path and the file...
/pictures/6846.jpg

I'm not sure where the uploaded file's data goes haywire, but something is way off. I looked at the original file and the uploaded file by notepad and they look very different too.

the uploaded file on the server in wordpad starts with:
Code:
ÿþÿØÿà  
://ns.adobe.com/xap/1.0/mm/'>

I'm using the upload.asp code of:
Code:
' File:	  Upload.asp
' Author: Jacob "Beezle" Gilley
 
There is no point just to avoid error message. That is never the purpose of my posts. The stream object is operated as I posted. The rest, in particular, the other people's script, I cannot deal for them, and that even their script is correct, millions of ways to use it wrong. If you have your script to post, I can, no promise, try to help, otherwise, no.
 
Furthermore, a jpg file into a string? That sound like dreaming.
 
Right, sorry.. here is the entire code of upload.asp:

Code:
<%
'***************************************
' File:	  Upload.asp
' Author: Jacob "Beezle" Gilley
' Email:  avis7@airmail.net
' Date:   12/07/2000
' Comments: The code for the Upload, CByteString, 
'			CWideString	subroutines was originally 
'			written by Philippe Collignon...or so 
'			he claims. Also, I am not responsible
'			for any ill effects this script may
'			cause and provide this script "AS IS".
'			Enjoy!
'****************************************

Class FileUploader
	Public  Files
	Private mcolFormElem

	Private Sub Class_Initialize()
		Set Files = Server.CreateObject("Scripting.Dictionary")
		Set mcolFormElem = Server.CreateObject("Scripting.Dictionary")
	End Sub
	
	Private Sub Class_Terminate()
		If IsObject(Files) Then
			Files.RemoveAll()
			Set Files = Nothing
		End If
		If IsObject(mcolFormElem) Then
			mcolFormElem.RemoveAll()
			Set mcolFormElem = Nothing
		End If
	End Sub

	Public Property Get Form(sIndex)
		Form = ""
		If mcolFormElem.Exists(LCase(sIndex)) Then Form = mcolFormElem.Item(LCase(sIndex))
	End Property

	Public Default Sub Upload()
		Dim biData, sInputName
		Dim nPosBegin, nPosEnd, nPos, vDataBounds, nDataBoundPos
		Dim nPosFile, nPosBound

		biData = Request.BinaryRead(Request.TotalBytes)
		nPosBegin = 1
		nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(13)))
		
		If (nPosEnd-nPosBegin) <= 0 Then Exit Sub
		 
		vDataBounds = MidB(biData, nPosBegin, nPosEnd-nPosBegin)
		nDataBoundPos = InstrB(1, biData, vDataBounds)
		
		Do Until nDataBoundPos = InstrB(biData, vDataBounds & CByteString("--"))
			
			nPos = InstrB(nDataBoundPos, biData, CByteString("Content-Disposition"))
			nPos = InstrB(nPos, biData, CByteString("name="))
			nPosBegin = nPos + 6
			nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(34)))
			sInputName = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
			nPosFile = InstrB(nDataBoundPos, biData, CByteString("filename="))
			nPosBound = InstrB(nPosEnd, biData, vDataBounds)
			
			If nPosFile <> 0 And  nPosFile < nPosBound Then
				Dim oUploadFile, sFileName
				Set oUploadFile = New UploadedFile
				
				nPosBegin = nPosFile + 10
				nPosEnd =  InstrB(nPosBegin, biData, CByteString(Chr(34)))
				sFileName = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
				oUploadFile.FileName = Right(sFileName, Len(sFileName)-InStrRev(sFileName, "\"))

				nPos = InstrB(nPosEnd, biData, CByteString("Content-Type:"))
				nPosBegin = nPos + 14
				nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(13)))
				
				oUploadFile.ContentType = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
				
				nPosBegin = nPosEnd+4
				nPosEnd = InstrB(nPosBegin, biData, vDataBounds) - 2
				oUploadFile.FileData = MidB(biData, nPosBegin, nPosEnd-nPosBegin)
				
				If oUploadFile.FileSize > 0 Then Files.Add LCase(sInputName), oUploadFile
			Else
				nPos = InstrB(nPos, biData, CByteString(Chr(13)))
				nPosBegin = nPos + 4
				nPosEnd = InstrB(nPosBegin, biData, vDataBounds) - 2
				If Not mcolFormElem.Exists(LCase(sInputName)) Then mcolFormElem.Add LCase(sInputName), CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
			End If

			nDataBoundPos = InstrB(nDataBoundPos + LenB(vDataBounds), biData, vDataBounds)
		Loop
	End Sub

	'String to byte string conversion
	Private Function CByteString(sString)
		Dim nIndex
		For nIndex = 1 to Len(sString)
		   CByteString = CByteString & ChrB(AscB(Mid(sString,nIndex,1)))
		Next
	End Function

	'Byte string to string conversion
	Private Function CWideString(bsString)
		Dim nIndex
		CWideString =""
		For nIndex = 1 to LenB(bsString)
		   CWideString = CWideString & Chr(AscB(MidB(bsString,nIndex,1))) 
		Next
	End Function
End Class

Class UploadedFile
	Public ContentType
	Public FileName
	Public FileData
	
	Public Property Get FileSize()
		FileSize = LenB(FileData)
	End Property
	
	Public Sub SaveToDisk(sPath,NewFileName)
		Dim oFS, oFile
		Dim nIndex
		Dim Data1, Data2, Data3
	    FileName = NewFileName
		If sPath = "" Or FileName = "" Then Exit Sub
		If Mid(sPath, Len(sPath)) <> "\" Then sPath = sPath & "\"
	
		Set oFS = Server.CreateObject("Scripting.FileSystemObject")
		If Not oFS.FolderExists(sPath) Then Exit Sub
		 'If oFS.FileExists(sPath & FileName) Then Exit Sub

		  dim ostream
		  set ostream=server.createobject("adodb.stream")
		  with ostream
  		  .type=2  'adTypeText=2
  		  .open
  		  .writetext FileData  'opt default adWriteChar=0
  		  .position=0
  		  .charset="UTF-8"
  		  '.savetofile sFile & FileName, 2  'adSaveCreateOverWrite=2
  		  .savetofile sPath & FileName, 2  'adSaveCreateOverWrite=2
  		  .close
		  end with
		  set ostream=nothing

	End Sub
	
	
	Public Sub SaveToDatabase(ByRef oField)
		If LenB(FileData) = 0 Then Exit Sub
		
		If IsObject(oField) Then
			oField.AppendChunk FileData
		End If
	End Sub

End Class
%>

A second file called uploader.asp initiates it all with partial code:
Code:
Dim picturespath

  picturespath = "D:\Inetpub\pictures\"

Dim formaction
Dim showuploadform
Dim Errormessage
Dim Uploader, File
Set Uploader = New FileUploader
' This starts the upload process
Uploader.Upload()

'******************************************
' Use [FileUploader object].Form to access 
' additional form variables submitted with
' the file upload(s). (used below)
'******************************************
formaction = lcase(Uploader.Form("formaction"))

showuploadform = true
if formaction = "upload" then
  ' Check if any files were uploaded
  If Uploader.Files.Count = 0 Then
	Response.Write "File not uploaded."
  Else
	' Loop through the uploaded files
   For Each File In Uploader.Files.Items

	' Save the file
	if Uploader.Form("id") <> "" then
	  dim NewFileName
	  NewFileName = Uploader.Form("id") & ".jpg"
	  File.SaveToDisk picturespath, NewFileName
...
 
[0] I have taken a look at the "class" script. I appreciate the diligent effort invested into it by the author, but, by the mere detection of its use of filesystemobject, I fear the class won't help for binary file upload. That is too bad.

[1] I can show you what I put together quickly and to the point of file upload mechanism. It works for both text and binary files upload with cleaner logic to my liking. It only saves the upload files (can be more than one file). The normal form data are not parsed. Hence, it only deals with file upload. Slight elaboration can cover regular form data no problem, but, I exclude that as it is much easier technically.

[2] Here is the asp that takes care of the persisting the uploaded files. Just make a html page with multipart/form-data posting to it with inputs of type="file" for file upload.
[tt]
<%
posteddata=request.binaryread(request.totalbyte)
shex=&quot;&quot;
for i=0 to ubound(posteddata)
shex=shex &amp; chr(ascb(midb(posteddata,i+1,1)))
next

set rx=new regexp

with rx
.pattern=&quot;^[^\x0D]*?(?=\x0D)&quot;
end with
sboundary=null
if rx.test(shex) then
sboundary=rx.execute(shex)(0)
end if
if isnull(sboundary) then
response.write &quot;post data is not multipart/form-data&quot; &amp; &quot;<br />&quot;
response.end
end if

with rx
.global=true 'to match all, multiple file upload
.pattern=&quot;(&quot; &amp; sboundary &amp; &quot;)&quot; &amp; &quot;(\x0D\x0AContent-Disposition:.+\x0D\x0A)((Content-Type:.+\x0D\x0A)?\x0D\x0A)([\s\S]*?)(?=\x0D\x0A\1)&quot;
end with

'condition to be fulfilled for multipart/form-data
if rx.test(shex) then
set ostream=server.createobject(&quot;adodb.stream&quot;)
set cm=rx.execute(shex)
for each m in cm
sprefix=m.submatches(0) &amp; m.submatches(1) &amp; m.submatches(2)
suploadeddatahex=m.submatches(4)
set rx_controldata=new regexp
with rx_controldata
.pattern=&quot;Content-Type:&quot;
end with
if rx_controldata.test(sprefix) then
bContentType=true
with rx_controldata
.pattern=&quot;name=&quot;&quot;(.+?)&quot;&quot;&quot;
end with
if rx_controldata.test(sprefix) then
controlname=rx_controldata.execute(sprefix)(0).submatches(0)
else
controlname=&quot;undetermined&quot;
end if
with rx_controldata
.pattern=&quot;filename=&quot;&quot;(.+?)&quot;&quot;&quot;
end with
if rx_controldata.test(sprefix) then
filename=rx_controldata.execute(sprefix)(0).submatches(0)
else
filename=&quot;&quot;
end if
else
bContentType=false
end if
set rx_controldata=nothing
if bContentType then
set rx2=new regexp
with rx2
.pattern=sprefix
end with
datastart=null
if rx2.test(shex) then
set cm2=rx2.execute(shex)
startpos=cm2(0).firstIndex
prefixlen=len(sprefix)
datastart=startpos+prefixlen
end if

dataend=null
if len(suploadeddatahex)<>&quot;&quot; then
datalen=len(suploadeddatahex)
if not isnull(datastart) then
dataend=datastart+datalen
end if
else
'do nothing
end if

if (not isnull(datastart)) and (not isnull(dataend)) and filename<>&quot;&quot; then
if dataend>datastart then
with ostream
.type=1 'adTypeBinary
.open
.write posteddata
.position=datastart
octetstr=.read(dataend-datastart)
.close
.type=1
.open
.write octetstr
.flush
.position=0
.savetofile server.mappath(outfilename),2
.close
end with
end if
end if
end if 'bcontenttype
next 'matches
set ostream=nothing
else
'response.write &quot;post data is not multipart/form-data&quot; &amp; &quot;<br />&quot;
end if

response.end
%>
[/tt]
 
re-listing
[2.1] Due to the forum formatting artifact, code between <% and %> is blown up! Here is a relisting, and I deliberately take out the <% and %> wrapping signs.
[tt]
posteddata=request.binaryread(request.totalbyte)

shex=""
for i=0 to ubound(posteddata)
shex=shex & chr(ascb(midb(posteddata,i+1,1)))
next

set rx=new regexp
with rx
.pattern="^[^\x0D]*?(?=\x0D)"
end with
sboundary=null
if rx.test(shex) then
sboundary=rx.execute(shex)(0)
end if
if isnull(sboundary) then
response.write "post data is not multipart/form-data" & "<br />"
response.end
end if

with rx
.global=true 'to match all, multiple file upload
.pattern="(" & sboundary & ")" & "(\x0D\x0AContent-Disposition:.+\x0D\x0A)((Content-Type:.+\x0D\x0A)?\x0D\x0A)([\s\S]*?)(?=\x0D\x0A\1)"
end with

'condition to be fulfilled for multipart/form-data
if rx.test(shex) then
set ostream=server.createobject("adodb.stream")
set cm=rx.execute(shex)
for each m in cm
sprefix=m.submatches(0) & m.submatches(1) & m.submatches(2)
suploadeddatahex=m.submatches(4)
set rx_controldata=new regexp
with rx_controldata
.pattern="Content-Type:"
end with
if rx_controldata.test(sprefix) then
bContentType=true
with rx_controldata
.pattern="name=""(.+?)"""
end with
if rx_controldata.test(sprefix) then
controlname=rx_controldata.execute(sprefix)(0).submatches(0)
else
controlname="undetermined"
end if
with rx_controldata
.pattern="filename=""(.+?)"""
end with
if rx_controldata.test(sprefix) then
filename=rx_controldata.execute(sprefix)(0).submatches(0)
else
filename=""
end if
else
bContentType=false
end if
set rx_controldata=nothing
if bContentType then
set rx2=new regexp
with rx2
.pattern=sprefix
end with
datastart=null
if rx2.test(shex) then
set cm2=rx2.execute(shex)
startpos=cm2(0).firstIndex
prefixlen=len(sprefix)
datastart=startpos+prefixlen
end if

dataend=null
if len(suploadeddatahex)<>"" then
datalen=len(suploadeddatahex)
if not isnull(datastart) then
dataend=datastart+datalen
end if
else
'do nothing
end if

if (not isnull(datastart)) and (not isnull(dataend)) and filename<>"" then
if dataend>datastart then
with ostream
.type=1 'adTypeBinary
.open
.write posteddata
.position=datastart
octetstr=.read(dataend-datastart)
.close
.type=1
.open
.write octetstr
.flush
.position=0
.savetofile server.mappath(outfilename),2
.close
end with
end if
end if
end if 'bcontenttype
set ostream=nothing
next 'matches
else
'response.write "post data is not multipart/form-data" & "<br />"
end if

response.end
[/tt]
 
amendment
Upon re-read what I posted, there is a typo (of inconsistent name of variable). The corresponding line should be read like this.
[tt] [red]'[/red].savetofile server.mappath(outfilename),2
.savetofile server.mappath([red]filename[/red]),2
[/tt]
 
Hi Tsuji,
Just got around to trying it, but can't tell where the file path is coming from in your code.
I'm more use to classic ASP, so forgive me if I missed something obvious.

I figure the "filename" should include the path? or is it inherited from somewhere? How would I set that?
Thanks,
-Peter
 
[3] The filename is the script I shown is parsed from these lines.
[tt]
if rx_controldata.test(sprefix) then
filename=rx_controldata.execute(sprefix)(0).submatches(0)
else
filename=""
end if
[/tt]
[3.1] It works like this. If the file upload is from the client m/c of path:
[tt] c:\xyz\pqr.ext[/tt]
The filename so parsed would look like this:
[tt] filename is assigned "pqr.ext"[/tt]
And if the asp (thisasp.asp, say) is located here:
[tt] x:\inetpub\wwwroot\abc\thisasp.asp[/tt]
the persisted file will be sitting in the same directory as the asp (thisasp.asp) with the name as the client file's name:
[tt] x:\inetpub\wwwroot\abc\pqr.ext[/tt]

[3.2] You can sure make any change you desire to make at the place of the quoted block (and that's my outfilename originally is designed for but eventually I decided to simplify the script and tool it out.) Hope that's clear.
 
Now I get this error:

Microsoft VBScript runtime error '800a01b6'

Object doesn't support this property or method: 'request.totalbyte'
 
amendment2

>[self]posteddata=request.binaryread(request.totalbyte)
Sorry, that is my typo.
[tt]posteddata=request.binaryread(request.totalbyte[red]s[/red])[/tt]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top