Recipe 18.2. Being an FTP Client
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:44:59Z

#

| Chapter 18 Internet Services |

## 18.2. Being an FTP Client

### Problem

You want to connect to an FTP server and get or put files. You might want to automate the one-time transfer of many files or automatically mirror an entire section of an FTP server, for example.

### Solution

Use the CPAN module Net::FTP:

    use Net::FTP;

    $ftp = Net::FTP->new("ftp.host.com")    or die "Can't connect: $@\n";
    $ftp->login($username, $password)       or die "Couldn't login\n";
    $ftp->cwd($directory)                   or die "Couldn't change directory\n";
    $ftp->get($filename)                    or die "Couldn't get $filename\n";
    $ftp->put($filename)                    or die "Couldn't put $filename\n";

### Discussion

Using the Net::FTP module is a three-part process: connect to a server, identify and authenticate yourself, and transfer files. All interaction with the FTP server happens through method calls on a Net::FTP object. If an error occurs, methods return `undef` in scalar context or an empty list in list context.

The connection is established with the `new` constructor. If an error occurs, `$@` is set to an error message and `new` returns `undef`. The first argument is the hostname of the FTP server and is optionally followed by named options:

    $ftp = Net::FTP->new("ftp.host.com",
                         Timeout => 30,
                         Debug   => 1)
        or die "Can't connect: $@\n";

The `Timeout` option gives the number of seconds all operations wait before giving up. `Debug` sets the debugging level (non-zero sends copies of all commands to STDERR). `Firewall` takes a string as an argument, specifying the machine acting as an FTP proxy. `Port` lets you specify an alternate port number (the default is 21, the standard port for FTP). Finally, if the `Passive` option is set to true, all transfers are done passively (some firewalls and proxies require this). The `Firewall` and `Passive` options override the environment variables `FTP_FIREWALL` and `FTP_PASSIVE`.

Having connected, the next step is to authenticate. Normally, you'll want to call `login` with up to three arguments: username, password, and account.

    $ftp->login()
        or die "Couldn't authenticate.\n";

    $ftp->login($username)
        or die "Still couldn't authenticate.\n";

    $ftp->login($username, $password)
        or die "Couldn't authenticate, even with explicit username
                and password.\n";

    $ftp->login($username, $password, $account)
        or die "No dice.  It hates me.\n";

If you call `login` with no arguments, Net::FTP uses the Net::Netrc module to find settings for the host you've connected to. If none are found there, anonymous login is attempted (username `anonymous`, password `username@hostname`). If no password is given and the username `anonymous` is used, the user's mail address is supplied as the password. The optional account argument is not used on most systems. If the authentication fails, `login` returns `undef`.

Once authenticated, the usual FTP commands are available as methods called on your Net::FTP object. The `get` and `put` methods fetch and send files. To send a file, use:

    $ftp->put($localfile, $remotefile)
        or die "Can't send $localfile: $!\n";

If you omit the second argument, the remote file will have the same name as the local file. You can also send from a filehandle (in which case the remote filename must be given as the second argument):

    $ftp->put(*STDIN, $remotefile)
        or die "Can't send from STDIN: $!\n";

If the transfer is interrupted, the remote file is not automatically deleted. The `put` method returns the remote filename if it succeeded, or `undef` if an error occurred.

To fetch a file, use the `get` method, which returns the local filename, or `undef` if there was an error:

    $ftp->get($remotefile, $localfile)
        or die "Can't fetch $remotefile : $!\n";

You can also `get` into a filehandle, in which case the filehandle is returned (or `undef` if there was an error):

    $ftp->get($remotefile, *STDOUT)
        or die "Can't fetch $remotefile: $!\n";

Pass `get` an optional third argument, an offset into the remote file, to begin the transfer at that offset. Received bytes are appended to the local file.

The `type` method changes the file translation mode. Pass it a string (`"A"`, `"I"`, `"E"`, or `"L"`) and it will return the previous translation mode. The `ascii`, `binary`, `ebcdic`, and `byte` methods call `type` with the appropriate string. If an error occurs (the FTP server does not do EBCDIC, for example), `type` and its helper methods return `undef`.

Use `cwd($remotedir)` and `pwd` to set and fetch the current remote directory. They both return true if successful, false otherwise. If you `cwd("..")`, the `cdup` method is called to change the directory to the parent of the current directory. Call `cwd` without an argument to change to the root directory.

    $ftp->cwd("/pub/perl/CPAN/images/g-rated");
    print "I'm in the directory ", $ftp->pwd(), "\n";

`mkdir($remotedir)` and `rmdir($remotedir)` make and delete directories on the remote machine. You have the built-in `mkdir` and `rmdir` functions to make and delete directories on the local machine. To create all directories up to the given directory, pass a true second argument to `mkdir`. For instance, if you want to make /pub, /pub/gnat, and /pub/gnat/perl, say:

       $ftp->mkdir("/pub/gnat/perl", 1)
        or die "Can't create /pub/gnat/perl recursively: $!\n";

If `mkdir` succeeds, the full path to the newly created directory is returned. If it fails, `mkdir` returns `undef`.

The `ls` and `dir` methods get a list of files in a remote directory. Traditionally, `dir` gives you a more verbose listing than `ls`, but neither has a standard format. Most Unix FTP servers return the output of ls and ls -l respectively, but you can't guarantee that behavior from every FTP server. These methods, in list context, return the list of lines returned by the server. In scalar context, they return a reference to an array.

    @lines = $ftp->ls("/pub/gnat/perl")
        or die "Can't get a list of files in /pub/gnat/perl: $!";
    $ref_to_lines = $ftp->dir("/pub/perl/CPAN/src/latest.tar.gz")
        or die "Can't check status of latest.tar.gz: $!\n";

When you're done and want to close up gracefully, use the `quit` method:

    $ftp->quit()    or warn "Couldn't quit.  Oh well.\n";

Other methods rename, change ownership and permissions of remote files, check the size of the remote file, and so on. Read the Net::FTP documentation for details.

If you want to mirror files between machines, use the excellent mirror program written in Perl by Lee McLoughlin. Look for it on the Web at http://sunsite.doc.ic.ac.uk/packages/mirror/.

### See Also

Your system's ftp (1) and ftpd (8) manpages (if you have them); the documentation for the Net::FTP module from CPAN

18.1. Simple DNS Lookups |  | 18.3. Sending Mail