Being an FTP Client (Perl Cookbook, 2nd Edition)

## 18.2. Being an FTP Client

### 18.2.1. Problem

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

### 18.2.2. Solution

Use the Net::FTP module:

>     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";

### 18.2.3. 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 the 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, 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 select 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, anonymous login is attempted (username `anonymous`, password `-anonymous@`). 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, respectively. 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` on error.

To fetch a file, use the `get` method, which returns the local filename, or `undef` on 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` on error):

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

Pass `get` an optional third argument, representing 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. 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 empty directories on the local machine. To create all directories up to the given directory, pass a true second argument to `mkdir`. For instance, to create /pub, /pub/gnat, and /pub/gnat/perl directories, 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; otherwise, it returns `undef`.

The `ls` and `dir` methods retrieve 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. In list context, these methods return the list of lines returned by the server. In scalar context, they return a reference to an array containing those lines.

>     @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 finish 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.

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/.

### 18.2.4. See Also

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

Copyright © 2003 O'Reilly & Associates. All rights reserved.