AnyEvent-FTP
view release on metacpan or search on metacpan
lib/AnyEvent/FTP/Client.pm view on Meta::CPAN
Get the modification time of the remote file specified by C<$path>. This is an extension to the FTP standard
specified in RFC3659, and may not be implemented by older (or even newer) servers.
=head2 quit
$client->quit;
Send the FTP C<QUIT> command and close the connection to the remote server.
=head2 site
$client->site;
The C<site> method provides an interface to site specific FTP commands. Many
FTP servers will support an extended set of commands using the standard FTP
C<SITE> command. This command will not check to see if the site commands are
supported by the remote server, so it is up to you to determine if you can
really use these interfaces yourself.
=over 4
=item $client-E<gt>site-E<gt>microsoft
For commands specific to Microsoft's IIS FTP server.
See L<AnyEvent::FTP::Client::Site::Microsoft>.
=item $client-E<gt>site-E<gt>net_ftp_server
For commands specific to L<Net::FTPServer>.
See L<AnyEvent::FTP::Client::Site::NetFtpServer>.
=item $client-E<gt>site-E<gt>proftpd
For commands specific to proftpd.
See L<AnyEvent::FTP::Client::Site::Proftpd>.
=back
=head1 EXAMPLES
Here are some longer examples. They are also included with the
L<AnyEvent::FTP> distribution in its C<example> directory.
=head2 fget.pl
Given a URL to a file, this script will fetch the file and store it
on your local machine. If you use the C<-d> option you can see the
FTP commands and their responses as they happen.
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use 5.010;
use AnyEvent::FTP::Client;
use URI;
use URI::file;
use Term::ProgressBar;
use Term::Prompt qw( prompt );
use Getopt::Long qw( GetOptions );
use Path::Class qw( file );
my $debug = 0;
my $progress = 0;
my $active = 0;
GetOptions(
'd' => \$debug,
'p' => \$progress,
'a' => \$active,
);
my $remote = shift;
unless(defined $remote)
{
say STDERR "usage: perl fget.pl [ -d | -p ] [ -a ] remote";
say STDERR " where remote is a URL for a file on an FTP server";
say STDERR " and local is a local filename (optional) where to transfer it to";
say STDERR " -d (optional) prints FTP commands and responses";
say STDERR " -p (optional) displays a progress bar as the file uploads";
say STDERR " -a (optional) use active mode transfer";
exit 2;
}
$remote = URI->new($remote);
unless($remote->scheme eq 'ftp')
{
say STDERR "only FTP URLs are supported";
exit 2;
}
unless(defined $remote->password)
{
$remote->password(prompt('p', 'Password: ', '', ''));
say '';
}
do {
my $from = $remote->clone;
$from->password(undef);
say "SRC: ", $from;
};
my @path = split /\//, $remote->path;
my $fn = pop @path;
if(-e $fn)
{
say STDERR "local file already exists";
exit 2;
}
my $ftp = AnyEvent::FTP::Client->new( passive => $active ? 0 : 1 );
$ftp->on_send(sub {
my($cmd, $arguments) = @_;
$arguments //= '';
$arguments = 'XXXX' if $cmd eq 'PASS';
say "CLIENT: $cmd $arguments"
if $debug;
});
$ftp->on_each_response(sub {
my $res = shift;
if($debug)
{
say sprintf "SERVER: [ %d ] %s", $res->code, $_ for @{ $res->message };
}
});
$ftp->connect($remote->host, $remote->port)->recv;
$ftp->login($remote->user, $remote->password)->recv;
$ftp->type('I')->recv;
$ftp->cwd(join '/', '', @path)->recv;
my $remote_size;
if($progress)
{
my $listing = $ftp->list($fn)->recv;
foreach my $class (qw( File::Listing File::Listing::Ftpcopy ))
{
my $parsed_listing = eval qq{ use $class; ${class}::parse_dir(\$listing->[0]) };
next if $@;
my ($name, $type, $size, $mtime, $mode) = @{ $parsed_listing->[0] };
$remote_size = $size;
last;
}
if(defined $remote_size)
{
}
else
{
say STDERR "could not determine size of remote file, cannot provide progress bar";
$progress = 0;
}
}
open my $fh, '>', $fn;
my $xfer = $ftp->retr($fn);
my $pb;
my $count = 0;
$xfer->on_open(sub {
my $handle = shift;
$pb = Term::ProgressBar->new({ count => $remote_size })
if $progress;
$handle->on_read(sub {
$handle->push_read(sub {
print $fh $_[0]{rbuf};
$pb->update($count += length($_[0]{rbuf})) if $pb;
$_[0]{rbuf} = '';
});
});
});
$xfer->recv;
close $fh;
$ftp->quit->recv;
=head2 fls.pl
Here is a similar example, which does a directory listing on a FTP
directory URL. If you use the C<-d> option to see the FTP commands
and their responses as they happen. You can use the C<-l> option
to see the long form of the file listing.
use strict;
use warnings;
use 5.010;
use URI;
use AnyEvent::FTP::Client;
use Term::Prompt qw( prompt );
use Getopt::Long qw( GetOptions );
my $debug = 0;
my $method = 'nlst';
GetOptions(
'd' => \$debug,
'l' => sub { $method = 'list' },
);
my $ftp = AnyEvent::FTP::Client->new;
if($debug)
{
$ftp->on_send(sub {
my($cmd, $arguments) = @_;
$arguments //= '';
$arguments = 'XXXX' if $cmd eq 'PASS';
say "CLIENT: $cmd $arguments";
});
$ftp->on_each_response(sub {
my $res = shift;
say sprintf "SERVER: [ %d ] %s", $res->code, $_ for @{ $res->message };
});
}
my $uri = shift;
unless(defined $uri)
{
say STDERR "usage: perl fls.pl URL\n";
exit 2;
}
$uri = URI->new($uri);
unless($uri->scheme eq 'ftp')
{
say STDERR "only FTP URL accpeted";
exit 2;
}
unless(defined $uri->password)
{
$uri->password(prompt('p', 'Password: ', '', ''));
say '';
}
my $path = $uri->path;
$uri->path('');
$ftp->connect($uri);
say $_ for @{ $ftp->$method($path)->recv };
=head2 fput.pl
This script uploads a local file to the remote given a local filename
and a remote FTP URL.
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use 5.010;
use AnyEvent::FTP::Client;
use URI;
use URI::file;
use Term::ProgressBar;
use Term::Prompt qw( prompt );
use Getopt::Long qw( GetOptions );
use Path::Class qw( file );
my $debug = 0;
my $progress = 0;
my $active = 0;
GetOptions(
'd' => \$debug,
'p' => \$progress,
'a' => \$active,
);
my $local = shift;
my $remote = shift;
unless(defined $local && defined $remote)
{
say STDERR "usage: perl fput.pl [ -d | -p ] [ -a ] local remote";
say STDERR " where local is a local file";
say STDERR " and remote is a URL for a FTP server";
say STDERR " -d (optional) prints FTP commands and responses";
say STDERR " -p (optional) displays a progress bar as the file uploads";
say STDERR " -a (optional) use an active transfer instead of passive";
exit 2;
}
$local = file($local);
$remote = URI->new($remote);
unless($remote->scheme eq 'ftp')
{
say STDERR "only FTP URLs are supported";
exit 2;
}
unless(defined $remote->password)
{
$remote->password(prompt('p', 'Password: ', '', ''));
say '';
}
do {
my $from = URI::file->new_abs($local);
my $to = $remote->clone;
$to->password(undef);
say "SRC: ", $from;
say "DST: ", $to;
};
my $ftp = AnyEvent::FTP::Client->new( passive => $active ? 0 : 1 );
$ftp->on_send(sub {
my($cmd, $arguments) = @_;
$arguments //= '';
$arguments = 'XXXX' if $cmd eq 'PASS';
say "CLIENT: $cmd $arguments"
if $debug;
});
$ftp->on_each_response(sub {
my $res = shift;
if($debug)
{
say sprintf "SERVER: [ %d ] %s", $res->code, $_ for @{ $res->message };
}
});
$ftp->connect($remote->host, $remote->port)->recv;
$ftp->login($remote->user, $remote->password)->recv;
$ftp->type('I')->recv;
if(defined $remote->path)
{
$ftp->cwd($remote->path)->recv;
}
open my $fh, '<', $local;
binmode $fh;
my $buffer;
my $count;
my $pb;
my $xfer = $ftp->stor($local->basename);
$xfer->on_open(sub {
my $whandle = shift;
$pb = Term::ProgressBar->new({ count => -s $fh })
if $progress;
$whandle->on_drain(sub {
$pb->update($count) if $pb;
my $ret = read $fh, $buffer, 1024 * 512;
$count += $ret;
if($ret > 0)
{
( run in 0.352 second using v1.01-cache-2.11-cpan-0b5f733616e )