[quote=Captain Future,16.01.2004, 01:24]
Bin noch ein Perl-Newbie habe hier mein erstes Script gepostet.
[/quote]
Fuer einen Neuling ist der Code schon recht gut. :)
Trotzdem wuerde ich dir eher raten, einen guten(! ) FormMailer anzupassen (siehe z.B.
NMS-FormMailer), statt hier in diverse Fallen zu geraten. Eine gute Uebung ist das Selberschreiben sicherlich, aber fuer den Produktiveinsatz halte ich den Code so fuer zu gefaehrlich.
QuoteLeider sind darin noch einige Fehler, da ich sozusagen einen Köpfler in Perl gemacht habe.
Da ich keine Perlumgebung @ Home laufen habe ist das Script also so runtergeschrieben.
Mein Tipp: Installier dir Perl! Selbst wenn du keinen Webserver laufen hast, kannst du zumindest deine Programme auf syntaktische Korrektheit pruefen.
Quote
#!/usr/bin/perl
# Pfad zu Prel
Hier fehlen auf jeden Fall
use strict;
use warnings;
Diese sind zwar nicht syntaktisch notwendig, erleichtern aber die Entwicklung ungemein, wenn du die Fehler- und Warnmeldungen erhaeltst. Fuer "strict" muessen allerdings saemtliche Variablen deklariert (oder voll qualifiziert angegeben) werden.
Quote
...
# Pfad zum Date-Kommando:
$date = '/usr/bin/date';
Dieses Date-Kommando brauchst du danach nie wieder.
Den Variablennamen dagegen verwendest du unten nochmal!
Quote
...
# E-Mail Adresse des Empfängers (mit \@):
@email_list = ("info\@xyz4711.de", "webmaster\@xyz4711.de");
Wenn man statt doppelter einfache Anfuehrungszeichen nimmt, kann man sich das Escapen der '@' sparen.
Quote
###################################################################
# Perl-Programm ist für Übergabemethode POST sowie GET geeignet:
if ($ENV{"REQUEST_METHODE"} eq "POST")
{
read(STDIN, $daten, $ENV{"CONTENT_LENGTH"});
...
Auahauaha.
Nein, bitte nicht diese kaputten selbstgeschriebenen Formularfunktionen! Nimmt CGI.pm, bitte! Es gehoert seit Perl 5.6.1 zum Standardumfang:
use CGI;
my %FORM = CGI::Vars();
Quote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
###################################################################
# ------------------ Formular-Elemente ------------------
$recipient = $FORM{'recipient'};
$recipient_bcc = $FORM{'recipient_bcc'};
$subject = $FORM{'subject'};
$CB01 = $FORM{'Kacheloefen'};
$CB02 = $FORM{'Kaminoefen'};
$CB03 = $FORM{'Herde'};
$CB04 = $FORM{'Heizkamine'};
$input05 = $FORM{'Vorname'};
$input06 = $FORM{'Nachname'};
$input07 = $FORM{'Strasse'};
$input08 = $FORM{'PLZ'};
$input09 = $FORM{'Ort'};
$input10 = $FORM{'Land'};
$input11 = $FORM{'Telefon'};
$input12 = $FORM{'Telefax'};
$input13 = $FORM{'eMail'};
$input14 = $FORM{'Betreff'};
$input15 = $FORM{'Text'};
Warum kopierst du hier die Formularinhalte von einem Hash mit sinnvoll benannten Feldern in durchnummerierte Variablen? Ich finde, der Code wird dadurch eher weniger verstaendlich, aber okay.
Quote
###################################################################
$input15 =~ s/\cM//g;
$input15 =~ s/\n/ /g;
Die Benutzereingaben zu bearbeiten ist eine gute Idee. Aber warum nur $input15? Der ist gerade am wenigsten gefaehrlich. $input05 und $input06 faende ich hier wichtiger, weil diese direkt im Header der Mail landen und durch Manipulation dieser Felder der Formmailer missbraucht werden kann.
Quote
###################################################################
# ------- Check auf fehlende und falsche Eingabe -------
&missing(Vorname) unless $input05;
&missing(Nachname) unless $input06;
&missing(eMail) unless $input13;
&missing(Text) unless $input15;
Hier sollte das Argument der Funktionsaufrufe jeweils in Anfuehrungszeichen stehen, da es sich um Strings handelt.
Also:
missing('Vorname') unless $input05;
...
Quote
### Zeile 74 ###
&falsch(Fehler 01: Bitte eine gueltige Postleitzahl(PLZ) eingeben !) unless ($input08 =~ m/\d{5});
Hier gilt das gleiche: Argument der Funktion in Anfuehrungszeichen.
Ausserdem ist hier die Regex nicht beendet und wahrscheinlich auch falshc. Ich vermute, du moechtest pruefen, ob $input08 exakt aus fuenf Ziffern besteht. Dann lautete es so:
falsch ("Fehler 01: Bitte eine gueltige Postleitzahl(PLZ) eingeben!") unless $input08 =~ m/^\d{5}$/;
Quote
### Zeile 75 ###
&falsch(Fehler 02: Bitte eine gueltige eMail Adresse eingeben !) unless ($input13 =~ m/^[a-zA-Z0-9][-\_\.]*[a-zA-Z0-9]\@[a-zA-Z0-9][-\_\.]*[a-zA-Z0-9][\.]([a-zA-Z]){2,4}$/);
Wie oben, nur dass zusaetzlich die Regex fuer die E-Mail-Adresse alles andere als vollstaendig ist. Nimm Email::Valid oder Mail::RFC822::Address oder aehnliches fuer diesen Test.
Quote
&falsch(Fehler 03: Bitte eine gueltige Telefonnummer eingeben !) unless ($input11 =~ m/^[0]\d+.\d+$/);
Siehe oben.
Quote
&falsch(Fehler 04: Bitte eine gueltige Telefaxnummer eingeben !) unless ($input12 =~ m/^[0]\d+.\d+$/);
Die Regex bedeutet: "Eine Null am Anfang, gefolgt von beliebig vielen Ziffern, gefolgt von einem beliebigen Zeichen, gefolgt von beliebig vielen Ziffern und Ende des Strings." War das so gemeint?
Quote
&falsch(Fehler 05: Bitte einen gueltigen Strassennamen eingeben !) unless ($input07 =~ m/\w?\-/);
Diese Regex bedeutet: "Der String enthaelt evtl. ein Wortzeichen (also a-z, A-Z, 0-9 oder '_' ), auf jeden Fall gefolgt von einem Bindestrich."
Quote
&falsch(Fehler 06: Bitte einen gueltigen Ortsnamen eingeben !) unless ($input09 =~ m/\D/);
"Der String enthaelt mindestens ein Zeichen, das keine Ziffer ist."
Quote
&falsch(Fehler 07: Bitte einen gueltigen Landesnamen eingeben !) unless ($input09 =~ m/\D/);
S.o.
Quote
sub falsch {
($fehler) = @_;
}
Gut, die Fehlerbehandlung steht wohl noch am Anfang. ;)
Quote
##################################################################
&getdate;
if($os eq "UNIX")
{
&SendIt;
} else {
require "winmail.pl";
&SendMail($mailprog, $tempdirectory, $subject, $email_list[$recipient], $Text);
}
Ich weiss nicht, was "winmail.pl" enthaelt, aber wahrscheinlich muss $tempdirectory irgendwo gesetzt werden, und $mailprog ist in diesem Programm auch nicht passend fuer ein Windows-System.
Wusstest du schon, dass es Perl-Module gibt, die das Versenden von E-Mails deutlich vereinfachen, wie Mail::Mailer oder MIME::Lite?
Quote
&PrintResponse;
###################################################################
# ---------- Empfänger-Mail aus den Formulardaten (im TXT-Format) ----------
sub SendIt {
open (MAIL, "|$mailprog -t") || die "Kann Sendmail nicht starten: $!";
Besser waere bei Sendmail der Aufruf
"|$mailprog -oit"
weil damit verhindert wird, dass man den eingebenen Text leicht so manipulieren kann, dass man damit beliebige E-Mails ueber den Server verschickt.
Quote
print MAIL "To: $email_list[$recipient, $recipient_cc]\n";
print MAIL "From: $input05, $input06\n\n";
Here be dragons!
Da die Eingaben $input05 und $input06 nicht geprueft wurden, kann ein Angreifer alles erdenkliche in den Header injizieren, inkl. neuer Empfaenger-Adressen in einem CC-Feld.
Quote
print MAIL "------ KUNDENANFRAGE via WebFormular ------\n";
print MAIL "===========================================\n";
print MAIL "Subject: $subject - ";
Den Betreff im Body der Mail zu haben ist zwar ungewoehnlich, aber nicht verboten. ;)
Quote
if ($FORM{'input14'} ne "") {print MAIL "$FORM{'input14'}\n";
Von $FORM{input14} war bisher nicht die Rede. Wahrscheinlich meinst du $input14 oder $FORM{Subject}.
Ausserdem: Wenn das Feld leer ist, wird in dieser Zeile auch kein Zeilenumbruch ausgegeben. Absicht?
Quote
print MAIL "===========================================\n";
print MAIL "Text des Kunden:\n";
print MAIL "$input15\n";
print MAIL "===========================================\n";
print MAIL "Kunde interessiert sich fuer:\n\n";
if ($FORM{'CB01'} ne "") {print MAIL "$FORM{'CB01'}\n";
if ($FORM{'CB02'} ne "") {print MAIL "$FORM{'CB02'}\n";
if ($FORM{'CB03'} ne "") {print MAIL "$FORM{'CB03'}\n";
if ($FORM{'CB04'} ne "") {print MAIL "$FORM{'CB04'}\n\n";
Auch hier soll es wahrscheinlich $CB01 etc. heissen.
Quote
print MAIL "===========================================\n";
print MAIL "Kundendaten:\n\n";
print MAIL "$input05, $input06\n";
if ($FORM{'input07'} ne "" and ne "Musterweg 10") {print MAIL "$FORM{'input07'}\n\n";
if ($FORM{'input08'} ne "" and ne "12345") {print MAIL "$FORM{'input08'}";
if ($FORM{'input09'} ne "" and ne "Musterhausen") {print MAIL "$FORM{'input09'}\n";
if ($FORM{'input10'} ne "" and ne "Musterland") {print MAIL "$FORM{'input10'}\n\n";
if ($FORM{'input11'} ne "" and ne "08382-72176") {print MAIL "Tel.: $FORM{'input11'}\n";
if ($FORM{'input12'} ne "" and ne "08382-75140") {print MAIL "Fax.: $FORM{'input12'}\n";
Dito fuer $FORM{inputXX} vs. $inputXX.
Quote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
print MAIL "eMail: $input13\n\n";
print MAIL "===========================================\n";
print MAIL "Das Formular wurde am $date um $time Uhr (MEZ) vom Kunden versendet.\n";
print MAIL "IP des Absenders: $ipaddr\n";
print MAIL "Host des Absenders: $hostname\n\n";
print MAIL "Formular-Nr.: $count\n";
print MAIL "===========================================\n\n";
print MAIL "<<< Dies ist ein Service des Webmasters: Captain Future >>>";
close (MAIL);
}
###################################################################
# ------------ Remote_Host auslesen (Variante für 1&1) ------------
# Using Socket-Library
use Socket;
# Fatal-Fehler an den Browser schicken
use CGI::Carp 'fatalsToBrowser';
# Die Variable $ipaddr auf die Remote IP-Adresse setzten
$ipaddr = $ENV{'REMOTE_ADDR'};
# Die IP muss codiert werden:
$iptocheck = inet_aton($ipaddr);
# Host-Lookup auf die codierte IP machen:
$hostname = gethostbyaddr($iptocheck, AF_INET);
Nur eine Warnung: Ein gethostbyaddr() kann laenger dauern, weil dafuer ein reverse DNS Lookup gemacht werden muss. Fuer Skripte, die sehr haeufig aufgerufen werden, wuerde ich darauf verzichten.
Quote
###################################################################
# ------------ Datums und Zeitstempel ------------
sub getdate {
@days = ("Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag");
@months = ("Januar", "Februar", "Maerz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember");
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
$time = sprinf("%02d:%02d:%02d", $hour, $min, $sec);
$year += 1900;
$date = "$days[$wday], $mday. $months[$mon] $year";
}
Tipp: Gewoehne dir an, deine Variablen in moeglichst kleinem Geltungsbereich ("Scope") zu deklarieren und moeglichst wenige globale Variablen zu benutzen. Wenn man sich an "use strict" gewoehnt hat, faellt einem das sogar leichter. Generell sollte man es vermeiden, in Subroutinen andere Variablen als lokal erzeugte oder uebergebene zu verwenden.
Quote
##################################################################
# ------------ Counter-Funktion ------------
$countfile = "formcount.txt";
$count = 'cat $countfile';
Das sollen wahrscheinlich keine einfachen Anfuehrungszeichen sein, sondern Backticks.
Quote
chop($count);
$count = $count + 1;
open (INF, ">$countfile");
print INF "$count\n";
close (INF);
Dieser Code faellt schnell auf die Nase, wenn das Programm mehrere Male parallel laeuft. Da wird entweder falshc gezaehlt oder sogar der Zaehler geloescht.
Siehe dazu auch
perldoc -q "get locking".
HTH