Net::DownloadMirror - Perl extension for mirroring a remote location via FTP to the local directory


Net-DownloadMirror documentation Contained in the Net-DownloadMirror distribution.

Index


Code Index:

NAME

Top

Net::DownloadMirror - Perl extension for mirroring a remote location via FTP to the local directory

SYNOPSIS

Top

  use Net::DownloadMirror;
  my $um = Net::DownloadMirror->new(
 	ftpserver		=> 'my_ftp.hostname.com',
 	user		=> 'my_ftp_user_name',
 	pass		=> 'my_ftp_password',
 	);
 $um->Download();

 or more detailed
 my $md = Net::DownloadMirror->new(
 	ftpserver		=> 'my_ftp.hostname.com',
 	user		=> 'my_ftp_user_name',
 	pass		=> 'my_ftp_password',
 	localdir		=> 'home/nameA/homepageA',
 	remotedir	=> 'public',
 	debug		=> 1 # 1 for yes, 0 for no
 	timeout		=> 60 # default 30
 	delete		=> 'enable' # default 'disabled'
 	connection	=> $ftp_object, # default undef
# "exclusions" default empty arrayreferences []
 	exclusions	=> ["private.txt", "Thumbs.db", ".sys", ".log"],
# "subset" default empty arrayreferences [ ]
 	subset		=> [".txt, ".pl", ".html", "htm", ".gif", ".jpg", ".css", ".js", ".png"],
# or substrings in pathnames
#	exclusions	=> ["psw", "forbidden_code"]
#	subset		=> ["name", "my_files"]
# or you can use regular expressions
# 	exclusinos	=> [qr/SYSTEM/i, $regex]
# 	subset		=> {qr/(?i:HOME)(?i:PAGE)?/, $regex]
 	filename		=> "modified_times",
 	);
 $um->Download();

DESCRIPTION

Top

This module is for mirroring a remote location to a local directory via FTP. For example websites, documentations or developmentstuff which ones were uploaded or changed in the net. Local files will be overwritten, also in case they are newer. It is not developt for mirroring large archivs. But there are not in principle any limits.

Constructor and Initialization

Top

methods

optional options

 =item delete
 When directories or files are to be deleted = 'enable'
 default = 'disabled'

EXPORT

None by default.

SEE ALSO

Top

 Net::MirrorDir
 Net::UploadMirror
 Tk::Mirror
 http://freenet-homepage.de/torstenknorr/index.html

FILES

Top

 Net::MirrorDir 0.19
 Storable
 File::Path

BUGS

Top

Maybe you'll find some. Let me know.

REPORTING BUGS

Top

When reporting bugs/problems please include as much information as possible.

AUTHOR

Top

Torsten Knorr, <create-soft@tiscali.de>

COPYRIGHT AND LICENSE

Top


Net-DownloadMirror documentation Contained in the Net-DownloadMirror distribution.

#*** DownloadMirror.pm ***#
# Copyright (C) 2006 - 2008 by Torsten Knorr
# create-soft@tiscali.de
# All rights reserved!
#------------------------------------------------
 use strict;
#------------------------------------------------
 package Net::DownloadMirror::FileName;
 use Storable;
 sub TIESCALAR { my ($class, $obj) = @_; return(bless(\$obj, $class || ref($class))); }
 sub STORE
 	{
 	if(-f $_[1])
 		{
 		${$_[0]}->{_last_modified} = retrieve($_[1]);
 		}
 	else
 		{
 		${$_[0]}->{_last_modified} = {};
 		store(${$_[0]}->{_last_modified}, $_[1]);
 		warn("\nno information of the files last modified times\n");
 		}
 	}
 sub FETCH { return(${$_[0]}->{_filename}); }
#-------------------------------------------------
 package Net::DownloadMirror;
#------------------------------------------------
 use Net::MirrorDir 0.19;
 use File::Path;
 use Storable;
#------------------------------------------------
 @Net::DownloadMirror::ISA = qw(Net::MirrorDir);
 $Net::DownloadMirror::VERSION = '0.10';
#-------------------------------------------------
 sub _Init
 	{
 	my ($self, %arg) = @_;
 	tie($self->{_filename}, 'Net::DownloadMirror::FileName', $self);
 	$self->{_filename}		= $arg{filename}	|| 'lastmodified_remote';
 	$self->{_delete}		= $arg{delete}	|| 'disabled';
 	$self->{_current_modified}	= {};
 	return 1;
 	}
#-------------------------------------------------
 sub Download
 	{
 	my ($self) = @_;
	return 0 unless($self->Connect());
 	my ($rh_lf, $rh_ld) = $self->ReadLocalDir();
 	if($self->{_debug})
 		{
 		print("local files : $_\n") for(sort keys %$rh_lf);
 		print("local dirs : $_\n") for(sort keys %$rh_ld);
 		}
 	my ($rh_rf, $rh_rd) = $self->ReadRemoteDir();
 	if($self->{_debug})
 		{
 		print("remote files : $_\n") for(sort keys %$rh_rf);
 		print("remote dirs : $_\n") for(sort keys %$rh_rd);
 		}
 	my $ra_rdnil = $self->RemoteNotInLocal($rh_ld, $rh_rd);
 	if($self->{_debug})
 		{
 		print("remote directories not in local: $_\n") for(@$ra_rdnil);
 		}
 	$self->MakeDirs($ra_rdnil);
 	my $ra_rfnil = $self->RemoteNotInLocal($rh_lf, $rh_rf);
 	if($self->{_debug})
 		{
 		print("remote files not in local : $_\n") for(@$ra_rfnil);
 		}
 	$self->StoreFiles($ra_rfnil);
 	if($self->{_delete} eq 'enable')
 		{
 		my $ra_lfnir = $self->LocalNotInRemote($rh_lf, $rh_rf);
 		if($self->{_debug})
 			{
 			print("local files not in remote: $_\n") for(@$ra_lfnir);
 			}
 		$self->DeleteFiles($ra_lfnir);
 		my $ra_ldnir = $self->LocalNotInRemote($rh_ld, $rh_rd);
 		if($self->{_debug})
 			{
 			print("local directories not in remote : $_\n") for(@$ra_ldnir);
 			}
 		$self->RemoveDirs($ra_ldnir);
 		}
 	delete(@{$rh_rf}{@$ra_rfnil});
 	my $ra_mrf = $self->CheckIfModified($rh_rf);
 	if($self->{_debug})
 		{
 		print("modified remote files : $_\n") for(@$ra_mrf);
 		}
 	$self->StoreFiles($ra_mrf);
 	$self->Quit();
 	return 1;
 	}
#-------------------------------------------------
 sub CheckIfModified
 	{
 	my ($self, $rh_rf) = @_;
 	return [] unless($self->IsConnection());
 	my @mf;
 	my $changed = undef;
 	for my $rf (keys(%$rh_rf))
 		{
 		next unless($self->{_current_modified}{$rf} = $self->{_connection}->mdtm($rf));
 		if(defined($self->{_last_modified}{$rf}))
 			{
 			next if($self->{_last_modified}{$rf} eq $self->{_current_modified}{$rf});
 			}
 		else
 			{
 			$self->{_last_modified}{$rf} = $self->{_current_modified}{$rf};
 			$changed++;
 			}
 		push(@mf, $rf);
 		}
 	store($self->{_last_modified}, $self->{_filename}) if($changed);
 	return \@mf;
 	}
#-------------------------------------------------
 sub UpdateLastModified
 	{
 	my ($self, $ra_rf) = @_;
 	return unless($self->IsConnection());
 	my $mt;
 	for(@$ra_rf)
 		{
 		next unless($mt = $self->{_connection}->mdtm($_));
 		next unless($mt =~ m/^\d+$/);
 		$self->{_last_modified}{$_} = $mt;
 		}
	store($self->{_last_modified}, $self->{_filename});
 	return 1;
 	}
#-------------------------------------------------
 sub StoreFiles
 	{
 	my ($self, $ra_rf) = @_;
 	return 0 unless(@$ra_rf && $self->IsConnection());
 	my $lf;
 	for my $rf (@$ra_rf)
 		{
 		$lf = $rf;
 		$lf =~ s!$self->{_regex_remotedir}!$self->{_localdir}!;
 		next unless($self->{_connection}->get($rf, $lf));
 		$self->{_last_modified}{$rf} = 
 			$self->{_current_modified}{$rf}
 			|| $self->{_connection}->mdtm($rf);
 		}
 	store($self->{_last_modified}, $self->{_filename});
 	return 1;
 	}
#-------------------------------------------------
 sub MakeDirs
 	{
 	my ($self, $ra_rd) = @_;
 	return 0 unless(@$ra_rd);
 	my $ld;
 	for my $rd (@$ra_rd)
 		{
 		$ld = $rd;
 		$ld =~ s!$self->{_regex_remotedir}!$self->{_localdir}!;
 		mkpath($ld, $self->{_debug}) unless(-d $ld);
 		}
 	return 1;
 	}
#-------------------------------------------------
 sub DeleteFiles
 	{
 	my ($self, $ra_lf) = @_;
 	return 0 unless(($self->{_delete} eq 'enable') && @$ra_lf);
	my $rf;
 	for my $lf (@$ra_lf)
 		{
 		$rf = $lf; 
 		next unless(-f $lf);
 		warn("can not unlink : $lf\n") unless(unlink($lf));
 		$rf =~ s!$self->{_regex_localdir}!$self->{_remotedir}!;
 		delete($self->{_last_modified}{$rf})
 			if(defined($self->{_last_modified}{$rf}));
 		}
 	store($self->{_last_modified}, $self->{_filename});
 	return 1;
 	} 
#-------------------------------------------------
 sub RemoveDirs
 	{
 	my ($self, $ra_ld) = @_;
 	return 0 unless(($self->{_delete} eq 'enable') && @$ra_ld);
 	for my $ld (@$ra_ld)
 		{
 		next unless(-d $ld);
 		rmtree($ld, $self->{_debug}, 1);
 		}
 	return 1;
 	}
#------------------------------------------------
 sub CleanUp
 	{
 	my ($self, $ra_exists) = @_;
 	my %h_temp = ();
 	for my $key (@$ra_exists)
 		{
		if(
 			defined($self->{_last_modified}{$key})
 			&& 
 			($self->{_last_modified}{$key} =~ m/^\d+$/)
 			)
 			{
 			$h_temp{$key} = delete($self->{_last_modified}{$key});
 			}
 	 	if($self->{_debug})
 	 		{
 			print(
 				"key: $_	value: "
 				. (defined($self->{_last_modified}{$_}) ? $self->{_last_modified}{$_} : 'undef')
 				. " removed\n")
					for(keys(%{$self->{_last_modified}}));
 			}
 		}
 	%{$self->{_last_modified}} = %h_temp;
 	store($self->{_last_modified}, $self->{_filename});
 	return 1;
 	}
#-------------------------------------------------
 sub LtoR
 	{
 	my ($self, $ra_lp) = @_;
 	my $ra_rp = [];
 	my $rp;
 	for(@$ra_lp)
 		{
 		$rp = $_;
 		$rp =~ s!$self->{_regex_localdir}!$self->{_remotedir}!;
 		push(@$ra_rp, $rp);
 		}
 	return $ra_rp;
 	}
#-------------------------------------------------
 sub RtoL
 	{
 	my ($self, $ra_rp) = @_;
 	my $ra_lp = [];
 	my $lp;
 	for(@$ra_rp)
 		{
 		$lp = $_;
 		$lp =~ s!$self->{_regex_remotedir}!$self->{_localdir}!;
 		push(@$ra_lp, $lp);
 		}
 	return $ra_lp;
 	}
#-------------------------------------------------
1;
#------------------------------------------------
__END__