jonnyfolk has asked for the wisdom of the Perl Monks concerning the following question:

I am using the following code to back up some files from one server to another. The file in question is transferred okay to the correct folder, but a copy of the file is also placed in cgi-bin, which is a bit of a pain!

I'd be grateful if someone could let me know how to prevent this. I'm also looking for advice on how to develop the script to fetch all the files found in @lines

Thanks for your help.

#!/usr/bin/perl -w use strict; use Net::FTP; use CGI::Carp qw(fatalsToBrowser warningsToBrowser); my $home="mysite.com"; my $username="username"; my $password="password"; my $directory="data/edit"; my $filename="data.txt"; my $ftp = Net::FTP->new("$home") or die "Can't connect: 1 $@\n"; $ftp->login($username, $password) or die "Couldn't login - 1\n"; $ftp->cwd($directory) or die "Couldn't change direct +ory - 1\n"; $ftp->get($filename) or die "Couldn't get $filename + - 1\n"; my @lines = $ftp->ls("/data/edit"); $ftp->quit; print "Content-type: text/html\n\n"; &PUT($filename); #============ sub PUT { my $away="myothersite.com"; my $awayname="awayname"; my $awaypass="awaypass"; my $awaydir="data/edit"; my $ftp = Net::FTP->new("$away") or die "Can't connect: $@\n"; $ftp->login($awayname, $awaypass) or die "Couldn't login - 2\n"; $ftp->cwd($awaydir) or die "Couldn't change away dir +ectory - 2\n"; $ftp->put($filename) or die "Couldn't put $filename + - 2\n"; $ftp->quit; print "Your file, <br>$filename, <br> has been successfully uploaded.\ +n"; } #============ print "<br>@lines<br>";

Replies are listed 'Best First'.
Re: Net::ftp - copy of file in cgi-bin
by ChrisR (Hermit) on Oct 28, 2003 at 15:56 UTC
    I have never used Net::FTP but here is a shot in the dark. When you $ftp->get($filename), the file is being copied to the current directory of the machine running the script. Then when you $ftp->put($filename), the file gets copied to it's final destination. Taking a quick look at the docs for Net::FTP, I did not see a method to change the local directory. In a standard ftp client this would be lcd directoryname but this would still copy the file locally first. The one way around this would be to have either one ofthe servers run the script. That way you can get or put the files directly where you want them instead of having a third server involved to to do the transfer. In the scenario you posted, I think you will have to kill the file in your local directory after you put it using Net::FTP.

    As for your other question, I think that's an easy one. Just loop through your @lines array and get all the files. Then loop through it again and put all the files. If you can get rid ofthe third server in the scenario, you will only have to do the loop once. To go through the loop only once in your current scenario, you would have to have two instances of Net::FTP and use one to get and the other to put.

    Update
    Here's an example (untested though)
    #!/usr/bin/perl -w use strict; use Net::FTP; use CGI::Carp qw(fatalsToBrowser warningsToBrowser); my $home="mysite.com"; my $username="username"; my $password="password"; my $directory="data/edit"; my $filename="data.txt"; my $away="myothersite.com"; my $awayname="awayname"; my $awaypass="awaypass"; my $awaydir="data/edit"; print "Content-type: text/html\n\n"; my $ftp1 = Net::FTP->new("$home") or die "Can't connect: 1 $@\n"; $ftp1->login($username, $password) or die "Couldn't login - 1\n"; $ftp1->cwd($directory) or die "Couldn't change directory - 1\n"; my $ftp2 = Net::FTP->new("$away") or die "Can't connect: 2 $@\n"; $ftp2->login($awayname, $awaypass) or die "Couldn't login - 2\n"; $ftp2->cwd($awaydir) or die "Couldn't change away dir +ectory - 2\n"; my @lines = $ftp1->ls("/data/edit"); foreach (@lines) { $ftp1->get($filename)or die "Couldn't get $_\n"; $ftp2->put($filename) or die "Couldn't put $_\n"; print "Your file, <br>$_, has been successfully uploaded.\n"; } $ftp1->quit; $ftp2->quit; unlink @lines; # This should delete all the local copies of the files +in @lines exit;
      lcd is a typical client call when FTP'ing files, however, I don't think it is universal. I just checked the POD for Net::FTP and there does not appear to be a method to do an lcd. This script would probably run best if it could be set up as a cron job on either the sending or the receiving server although if this is not possible, then it would require a third location as a temporary stopping point. As ChrisR points out, you would need to remove the files from the middle point after you had succesfully put your files to the final destination.


      "Ex libris un peut de tout"
      Thanks very much for your interesting reply.

      I have put the script on the server onto which I am downloading the files. Based on my undertanding of the Net:: FTP docs the new file should be created in and identical path/$filename as the original, but in fact the file is only showing up in the cgi-bin. Obviously it is my misunderstanding but I would appreciate some help in unravelling this. (Obviously having got the files onto the server I can easily shift them to where I need them and clean up afterwards, but I would prefer to get this working to my satisfaction!).

      my $ftp = Net::FTP->new("$home") or die "Can't connect: 1 $@\n"; $ftp->login($username, $password) or die "Couldn't login - 1\n"; $ftp->cwd($directory) or die "Couldn't change direct +ory - 1\n"; $ftp->get($filename) or die "Couldn't get $filename + - 1\n"; $ftp->put($filename) or die "Couldn't put $filename +\n"; my @lines = $ftp->ls("/data/edit");
        According to the docs:
        The FTP protocol allows files to be sent to or fetched from the server. Each transfer involves a local file (on the client) and a remote file (on the server). In this module, the same file name will be used for both local and remote if only one is specified. This means that transferring remote file /path/to/file will try to put that file in /path/to/file locally, unless you specify a local file name.
        Update:
        After taking a closer look at the docs, I found:
        get ( REMOTE_FILE [, LOCAL_FILE , WHERE] )
        Get REMOTE_FILE from the server and store locally. LOCAL_FILE may be a filename or a filehandle. If not specified, the file will be stored in the current directory with the same leafname as the remote file.
        If WHERE is given then the first WHERE bytes of the file will not be transfered, and the remaining bytes will be appended to the local file if it already exists.
        Returns LOCAL_FILE, or the generated local file name if LOCAL_FILE is not given. If an error was encountered undef is returned.

        put ( LOCAL_FILE , REMOTE_FILE )
        Put a file on the remote server. LOCAL_FILE may be a name or a filehandle. If LOCAL_FILE is a filehandle then REMOTE_FILE must be specified. If REMOTE_FILE is not specified then the file will be stored in the current directory with the same leafname as LOCAL_FILE.
        Returns REMOTE_FILE, or the generated remote filename if REMOTE_FILE is not given.
        NOTE: If for some reason the transfer does not complete and an error is returned then the contents that had been transfered will not be remove automatically.
Re: Net::ftp - copy of file in cgi-bin
by jonnyfolk (Vicar) on Oct 28, 2003 at 20:19 UTC
    After much wrestling, mainly through my misunderstanding of the Net::FTP module, I have arrived at the following script, which does what I need. I post it here as 'closure' - in the hope that it may be useful to someone else... (multiple file downloads tomorrow :))
    #!/usr/bin/perl -w use strict; use Net::FTP; use CGI::Carp qw(fatalsToBrowser warningsToBrowser); my $home="mysite.com"; my $username="username"; my $password="password"; my $directory="data/edit"; my $filename="data.txt"; my $filename1="path/to/file/data.txt"; my $ftp = Net::FTP->new("$home") or die "Can't connect: 1 $@\n"; $ftp->login($username, $password) or die "Couldn't login - 1\n"; $ftp->cwd($directory) or die "Couldn't change direct +ory - 1\n"; $ftp->get($filename, $filename1) or die "Couldn't g +et $filename - 1\n"; my @lines = $ftp->ls("/data/edit"); $ftp->quit; print "Content-type: text/html\n\n"; print "<br>@lines<br>";
Re: Net::ftp - copy of file in cgi-bin
by Apocalypse (Initiate) on Oct 28, 2003 at 18:28 UTC
    Why not use something like FXP to send the files directly between the server?
    It's faster and saves the "middle-man" stuff...
    Look at the pasv_xfer command in the Net::FTP docs :)