Nov 23

Seit gestern schlug ich mich mit einem Problem rum, mittels des CPAN-Modules Net::FTP von einem passivem FTP-Server eine Datei zu laden. Leider schlugen alle Versuche immer fehl. Anbei das Beispiel-Script:


#/usr/local/bin/perl

use strict;
use Net::FTP;

# benötigte Variablen
my ($ftpserver, $ftppath, $ftpdatei, $modtime, $update) = ("")x5;
my $ftppassiv = 1;
my $ftpport = 21;
my $ftpuser = "gast";
my $ftppassword = "geheim";
my $ftplink = "ftp.comnart.de/logs/www.comnart.de_ftp_access.log.zip";
my $lokaledatei = "access.log";
my $zipname = "www.comnart.de_ftp_access.log";

# FTP Link zerlegen
if ($ftplink =~ /^(.*?)\/(.*\/)?(.*?)$/) {
$ftpserver = $1;
$ftppath = $2;
$ftpdatei = $3;
} else {
die "Kann den FTP Link nicht zerlegen!\n";
}

# FTP Verbindung aufbauen
my $ftp = Net::FTP->new(
$ftpserver,
PORT => $ftpport,
PASSIVE => $ftppassiv,
Timeout => 60) or die "Konnte die FTP-Verbindung nicht aufbauen: $@\n";

# FTP Login
$ftp->login($ftpuser, $ftppassword) or die "Konnte nicht einloggen";

# Verzeichniss wechseln falls nötig
$ftp->cwd($ftppath) if $ftppath;

# ÜbertragungsModus umschalten, entsprechend der Datei-Endung
## XML, Text, CSV und HTML Dateien im ASCII-Modus
$ftp->ascii() if $ftpdatei =~ /\.(txt|csv|html|xml)$/i;
## Zip, XLS und DBase Dateien im BINÄR-Modus
$ftp->binary() if $ftpdatei =~ /\.(gz|zip|xls|dbf|bz2)$/i;

# FTP-Feature MDTM verfügbar?
if ($ftp->feature( 'MDTM' )) {
$modtime = $ftp->mdtm($ftpdatei)
or print "Konnte das Datum der Datei $ftpdatei: nicht lesen: $@\n";
} else {
# Alternativ Verzeichniss auslesen und Datum extrahieren
my $ls = $ftp->dir();
foreach my $entry (parse_dir($ls)) {
my ($name, $type, $size, $mtime, $mode) = @$entry;
if ($type eq 'f') {
next unless ($name eq $ftpdatei);
$modtime = $mtime;
}
}
}

# Überprüfen, ob die Datei lokal schon aktuell & vorhanden ist
my @lokalinfo = stat($lokaledatei);
if ($modtime ne $lokalinfo[9])
{
# Alte Datei loeschen
unlink $lokaledatei or do print "Fehler beim löschen der alten lokalen Datei! $lokaledatei";

if ($zipname){
my $extraktok = 0;
# Neue Datei per FTP holen
$ftp->get($ftpdatei,$lokaledatei.".zip") or die "Konnte die Datei $ftpdatei -> ".$lokaledatei.".zip nicht empfangen: $@\n";

# Datei entpacken
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
my $zip = Archive::Zip->new();
die "Winzip 'read error' " if $zip->read($lokaledatei.'.zip') != AZ_OK;
if ($zip->extractMember($zipname,$lokaledatei) != AZ_OK) {
print "Winzip 'write error' ";
} else {
$extraktok = 1;
}

# Zip-Datei loeschen
if ($extraktok) {
unlink $lokaledatei.'.zip' or print "Fehler beim löschen der gezippten Datei!";
} else {
print "Fehler beim Entpacken, Datei nicht gefunden ";
}

} else {
$ftp->get($ftpdatei,$lokaledatei) or do print "Konnte die Datei $ftpdatei: nicht empfangen: $@\n";
$update = 1;
}
} else {
$update = 0;
}

$ftp->close() or print "Konnte Verbindung nicht schließen";

if ($update) {
# Zeitstempel größer aktuelle Zeit?
$modtime = time if ($modtime > time); # Zeit auf Server größer aktueller Zeit
$modtime = time if ($modtime < 1); # Hack: Hier sollte man sich was besseres einfallen lassen ;) # Neue Datei mit Zeitstempel setzen utime ($modtime,$modtime,$lokaledatei); print "Download der Datei erfolgreich! (Timestamp: $modtime)\n"; } else { print "Datei ist aktuell (Timestamp: $modtime)\n"; } exit(0);

Im passiven Modus funktionierte alles bis zum

$ftp->get($ftpdatei,$lokaledatei) or do print "Konnte die Datei $ftpdatei: nicht empfangen: $@\n";

an dieser Stelle brach das Script mit der Meldung, das ein Abruf der Datei nicht möglich sei ab.

Nach langer Suche bei Google fand ich in diesem Forum den passenden Tip! 🙂
Die Lösung ist eigentlich ziemlich simpel. Einfach vor dem Login folgende Zeile einfügen:

$ENV{FTP_PASSIVE} = $passiv ? 1 : undef;

und schon funktioniert es auch mit problematischen passiven FTP-Servern!

Tagged with:
Apr 13

Um mit Perl XSL-Transformationen durchführen zu können, wollte ich zunächst das nachfolgende einfache Beispiel aus dem CPAN-Archiv ausprobieren:

use XML::LibXSLT;
use XML::LibXML;

my $xslt = XML::LibXSLT->new();
my $source = XML::LibXML->load_xml(location => 'foo.xml');
my $style_doc = XML::LibXML->load_xml(location=>'bar.xsl', no_cdata=>1);
my $stylesheet = $xslt->parse_stylesheet($style_doc);
my $results = $stylesheet->transform($source);

print $stylesheet->output_as_bytes($results);

Jedoch bekam ich nur folgende Fehlermeldung:

Can't locate object method "load_xml" via package "XML::LibXML"

Die Suche bei Google ergab, das bei Ubuntu 9.10 nur XML::LibXML in der Version 1.68 in den Ubuntu-Quellen vorliegt, die Funktion „load_xml“ aber erst in Version 1.70 existiert. Somit blieb nur die Installation über das CPAN-Archiv mittels
perl -MCPAN -e shell .

Das Perl-Modul wurde aus dem CPAN-Archiv erfolgreich installiert, aber das obige Beispiel funktionierte immernoch nicht. Jetzt meldete sich das Perl-Modul XML::LibXSLT mit der Fehlermeldung, das dieses Modul in Version 1.68 auch das Perl-Modul XML::LibXML in Version 1.68 benötigt!
Okay also das Perl-Modul XML::LibXSLT auch in Version 1.70 aus dem CPAN-Archiv installieren. Der Versuch wurde jedoch leider mit folgender Fehlermeldung abgebrochen:

/usr/bin/ld: cannot find -lgdbm

Die Suche bei Google war diesmal nicht so erfolgreich, der einzige Hinweis war, das es wohl an der Library libgdbm.so liegt. Diese war bei mir jedoch bereits installiert und ein libgdbm-perl Paket in den Ubuntu-Quellen gab es nicht, nur Pakete für Ruby und Smalltalk. Jedoch gab es das Paket libgdbm-dev, welches ich installierte und mit somit zur Lösung des Problems führte.

Jetzt funktioniert obiges Beispiel fehlerfrei und ich kann mit dem ausprobieren loslegen! 🙂

Nachtrag:

Unter Debian waren zusätzlich zur Installation des Paketes libgdbm-dev noch die Pakete libxslt1-dev und libxml2-dev notwendig bevor(!) sich aus dem CPAN-Archiv die aktuellen
Perl-Module XML::LibXML und XML::LibXSLT installieren ließen.
Ohne die Installation dieser Entwicklerpakete meldete der Versuch der CPAN-Archiv Installation folgende Fehler:
looking for -lxml2... no
looking for -llibxml2... no
libxml2 not found

Tagged with:
preload preload preload