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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

I'm trying to copy a file from my c

Status
Not open for further replies.

Steve Meyerson

Programmer
Sep 17, 2020
320
US
I'm trying to copy a file from my computer to my web host's server using FtpPut.prg (shown below for reference).

The debugger with SET STEP ON shows the connection is made ok but the transfer fails at
Code:
   IF FtpPutFile(hftpSession, lcSource,;
         lcTarget, lnXFerType, 0) = 1
      WAIT WINDOW lcSource + ' transferred.' TIMEOUT 2
   ENDIF

My aim is to transfer files in my VFP9 program (exe) as simple (and fast) as possible without additional installation(s) required by the users. Most files will be pdf's (.5-1 MB). I would appreciate any help. TIA.

Steve

Code:
*... FTPPut.PRG ...*

*PARAMETERS lcHost, lcUser, lcPassword, lcSource, lcTarget, lnXFerType

*.................................................................................
*:   Usage: DO ftpput WITH ;
*:         'ftp.host', 'name', 'password', 'source.file', 'target.file'[, 1 | 2]
*:
*:  Where:  lcHost     = Host computer IP address or name
*:          lcUser     = user name - anonymous may be used
*:          lcPassword = password
*:          lcSource   = source file name (remote)
*:          lcTarget   = target file name (local)
*:          lnXFerType = 1 (default) for ascii, 2 for binary
*.................................................................................
set step on
************** My parameters
lcHost     = 'gator4247.hostgator.com'
lcUser     = 'smeyerson'
lcPassword = 'MyPasswordxxx'
lcSource   = 'e:\TextFile.txt'
lcTarget   = '/home2/smeyerson/MyFolder'

DECLARE INTEGER InternetOpen IN wininet.DLL;
   STRING  sAgent,;
   INTEGER lAccessType,;
   STRING  sProxyName,;
   STRING  sProxyBypass,;
   STRING  lFlags

DECLARE INTEGER InternetCloseHandle IN wininet.DLL INTEGER hInet

DECLARE INTEGER InternetConnect IN wininet.DLL;
   INTEGER hInternetSession,;
   STRING  lcHost,;
   INTEGER nServerPort,;
   STRING  lcUser,;
   STRING  lcPassword,;
   INTEGER lService,;
   INTEGER lFlags,;
   INTEGER lContext

DECLARE INTEGER FtpPutFile IN wininet.DLL;
   INTEGER hConnect,;
   STRING  lpszLocalFile,;
   STRING  lpszNewRemoteFile,;
   INTEGER dwFlags,;
   INTEGER dwContext

PUBLIC hOpen, hftpSession

lcHost     = ALLTRIM(lcHost)
lcUser     = ALLTRIM(lcUser)
lcPassword = ALLTRIM(lcPassword)
lcSource   = ALLTRIM(lcSource)
lcTarget   = ALLTRIM(lcTarget)
lnXFerType = 1

IF connect2ftp (lcHost, lcUser, lcPassword)
   WAIT WINDOW 'Transferring....' NOWAIT
   IF FtpPutFile(hftpSession, lcSource,;
         lcTarget, lnXFerType, 0) = 1
      WAIT WINDOW lcSource + ' transferred.' TIMEOUT 2
   ENDIF

   = InternetCloseHandle (hftpSession)
   = InternetCloseHandle (hOpen)
ENDIF

*..................... connect2ftp .........................................
*...  Makes sure there is actually a valid connection to the host
FUNCTION  connect2ftp (lcHost, lcUser, lcPassword)   
   * open access to Inet functions    
   hOpen = InternetOpen ("vfp", 1, 0, 0, 0)    

   IF hOpen = 0    
      ? "Unable to get access to WinInet.Dll"   
      RETURN .F.   
   ENDIF   

   *... The first '0' says use the default port, usually 21.
   hftpSession = InternetConnect (hOpen, lcHost,;
      0, lcUser, lcPassword, 1, 0, 0)   &&... 1 = ftp protocol

   IF hftpSession = 0    
   * close access to Inet functions and exit    
      = InternetCloseHandle (hOpen)    
      ? "ftp " + lcHost + " is not available"   
      RETURN .F.   
   ELSE    
      ? "Connected to " + lcHost
   ENDIF    
RETURN .T.   
RETURN
*** End of ftpPut.PRG ****************************
 
Steve,

check that user has write & delete permissions into that folder. You may also need passive FTP.

Take a look at chilkat's ftp component ... apart from anything else it has good error reporting.

And there is west wind which will also do much of the heavy lifting. wwFTP has code you might borrow to get the last error using the wininet api.

hth

n
 
Thanks, Nigel. I do have read/write/delete permission for the folders on the site.

It looks to me Chilkat or WestWind might be overkill. All I want to do is send & retrieve files on the site without users having to buy or install another product. FtpPut.prg seems like a solution. I'm wondering if anyone has used it successfully and how they did it. Thanks.

Steve

 
WININET is sensitive to misuse of handles. When InternetOpen already created a handle InternetCloseHandle first needs to close that before you can use InternetOpen again. Therefore when you experimented a lot before you got the code to work up to this point, the problem might simply disappear when you restart the system, really shut down and restart, not just restart VFP.


Chriss
 
Chris,
Restart no help.
hopen = 13369348
hfptSession = 13369352
Same values on 2nd (consecutive) run (no restart).
Is this normal?

Steve
 
Your code works for me (obviously changing the FTP server and credentials) and file related variables.

It's just lcTarget must be the target file name, not just the target folder. And in my case just the file name transfers to the root directory FTP connects to and using ./subfolder/TextFile.txt I get it to that subfolder.



Chriss
 
Hi Steve,

You could take a look at WINSCP, it can be called by VFP because it can be controlled with command line options.
You can use SFTP too as most providers don’t allow FTP any more.

Regards, Gerrit
 
Chriss, thanks, I really appreciate that. That's a big help for me in figuring this thing out.

Thanks, Gerrit, I will look into those.

Steve
 
Gerrit still has a point, because while your code works for me a hosted FTP Sever, it may also be your counterpart FTP Server that limits this to work, as it requires a secure connection and while InternetConnect can establish an HTTPS connection, it can't do the similar thing for FTPS.




Chriss
 
Thanks, Chris. I've been busy and haven't tried Gerrit's suggestion yet, but I will. I'll let you know the result.
Steve
 
Guys,

Thanks for your help.
I downloaded WinSCP.
Tried both SFTP & FTP protocols.
Used same parameters as I did in PutFTP.prg.
Both protocols worked fine transferring files both ways.

However since users would have to download WinSCP (a task beyond some of them), I would still like to incorporate FTPPut & FTPGet into my program if I can get them to work. I'll keep trying.

BTW, Filezilla also worked for me a couple years ago (don't remember which protocol).

Steve


 
I would go for Binary transfer and as said the target needs to be the file name (relative path+file name), not just the path. You might have uploaded a file that is named the same as the path, but that may have clashed with the existing directory name.

Chriss
 
Chris,

Hostgator "help" said not to repeat file with target folder. Anyway I've tried it with & without file name (Text.txt). Same result.

By "binary", do you mean parameter lnXFerType=2 instead of 1? Tried that too.

Steve
 
Hi Steve,

I think there is a version of WinSCP you don’t have to install. So you could probably distribute this with your program or update and run it invisible without installing anything for WinSCP. Your users wouldn’t even notice this.

I haven’t tried this myself yet, but you can give it a try.

Regards, Gerrit
 
Gerrit & Chris,

I could not find a WinSCP version without an install. HOWEVER, I think I solved my problem (albeit with limited testing).

I was able to upload a pdf file to the server using just a command line in a Windows command window. Presumably, I could execute this in VFP with a RUN command (haven't tried it yet).

Instead of having to install WinSCP on user's computer, I may only have to add one file (WinSCP.exe) to my distribution. Here's how:

I uninstalled WinSCP. Before uninstalling, I saved a copy of WinSCP.exe in the main folder for my app. To my surprise, the command line still worked! I'm assuming a clean UNinstall after reboot.

FYI, here's the command line (w/o pw, etc.):

Code:
"E:\MyAppFolder\WinSCP.exe" /command "open sftp://username:password@servername.com" "put MyFile.pdf /targetPath/" "exit"

Thanks for your help!

Steve
 
Steve Meyerson said:
Hostgator "help" said not to repeat file with target folder.

Well, that's not a thing about the server, that's stated in the FtpPutFile API:

pszNewRemoteFile
Pointer to a null-terminated string that contains the name of the file to be created on the remote system.

This function might in turn use two FTP commonds on the connection, on to change into that directory and one to transfer the file, but the Windows API needs a full filename, path and filename.


Chriss
 
Chris said:
... but the Windows API needs a full filename, path and filename.

That makes sense to me since one might want to save the file with a different name on the server, although I haven't tried that (I'm new to this stuff).

Steve
 
Steve,

then try out
Code:
lcTarget="Filename.txt"

While that contradicts what I said last, it'll transfer the file to the root directory you connect to. As said earlier paths need to be relative to that. FTP connections always get you to a root folder from which you can change to subfolders. Notice you usually can't transfer files to parent folders by specifying ../ in the path, but since you might have files not for the web, usually the webroot is a subfolder of the FTP root folder.

Chriss
 
Chris said:
. FTP connections always get you to a root folder from which you can change to subfolders.

Not exactly sure if you mean file is always transferred to the server's root folder. If so, when I preface lcTarget with path to a subfolder on the server, it does go to the subfolder. I may misunderstand.

Other subject: In my previous post, I said I was able to transfer using WinSFP command line. Problem came up with long filenames & paths causing command line to go over 255 characters (string literal limit).
I tried breaking it up using the "open" command to connect, then the "put" command in the loop. But I couldn't find a way to use the "put" command by itself - the examples I found are not clear to me. Any suggestions (besides 'study harder')? Thanks.

Steve

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top