Kategorie: Programmierung

Bessere Fehlerbehandlung mit Try::Tiny

· · · 0 Kommentare

Die im Beitrag "MIME::Lite Fehlerbehandlung" implementierte Fehlerbehandlung mit "eval" funktioniert zwar in den meisten Fällen, kann aber in bestimmten Situationen doch nicht zum gewünschten Ergebnis führen.

Eine bessere Alternative ist die Verwendung von z.B. Try::Tiny, welches sich mit den aus anderen Sprachen bekannten "try", "catch" und "finally"-Anweisungen um die Fehlerbehandlung kümmert:

use strict;
use warnings;
use MIME::Lite;
use Try::Tiny;

MIME::Lite->send('smtp', 'mailserver', Debug => 0);

my $msg = MIME::Lite->new(

	From    => 'me@whereever.net',
	To      => 'you@somewhereelse.net',
	Data    => 'Hello World!',
	Subject => 'testmail',
);

try {
	$msg->send;
}
catch {
	warn "you DON'T have mail!";
};

print "... still running ...";

Nach der Warnung "you DON'T have mail!" wird das Programm mit "... still running ..." fortgesetzt.


MIME::Lite Fehlerbehandlung

· · · 0 Kommentare

Ein Skript, welches MIME::Lite zum Versenden von Mails verwendet, hat sich im Fehlerfall lieber direkt mit einem "SMTP Failed to connect to mail server: Bad file descriptor" beendet, statt gemäß Dokumentation auf den Fehler zu reagieren.

use strict;
use warnings;
use MIME::Lite;

MIME::Lite->send('smtp', 'mailserver', Debug => 0);

my $msg = MIME::Lite->new(

	From    => 'me@whereever.net',
	To      => 'you@somewhereelse.net',
	Data    => 'Hello World!',
	Subject => 'testmail',
);

$msg->send || die "you DON'T have mail!";

print "... still running ...";

Weder "you DON'T have mail!" noch "... still running ..." werden ausgegeben, da diese Stellen im Code auf Grund des Programmabbruchs nicht mehr erreicht werden.

Leider ist die Erläuterung zum Verhalten der Funktion "$msg->send" nicht wirklich hilfreich:

Returns whatever the mail-handling routine returns: this should be true on success, false/exception on error.

Eine Suche im Internet führte zum Blogbeitrag "Perl exception handling", welcher genau das aufgetretene Verhalten beschreibt und eine Lösungsmöglichkeit mittels "eval"  aufzeigt:

use strict;
use warnings;
use MIME::Lite;

MIME::Lite->send('smtp', 'mailserver', Debug => 0);

my $msg = MIME::Lite->new(

	From    => 'me@whereever.net',
	To      => 'you@somewhereelse.net',
	Data    => 'Hello World!',
	Subject => 'testmail',
);

eval { $msg->send; };

if ($@) {
	print "you DON'T have mail!";
}

print "... still running ...";

So gekapselt läuft das Skript auch nach einem gescheiterten "$msg->send" weiter und auf einen eventuellen Fehler kann reagiert werden.


Net::SSLeay: load_file:Das angegebene Modul wurde nicht gefunden

· · · 2 Kommentare

Der Versuch, das Perl-Modul "WWW::Mechanize" zu installieren scheitert mit der Meldung, daß ein Modul nicht gefunden werden kann:

cpan> install WWW::Mechanize
...
Can't load 'C:/Strawberry/perl/vendor/lib/auto/Net/SSLeay/SSLeay.xs.dll' for module Net::SSLeay: load_file:Das angegebene Modul wurde nicht gefunden at C:/Strawberry/perl/lib/DynaLoader.pm line 193.
  at C:/Strawberry/perl/vendor/lib/IO/Socket/SSL.pm line 19.
...
Can't load 'C:/Strawberry/perl/vendor/lib/auto/Crypt/SSLeay/SSLeay.xs.dll' for module Crypt::SSLeay: load_file:Das angegebene Modul wurde nicht gefunden at C:/Strawberry/perl/lib/DynaLoader.pm line 193.
  at C:/Strawberry/perl/vendor/lib/Net/SSL.pm line 20.
...

Die ausgegebene Fehlermeldung führt allerdings zuerst auf eine falsche Fährte, denn in angegebenen Ordnern ist das Modul sehr wohl zu finden:

C:\>dir C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay\SSLeay.xs.dll
...
 Verzeichnis von C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay

17.03.2020  05:24           485.888 SSLeay.xs.dll
...

C:\>dir C:\Strawberry\perl\vendor\lib\auto\Crypt\SSLeay\SSLeay.xs.dll
...
 Verzeichnis von C:\Strawberry\perl\vendor\lib\auto\Crypt\SSLeay

17.03.2020  05:26            59.904 SSLeay.xs.dll
...

Die Ursachenforschung im Internet führt überwiegend zu Treffern, die darauf hin deuten, daß ein Problem mit Modulabhängigkeiten besteht und überprüft werden sollte, ob der der Ordner "C:\Strawberry\c\bin" im Pfad enthalten ist. Dies ist der Fall:

Path=...;C:\Strawberry\c\bin;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;

Eine Analyse mit Microsofts Process Monitor zeigt, daß es an insgesamt drei Modulen aus dem Ordner "C:\Strawberry\c\bin" liegt, die trotz vorhandenem Pfad-Eintrag nicht gefunden werden.

 

Zum Beheben des Fehlers können entweder die drei Module in den Ordner "C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay\" kopiert oder (als vielleicht elegantere Lösung) entsprechende Links gesetzt werden:

C:\>cd C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay\

C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay>mklink libcrypto-1_1-x64__.dll C:\Strawberry\c\bin\libcrypto-1_1-x64__.dll
symbolische Verknüpfung erstellt für libcrypto-1_1-x64__.dll <<===>> C:\Strawberry\c\bin\libcrypto-1_1-x64__.dll

C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay>mklink libssl-1_1-x64__.dll C:\Strawberry\c\bin\libssl-1_1-x64__.dll
symbolische Verknüpfung erstellt für libssl-1_1-x64__.dll <<===>> C:\Strawberry\c\bin\libssl-1_1-x64__.dll

C:\Strawberry\perl\vendor\lib\auto\Net\SSLeay>mklink zlib1__.dll C:\Strawberry\c\bin\zlib1__.dll
symbolische Verknüpfung erstellt für zlib1__.dll <<===>> C:\Strawberry\c\bin\zlib1__.dll

Anschließend läuft die Installation ohne Probleme durch:

cpan> install WWW::Mechanize
...
All tests successful.
Files=62, Tests=816, 147 wallclock secs ( 0.23 usr + 0.19 sys = 0.42 CPU)
Result: PASS

Referrer oder Referer?

· · · 0 Kommentare

Ich bin gerade darüber gestolpert, daß der Referrer in der Verwendung als HTTP_REFERER nur mit einem "R" geschrieben wird. Wie die Wikipedia erläutert, ist ein Versehen in der RFC 2068 dafür verantwortlich:

Die korrekte englische Schreibweise lautet Referrer. Der ursprüngliche RFC (RFC 2068) enthielt jedoch versehentlich die falsche Schreibweise Referer und erhebt diesen Wortlaut damit zum Standard innerhalb von HTTP. [Quelle]


Windows-Hintergrundbild mit Perl setzen

· · · 0 Kommentare

Das Setzen des Windows-Hintergrundbilds ist von Perl aus ganz einfach - zumindest wenn man die Win32-API verwendet:

use strict;
use warnings;
use Win32::API;

use constant SPI_SETDESKWALLPAPER => 0x0014;
use constant SPIF_UPDATEINIFILE   => 0x0001;
use constant SPIF_SENDCHANGE      => 0x0002;
use constant ZERO                 => 0x0000;

my $syspinf = Win32::API->new('user32', 'SystemParametersInfo', [I,I,P,I], I) or die "SystemParametersInfo not available.\n";

$syspinf->Call(SPI_SETDESKWALLPAPER, ZERO, $ARGV[0], SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);

Das Skript erwartet den Namen des Bildes inklusive Pfad als Parameter.