FormMailer - Formulare per Mail verschicken

Installation und Konfiguration von FormMailer

 


Hier geht's zur Download-Seite von FormMailer

1. Allgemeines

1.1. Produktbeschreibung in Kürze

FormMailer ist ein kleines Script, welches es ermöglicht, Formulare per Mail zu versenden. Dabei kann das Mail nach belieben formatiert werden. Es werden beliebig viele - auch unterschiedliche - Mails sowie Dateianhänge unterstützt. Einfache Checks wie gültige Mailadressen und Pflichtfelder können ebenfalls durchgeführt werden. UNIX, deutsch, kostenlos.

1.2. Was kann FormMailer?

Online-Formulare gibt es fast auf jeder Homepage: sei es für eine webbasierte Kontaktaufnahme, ein Feedback-Formular, ein Anmelde-/Bestellformular oder was auch immer. Genauso viele Formmailer-Scripts dürften auch im Umlauf sein. FormMailer besitzt einige zusätzliche Funktionen, welchen ihn von der grossen Masse der anderen Scripts anheben:

1.3. Voraussetzungen

Der Server muss natürlich CGI's verarbeiten können. Nebst CGI-Unterstützung gelten noch folgende Voraussetzungen:

1.4. Lizenzbestimmungen

Dieses Skript basiert auf den STANDARD-Lizenzbedinungen, die Sie unter http://www.cgicorner.ch/download/download-info oder in der Datei cgicorner.txt im ZIP-Archiv finden.

2. Installation

2.1. Dateien kopieren und Berechtigungen setzen

Folgende Dateien müssen kopiert und mit den entsprechenden Berechtigungen versehen werden:

 cgi-bin - Verzeichnis, z.B. /cgi-bin/formmailer/
. chmod 755/777 Verzeichnis
formmailer.cgi chmod 755 Hauptscript
config.pl chmod 755 Konfiguration (*) (***)
subs.pl chmod 755 Subroutinen (*)
*.template chmod 600 Mail-Templates
seccode.jpg chmod 644 Secure-Code Bild (**)
scdata.cgi chmod 644 Secure-Code Daten (*) (**)
 Daten - Verzeichnis, z.B. /formulare/
. chmod 755/777 Verzeichnis
*.htm / *.php chmod 644 HTML-Formular (selbsterstellt)

Die mit (*) gekennzeichneten Dateien befinden sich nicht im ZIP-Archiv und werden erst im Betrieb erstellt.

Dateien, welche mit (**) gekennzeichneten sind werden nur für den Betrieb mit Secure-Code benötigt und können ansonsten gelöscht werden. Dateien mit (***) sind nur im Betriebsmodus "Administrationsbereich" vorhanden.

3. Konfigurationsmodes

3.1. Auswahl des aktuellen Modes

FormMailer arbeitet in drei unterschiedlichen Konfigurationsmodes, von denen immer nur einer aktiv ist. Jeder dieser Modes hat seine Vor- und Nachteile und spezifischen Konfigurationsparameter, welche in diesem Abschnitt noch genauer erläutert werden.

Die nachfolgende Tabelle zeigt auf, anhand welcher Kriterien sich FormMailer für einen bestimmten Konfigurationsmode entscheidet:

Existiert die Datei config.pl?
Ja
Es wird immer die Konfigurationsmode 3 "Administrationsbereich" verwendet.
Nein
Wurde mindestens ein Template mittels &addTemplate("abc.template"); innerhalb des Scriptes definiert?
Ja
Es wird die Konfigurationsmode 1 "Templatekonfiguration innerhalb des Scriptes" verwendet.
Nein
Es wird die Konfigurationsmode 2 "Templates via Parameter" verwendet.

3.2. Templatekonfiguration innerhalb des Scriptes

Der Konfigurationsmode "Templatekonfiguration innerhalb des Scriptes" eignet sich dann besonders, wenn FormMailer nur für ein einziges Formular verwendet wird. Die Templates werden hierbei innerhalb des Scripts definiert, so dass weder versteckte Formularfelder noch eine Konfiguration mittels Admin-Bereich notwendig sind. Obwohl auch die anderen zwei Konfigurations-Modes sicher sind, ist diese Variante die Sicherste, da keine Passwörter in falsche Hände geraten können.

Vorteile

Nachteile

3.2.1. Einsatz dieser Konfiguration

Um den Konfigurationsmode "Templatekonfiguration innerhalb des Scriptes" zu aktivieren, sind folgende Schritte notwendig.

3.2.2. Gültiges Formular

Folgendes Formular enthält alle benötigen Felder. Mehr Infos zu Formularen befinden sich im Kapitel 4.2..

<form action="formmailer.cgi" method="post">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm"/>
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm"/>
<textarea name="kommentar"><textarea>
<input type="submit" value="Absenden"/>

3.3. Templates via Parameter

Der Konfigurationsmode "Templates via Parameter" eignet sich, wenn FormMailer für mehrere Formulare eingesetzt werden soll, jedoch auf einen Administrationsbereich verzichtet werden kann. Um trotz variabler Dateinamen eine grosse Sicherheit zu gewährleisten verarbeitet FormMailer in dieser Konfiguration ausschliesslich Template-Dateien, welche die Dateiendung .template haben und im gleichen Verzeichnis wie das CGI-Script liegen. Ebenfalls darf der Dateiname nur aus den Buchstaben a-z, A-Z, den Zahlen 0-9 sowie aus - und _ bestehen.

Vorteile

Nachteile

3.3.1. Einsatz dieser Konfiguration

Um den Konfigurationsmode "Templates via Parameter" zu aktivieren, sind folgende Schritte notwendig.

3.3.2. Gültiges Formular

Folgendes Formular enthält alle benötigen Felder. Mehr Infos zu Formularen befinden sich im Kapitel 4.2..

<form action="formmailer.cgi" method="post">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm"/>
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm"/>
<input type="hidden" name="template" value="simple"/>
<input type="hidden" name="template2" value="simplereply"/>
<textarea name="kommentar"><textarea>
<input type="submit" value="Absenden"/>

3.4. Administrationsbereich

Der Konfigurationsmode "Administrationsbereich" bietet einen umfangreichen Administrationsbereich, in dem Templates, URLs, Feldwerte etc. zentral definiert und einer ID zugeordnet werden können. Ebenfalls ist es möglich, Templates webbasiert zu editieren. Diese Konfiguration eignet sich für Personen, welche jederzeit und überall Änderungen an Templates vornehmen wollen oder eine grössere Menge von Formularen bequem verwalten wollen.

Vorteile

Nachteile

3.4.1. Einsatz dieser Konfiguration

Um den Konfigurationsmode "Administrationsbereich" zu aktivieren, sind folgende Schritte notwendig.

3.4.2. Gültiges Formular

Folgendes Formular enthält alle benötigen Felder. Mehr Infos zu Formularen befinden sich im Kapitel 4.2..

<form action="formmailer.cgi" method="post"/>
<input type="hidden" name="id" value="myid"/>
<textarea name="kommentar"><textarea>
<input type="submit" value="Absenden"/>

4. Konfiguration

4.1. Script

Die Datei formmailer.cgi bietet einige Einstellungsmöglichkeiten, die aber kaum angepasst werden müssen

$sendmail Pfad zu sendmail
$sendmailParams Definiert zusätzliche Parameter für sendmail. Ist dieses Feld leer, wird noch der Parameter -fabsender@server.ch hinzugefügt, welches automatisch den Absender für die SMTP-Kommunikation benutzt (dabei wird der Absender aus dem Template gelesen). Diese Standard-Einstellung muss in der Regel nicht verändert werden. Enthält der Parameter nur einen -, wird der -f-Parameter nicht übergeben (unter Umständen unter Windows-Servern erforderlich, die einen Sendmail-Clone nutzen, der nicht jeden Parameter verarbeiten kann). Alle anderen Inhalte werden 1:1 dem Sendmail-Aufruf angehängt.
$mailVersand Debug-Switch: TRUE: Mails werden versendet; FALSE: Mails werden als EML-Datei im Script-Verzeichnis gespeichert.
$configFile Dateiname der Konfigurationsdatei (nur bei Betriebsvariante 3: Adminbereich) relevant); muss nicht angepasst werden.
$ipCheck Definiert, ob die IP-Adresse im Session-Key mitgespeichert werden soll. Wird die Funktion aktiviert, kann die Adminsession nicht durch Kopieren der URL von einem anderen PC aus übernommen werden. Erfolgt jedoch der Zugriff bei jedem Klick von unterschiedlichen IPs (z.B. Lastenverteilung auf mehrere Firewalls), führt dies zu Problemen. Tipp: Einstellung auf 1 belassen, funktioniert der Adminbereich nicht korrekt (Fehlermeldung "Login fehlgeschlagen" nach jedem Link-Klick auf 0 setzen).
$csvPath optionaler Pfad zur Ablage von CSV-Dateien (falls überhaupt im Einsatz). Ist der Parameter leer, werden die CSV-Dateien im Scriptverzeichnis gespeichert, ansonsten kann ein UNIX-Pfad mit abschliessendem / eingetragen werden.
$secureCode Legt fest, ob der Secure-Code aktiviert(1) oder deaktiviert (0) ist. Die Einstellung gilt für alle Formulare
$secureCodeImage nur bei aktiviertem Secure-Code: Dateiname zum Hintergrund-Bild
$secureCodeColor1 nur bei aktiviertem Secure-Code: Schriftfarbe des Codes
$secureCodeColor2 nur bei aktiviertem Secure-Code: Schriftfarbe der Ziffern im Hintergrund
$secureCodeData nur bei aktiviertem Secure-Code: Daten-Datei für die Codes
&addTemplate(); nur bei Konfigurations-Mode 1: eines oder mehrere Mail-Templates. Bei Konfigurationsmode 2 muss das Feld zwingend leer sein, bei Konfigurationsmode 3 wird die Einstellung ignoriert.
&addFTemplate("") nur bei Konfigurations-Mode 1: eines oder mehrere CSV-Templates (optional). Bei Konfigurationsmode 2 muss das Feld zwingend leer sein, bei Konfigurationsmode 3 wird die Einstellung ignoriert.

Der Pfad zu sendmail muss gemäss Informationen des Providers eingetragen werden. /usr/bin/sendmail ist auf den meisten Servern korrekt, ebenfalls weit verbreitet ist /usr/lib/sendmail. Ggf. sollten die Support-Seiten des Webhosting-Anbieters konsultiert werden.

In dem Konfigurationsmode "Templatekonfiguration innerhalb des Scriptes" muss noch der Namen der Template gemäss Informationen von Kapitel 3.2 definiert werden, ansonsten muss der Verweis auf simple.template aus dem Script gelöscht werden (Zeile &addTemplate("simple.template"); löschen).

4.2. Formular

Das Formular für den Formmailer kann natürlich nach belieben gestaltet werden. Im ZIP-Archiv befinden sich zwei Beispiele: simple.htm (einfaches Personalien-Formular) und mime.htm (Formular mit Möglichkeit zum Upload von zwei Bildern und einer beliebigen Datei). Um die Möglichkeiten von FormMailer komplett nutzen zu können sind jedoch trotzdem noch einige Informationen wichtig:

4.2.1. minimales Formular

Das Formular muss zwingend die zwei versteckten Felder "okurl" und "notokurl" beinhalten (Ausnahme: Konfigurationsmode 3 "Administrationsbereich"). Hier gibt es zwei Eingabemöglichkeiten:

Ein minimales Formular sieht also wie folgt aus:

<form action="/cgi-bin/formmailer/formmailer.cgi" method="post">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm"/>
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm"/>
<input type="submit" value="Absenden"/>
</form>

Im Konfigurationsmode 2 "Templates via Parameter" muss zwingend der Name mindestens eines Templates als versteckter Parameter übergeben werden. Dabei muss der Feldname mit "template" beginnen und den Dateinamen ohne Endung ".template" beinhalten. Folgende Zeile verwendet das Template test.tempalte im Scriptverzeichnis:

<input type="hidden" name="TEMPLATE123" value="test"/>

Im Konfigurationsmode 3 "Administrationsbereich" muss zwingend die ID der Konfiguratio versteckter Parameter übergeben werden:

<input type="hidden" name="id" value="test"/>

Dafür sind in diesem Konfigurationsmodus die versteckten Felder "okurl" und "notokurl" nicht notwendig (URLs werden Adminbereich definiert)

Übrigens: FormMailer ist es egal, ob Sie das Formular mittels method="get" oder method="post" übermitteln. Nehmen Sie, was Ihnen besser gefällt. Bei grösseren Texten sollten Sie post verwenden, da bei "get" die maximale Länge beschränkt ist (Länge browserabhängig).

4.2.2. Feldtypen

FormMailer entscheidet anhand des Feldnamens, um welchen Typ es sich handelt. Somit muss an keiner Stelle definiert werden, welche Felder existieren und welchen Typ sie haben. Folgende Möglichkeiten stehen zur Verfügung:

name Feld mit beliebigem Inhalt (auch mehrzeilig mit einer textarea)
NUM_name numerisches Feld. Es sind nur Zahlen sowie . , - und ´ erlaubt. Enthält das Feld andere Zeichen wird der Versand abgebrochen und es wird die notokurl angezeigt.
NNUL_name Pflichtfeld (auch mehrzeilig mit einer textarea). Ist das Feld leer wird der Versand abgebrochen und es wird die notokurl angezeigt.
ONELINE_name Feld mit beliebigem Inhalt. Allfällige Zeilenumbrüche werden automatisch entfernt. Dieser Feldtyp (oder MAIL_ bzw. NNMAIL_) ist bei Header-Feldern dringend empfohlen, damit es nicht möglich ist, im Header-Bereich zusätzliche Informationen einzufügen.
MAIL_name Leeres Feld oder Feld mit einer Mailadresse. Enthält das Feld andere Werte wird der Versand abgebrochen und es wird die notokurl angezeigt.
NNMAIL_name Pflichtfeld für Mailadresse. Ist das Feld leer oder enthält das Feld andere Werte wird der Versand abgebrochen und es wird die notokurl angezeigt.
EMPTY_name Wenn das Feld "name" leer ist, wird stattdessen der Wert des Feldes "EMPTY_name" verwendet (in der Regel sind EMPTY_-Felder verstecktes Felder).EMPTY-Felder sollten nicht mehr verwendet werden, da sie in einer neueren Version von FormMailer evtl. nicht mehr unterstützt werden. Empfohlen ist neu eine IF-Abfrage im Template: <!--if:name=§Text anstelle leer-->. Im Kapitel 4.3.2 ist die IF-Abfrage genauer beschrieben.
IMG_name Feld mit einem hochgeladenen Bild (GIF/JPG/PNG; Datei wird geprüft). Muss zwingend vom Typ file sein: <input type="file" name="IMG_meinbild"/>
FILE_name Feld mit einer beliebigen Datei. Muss zwingend vom Typ file sein: <input type="file" name="FILE_meinedatei"/>
HTML_name Konvertiert alle Zeilenumbrüche nach <br/>, damit sie in HTML-Mails auch als solche dargestellt werden.
MAX_name Maximale Dateigrösse des Feldes "name" (nur FILE oder IMAGE) in Bytes. Nur als fixer Wert im Konfigurationsmode 3 "Administrationsbereich" sinnvoll, da ansonsten der Wert jederzeit geändert werden kann. Beispiel: um die Maximale Dateigrösse von "FILE_myfile" auf 500kb zu beschränken, sollte im Adminbereich unter "Fixe Werte" folgendes eingetragen werden: MAX_FILE_myfile=500000

Die spezielle Feldbezeichnung wie "NNUL_" muss am Anfang des Feldes stehen. Vorher sind nur Zahlen und _ als Prefix erlaubt. Beispiel: "NNUL_test" oder "100_NNUL_test" definiert ein Pflichtfeld, "test_NNUL_test" ist jedoch ein normales Feld.

4.2.3. Welcher Feldtyp für welchen Zweck?

Den richtigen Feldtyp zu wählen ziemlich einfach. Am besten eignen sich einige Kontrollfragen:

1. Handelt es sich um eine hochgeladene Datei?
Ja
2. Handelt es sich bei der Datei um ein Bild?
Ja
Es wird der Typ IMG_ empfohlen. Alternative wäre FILE_ wenn es auch Bilder ausser JPG/GIF/PNG (z.B. BMP etc.) sein können.
Nein
Es kommt nur der Typ FILE_ in Frage, alle anderen Feldtypen funktionieren nicht.
Nein
2. Handelt es sich um ein Pflichtfeld?
Ja
3. Handelt es sich um eine Mailadresse?
Ja
Es wird der Typ NNMAIL_ empfohlen. Alternative wäre NNUL_ es auch mehrere Mailadressen sein könnten.
Nein
Es wird der Typ NNUL_ empfohlen. Wichtig: Pflichtfelder sollten nicht im Header-Bereich untergebracht werden, stattdessen sollten im Header ausschliessliche die Feldtypen MAIL_, NNMAIL_, NUM_ und ONELINE_ verwendet werden.
Nein
3. Handelt es sich um eine Mailadresse?
Ja
Es wird der Typ MAIL_ empfohlen.
Nein
4. Handelt es sich um ein Header-Feld?
Ja
Es wird DRINGEND der Typ ONLINE_ empfohlen! Bei anderen Feldtypen wäre Missbrauch des Formulars möglich. Eine Alternative wäre NUM_, falls es sich um ein numerisches Feld handelt.
Nein
5. Handelt es sich um ein numerisches Feld?
Ja
Es wird der Typ NUM_ empfohlen. Alternative wäre ein normales Feld, falls noch Währung, Landeskennzeichen oder anderer Text vorhanden sein könnte.
Nein
Es wird empfohlen, ein normales Feld zu verwenden (allenfalls HTML_, wenn Zeilenumbrüche umgewandelt werden sollen).
4.2.4. Secure-Code verwenden

Die Secure-Code Funktion kann nur pro Script-Installation und nicht template-abhängig definiert werden, da ansonsten der Schutz leicht umgangen werden könnte.

Zur Funktionsweise: Wenn die Funktion aktiviert ist, muss man in jedes Formular eine Grafik einbinden, welche eine fünfstellige Zufallszahl anzeigt. Diese muss vom Benutzer in ein eigens dafür vorgesehenes Feld eingetragen werden. Dieses Vorgehen wird mittlerweile häufig eingesetzt. Da Computer nicht in der Lage sind, diese Grafik zu "sehen", ist es mit dieser Option nicht mehr möglich, die Formulare automatisiert abzufüllen und zu versenden (Formular-Spamming). Es sei jedoch auch erwähnt, dass sehbehinderte Menschen diesen Code ebenfalls nicht sehen können und so auch nicht in der Lage sein werden, das Formular auszufüllen. Der Secure-Code sollte also erst dann eingesetzt werden, wenn andere Schutzmechanismen (z.B. Texteinschränkungen via Adminbereich) versagen und die Menge von Formmailer-Spam ein ärgerliches Ausmass annimmt.

Damit der Secure-Code funktioniert, müssen folgende Voraussetzungen erfüllt sein:

Grundprinzip

ein verstecktes Feld

<input type="hidden" name="seccodeid" value="{eindeutige Kennung}"/>

ein Eingabefeld für den Code

<input type="text" name="seccode"/>

das Bild mit dem Secure-Code (URL zur formmailer.cgi anpassen!)

<img src="formmailer.cgi?action=seccode&id={eindeutige Kennung}">

{eindeutige Kennung} kann dabei eine beliebige Zeilenfolge (Zahlen und oder Text) sein. Einzige Bedingung: die Kennung muss eindeutig sein und sich bei jedem Aufruf ändern.

Variante a) Javascript

unterhalb des Form-Tags wird folgender Code eingefügt:

<script type="text/javascript">
var id=Math.round(Math.random()*1000000000000000);
document.write('<input type="hidden" name="seccodeid" value="'+id+'"/>'); </script>

An einer beliebigen Stelle wird ein Eingabefeld für den Secure-Code eingefügt:

<input type="text" name="seccode"/>

An beliebiger Stelle (vorzugsweise neben dem Eingabefeld) wird der Secure-Code angezeigt (URL zur formmailer.cgi anpassen!):

<script type="text/javascript">
document.write('<img src="formmailer.cgi?action=seccode&id='+id+'"/>');
</script>
Variante b) PHP

Seite nach *.php umbenennen. Unterhalb des Form-Tags wird folgender Code eingefügt:

<?PHP $id=time().rand(1000,0); ?>
<input type="hidden" name="seccodeid" value="<?=$id?>"/>

An einer beliebigen Stelle wird ein Eingabefeld für den Secure-Code eingefügt:

<input type="text" name="seccode"/>

An beliebiger Stelle (vorzugsweise neben dem Eingabefeld) wird der Secure-Code angezeigt (URL zur formmailer.cgi anpassen!):

<img src="formmailer.cgi?action=seccode&id=<?=$id?>">
Variante c) Template

Wird das Formular als Template dargestellt (siehe 4.5. HTML-Template) kann die ID auch durch den Platzhalter <!--id--> eingefügt werden. Dies sieht dann so aus:

<input type="hidden" name="seccodeid" value="<!--id-->"/>

An einer beliebigen Stelle wird ein Eingabefeld für den Secure-Code eingefügt:

<input type="text" name="seccode"/>

An beliebiger Stelle (vorzugsweise neben dem Eingabefeld) wird der Secure-Code angezeigt (URL zur formmailer.cgi anpassen!):

<img src="formmailer.cgi?action=seccode&id=<!--id-->">

4.3. Mail-Template

Das Mail-Template besteht aus dem kompletten Mail. Dabei sind Mail-Header und der eigentliche Text durch eine Leerzeile getrennt, welche zwingend vorhanden sein muss.

Das Verfahren mit dem Mail-Template ist simpel: Fix-Text kann einfach eingetragen werden. Dynamischer Text kann mit <!--feldname--> eingefügt werden, wobei feldname der Name des Feldes im HTML-Formular ist.

Der Wert des Feldes <input type="text" name="MAIL_email"/> (Mailadresse oder leer) kann also im Mail-Template mit <!--MAIL_email--> eingefügt werden.

Die Zeilen

Date: <!--date-->
Message-ID: <!--msgid-->

sollten in jedem Mail belassen werden, um es korrekt zu formatieren.

4.3.1. Spezielle Felder

FormMailer bietet einige spezielle Felder, welche automatisch vom Script generiert werden und nicht aus dem Formular übergeben werden müssen:

<!--msgid--> Message-ID, wird im Header verwendet und enthät eine eindeutige Kennzeichnung des Mails gemäss Standard.
<!--ip--> IP-Adresse des Formular-Absenders.
<!--date--> Datum im Format für den Mailheader, z.B. Fri, 17 Dec 2004 20:13:55
<!--datum--> Datum in deutscher Schreibweise inkl. ausgeschriebenem Monat: 1. Januar 1970 (t. mmmm jjjj)
<!--datumTTMMJJJJ--> Datum in deutscher gekürzter Schreibweise: 01.01.1970 (tt.mm.jjjj)
<!--zeit--> Zeit inkl. Sekunden: 15:40:13 (hh:mm:ss)
<!--suppressemptyline--> Wenn auf einer Zeile dieser Tag an beliebiger Stelle vorkommt, wird die Zeile unterdrückt, sofern sie komplett leer ist (der Tag ist im Mail nicht sichtbar)
4.3.2. IF-Abfrage

Im Template ist es möglich, mittels IF-Abfrage (WENN-Bedingung) einen bestimmten Text nur dann auszugeben, wenn eine Bedingung erfüllt oder nicht erfüllt ist. Dies funktioniert im Header- und Body-Bereich. Der Syntax sieht wie folgt aus:

<!--if:feldname=wert§Text wenn Feldname=Wert-->
<!--if:feldname!wert§Text wenn Feldname ungleich Wert-->

Im Text können auch Feldnamen ausgegeben werden, müssen aber mit #!--feldname--# statt <!--feldname--> geschrieben werden. Ebenfalls kann mit \n ein Zeilenumbruch eingefügt werden. Wenn mehrere Kriterien in einer Abfrage erfüllt sein müssen, können diese mit && verkettet werden.

Beispiel für einige IF-Abfragen:

<!--name--><!--if:ort!§ aus #!--ort--#--> hat folgendes Feedback zur Homepage abgegeben:

Dies führt dazu, dass der Text "aus" nur ausgegeben wird, wenn "ort" nicht leer ist, also "Hans Muster aus Mustershausen hat folgendes Feedback zur Homepage abgegeben", aber "Hans Muster hat folgendes Feedback zur Homepage abgegeben".

Weiteres Beispiel wäre eine Absenderkopie auf Wunsch. Hierzu wird im Formular beispielsweise eine Check-Box eingefügt:

<input type="checkbox" name="kopie" value="ja"/> Ich möchte eine Kopie der Anfrage erhalten

Wir gehen davon aus, dass die E-Mail-Adresse des Absenders bereits in einem Feld "MAIL_absender" an anderer Stelle im Formular abgefragt wird. Nun muss das Template abgeändert werden:

From: <!--MAIL_absender-->
To: sales@meinedomain.ch<if:kopie=ja§\nCC: #!--MAIL_absender--#-->
Subject: Anfrage

Dies führt dazu, dass die Zeile "CC: [Absender]" nur dann eingefügt wird, wenn "kopie" den Wert "ja" enthält. Folgende Schreibweise sollte in der Regel auch funktionieren:

From: <!--MAIL_absender-->
To: sales@meinedomain.ch
CC: <if:kopie=ja§#!--MAIL_absender--#-->
Subject: Anfrage

Die folgende Schreibweise ist hingegen in Header-Feldern NICHT GESTATTET:

From: <!--MAIL_absender-->
To: sales@meinedomain.ch
<if:kopie=ja§CC: #!--MAIL_absender--#-->
Subject: Anfrage

Grund: Wenn "kopie" != "ja" wird der Text innerhalb der IF-Abfrage nicht ausgegeben, das ist ja gewollt. Der Zeilenumbruch am Ende der Zeile gehört jedoch nicht in die IF-Abfrage und würde ausgegeben werden. Dies führt zu einer Leerzeile und somit zum Abschluss des Headers, d.h. die Zeile "Subject: Anfrage" wäre nicht mehr der Betreff des Mails sondern die erste Zeile im Mail-Body.

Beim folgenden Beispiel wird der "Fehlertext" nur dann ausgegeben, wenn feldA leer ist und feldB einen Wert enthält:

<!--if:feldA=&&feldB!§Fehlertext-->

Und hier noch ein Beispiel einer IF-ELSE Abfrage. Hier wird ausgegeben, ob feldA gefüllt ist oder nicht:

<!--if:feldA=§feldA enthaelt keinen Wert§feldA enthaelt einen Wert-->
4.3.3. Feldauflistung

Selten kann es vorkommen, dass nicht alle Feldnamen des Formulares im Template bekannt sind, vor allem dann, wenn das Formular dynamisch (z.B. durch ein Fremdscript) generiert wird oder man einfach ein Mailtemplate für beliebige Formulare verwenden möchte und dabei Abstriche bei der Darstellung in Kauf nimmt.

Dafür existiert in FormMailer ein leistungsstarker aber zugegebenermassen nicht sonderlich übersichtlicher Tag.

Dabei lässt sich steuern, welche Feldnamen angezeigt, welche nicht angezeigt und welche Feldinhalte angezeigt und nicht angezeigt werden sollen. Dies wird mit Perl Regular-Expressions gesteuert:

<!--list:FeldnamenErforderlich§FeldnamenVerboten§InhaltErforderlich§InhaltVerboten-->

Hier einige Beispiele der häufigsten Möglichkeiten:

Alle Felder (leere Felder unterdrücken)
<!--list:.*§§.*§-->

Alle Felder (leere Felder NICHT unterdrücken)
<!--list:.*§§.*§%%%%%%--> (wobei %%%% ein beliebiger, nie vorkommender Wert sein kann)

Alle Felder, die mit "test" beginnen (leere Felder unterdrücken)
<!--list:test.*§§.*§-->

Alle Pflichtfelder
<!--list:NNUL_.*§§.*§-->

Alle Felder, die mit "test" oder "hallo" beginnen (leere Felder unterdrücken)
<!--list:(test|hallo).*§§.*§-->

Alle Felder, die mit "ja" im Wert enthalten
<!--list:.*§§.*ja.*§-->

Alle Felder, die eine Zahl im Wert enthalten
<!--list:.*§§.*\d.*§-->

Die Darstellung der Felder erfolgt in tabellarischer Form:

Feldname_1              Wert
Feldname_2              Wert mit einem sehr langen Text, der dann auf
                        mehrere Zeilen umbrochen wird - voellig
                        automatisch, ohne dass der Benutzer was
                        einstellen muss
Feldname_3
Feldname_4              In diesem Beispiel wird auch das leere Feld
                        Feldname_3 ausgegeben

4.4. CSV-Template

FormMailer ist in der Lage, die Formular-Daten ausser im Mail noch in einer CSV-Datei zu speichern. Dazu kann in der formmailer.cgi ein File-Template definiert werden: &addFTemplate("csv.template");. Zum CSV-Template sind folgende Anmerkungen zu machen:

4.5. HTML-Template

Für die "okurl" und "notokurl" können entweder komplette URLs oder aber auch HTML-Templates verwendet werden. Die HTML-Templates basieren auf dem gleichen Prinzip wie die Mail-Templates, d.h. in einen Platzhalter <!--feldname--> wird der Inhalt des Feldes "feldname" eingesetzt. HTML-Templates haben den Vorteil, dass Feldwerte wieder zur Verfügung stehen was gerade bei Fehlerseiten (Formular nicht vollständig ausgefüllt) sehr hilfreich sein kann. Aber auch zur Anzeige der Feldwerte als "Sendebestätigung" kann es gewünscht sein.

Um HTML-Templates zu verwenden müssen folgende Voraussetzungen erfüllt sein:

Das Feld <input type="hidden" name="okurl" value="Success123" /> würde also auf die Datei Success123.template in FormMailer-Scriptverzeichnis verweisen.

Wird das Formular im Fehlerfall (notokurl) nochmals angezeigt, ist es möglich, für den ersten Aufruf die URL formmailer.cgi?action=parsetemplate&template=myform zu verwenden: dies zeigt das Template an und verhindert so, dass ein Template sowohl als HTML-Seite für den ersten Aufruf als auch als HTML-Template für den Fehlerfall erstellt werden muss.

4.5.1. Fehlermeldungen

Wird im Falle eines Fehlers keine Fehlerseite, sondern wieder das Formular angezeigt (notokurl), so ist es natürlich möglich, eine Fehlermeldung anzuzeigen, um dem Benutzer zu zeigen, dass seine Eingaben unvollständig waren. Die Fehlermeldung kann entweder global angezeigt werden (allgemeiner Text, der darauf hinweist, dass es einen Fehler hat) oder pro Feld.

Globale Fehlermeldungen werden mittels IF-Abfrage realisiert: nur beim ersten Aufruf wird das Formular mit "action=parsetemplate" aufgerufen. Somit kann man also sagen, dass in diesem Fall das Formular noch leer und fehlerfrei ist und das Formular einen Fehler enthält, wenn der action-Tag nicht gesetzt ist. Die IF-Abfrage sieht somit so aus:

<!--if:action!parsetemplate§<p class="sysMsg">Das Formular wurde unvollständig oder fehlerhaft ausgefüllt.</p>-->

Es ist ebenfalls möglich, jedes einzelne Feld zu prüfen. Dafür existiert ein separates Feld "error". Hier kann ein Feldname und ein Text angegeben werden. Dabei wird der Text nur dann angezeigt, wenn ein Feld auch einen fehler enthält. Beispiel:

<!--error:NNUL_vorname§Bitte geben Sie einen Vornamen an.-->

Dies bewirkt, dass der Text "Bitte geben Sie einen Vornamen an." nur dann angezeigt wird, wenn das Pflichtfeld "NNUL_vorname" nicht gefüllt ist. Natürlich lassen sich diese zwei Varianten auch mischen, d.h. mit der action-Abfrage gibt man einen Text wie "Ihr Formular konnte nicht abgesendet werden, da es fehlerhaft oder unvollständig ist. Die fehlerhaften Felder sind markiert.". Mit dem error-Tag kann man dann neben jedem Feld, welches einen Fehler enthält noch einen separaten Text anzeigen.

4.6. Debugging

Um eine Liste aller übermittelten Feldewerte inkl. Feldern mit Fehler zu sehen, kann als NOTOKURL (oder auch OKURL) der Wert DEBUG eingetragen werden. Ist dies der Fall, erscheint als Ergebnisseite eine von FormMailer definierte HTML-Seite. Damit lassen sich Probleme mit ungü:tigen Formular-Namen sehr rasch erkennen.

5. Administrationsoberfläche

Die Administrationsoberfläche steht nur im Betriebsmode 3 (Administrationsbereich) und setzt eine leere Datei config.pl im Scriptverzeichnis voraus.

Ist dies der Fall, ist der Administrationsbereich unter der URL http://www.meinserver.ch/cgi-bin/formmailer/formmailer.cgi?action=admin zugänglich.

Beim ersten Aufruf muss gleich ein Passwort definiert werden, welches später unter dem Menüpunkt "Login Daten ändern" angepasst werden kann. Falls es vergessen geht, kann die Datei config.pl editiert werden, indem die Zeile "password=" gelöscht wird. Beim nächsten Aufruf des Adminbereiches muss dann ein neues Passwort definiert werden.

Im Adminbereich existiert ein Menüpunkt "Template Konfiguration". Hier können die einzelnen Templates und deren ID erstellt werden. Die "Template-ID" ist die eindeutige Erkennung des Templates und muss später im Formular als verstecktes Feld eingefügt werden:

<input type="hidden" name="id" value="myid"/>

Die zwei URLs definierten die Ziele, wenn das Formular erfolgreich abgeschickt wurde bzw. fehler enthält. Die URLs müssen absolut, also inkl. führendem http:// angegeben werden. Das Eingabefeld "Templates" dient dazu, die Mailtemplates zu definieren. Es dürfen beliebig viele Templates für ein Formular angegeben werden (pro Zeile ein Template). Die Template-Dateien müssen zwingend die Dateiendung .template aufweisen. Die Dateien müssen noch nicht zwingend existieren.

Das nächste Eingabefeld "fixe Werte" dient dazu, beliebige Werte zu definieren, welche später nicht mehr geändert werden können. Dadurch kann beispielsweise ein Template für mehrere Formulare verwendet werden und der Betreff kann im Adminbereich definiert werden (anstatt in versteckten Feldern). Ebenfalls sollten maximale Dateigrössen (MAX_name) stets im Adminbereich definiert werden, da versteckte Felder jederzeit angepasst werden können.

Die Textbox "numerische Einschränkungen" erlaubt es, numerische Werte einzuschränken (z.B. alter >= 18 etc.). Pro Zeile kann eine Einschränkung eingetragen werden. Der Syntax ist im Adminbereich beschrieben.

Die letzte Eingabefeld "Text Einschränkungen" dient dazu, die Textfelder einzuschränken und so nur bestimmte Text(muster) zuzulassen oder zu verbieten. Die Regeln müssen mit Perl Regular Expressions geschrieben werden, sind aber somit extrem flexibel. Eine kurze Erklärung zu den Regular Expressions sowie dem Syntax befindet sich im Adminbereich. Wichtig: Texteinschränkungen werden nur geprüft, wenn das Feld ausgefüllt ist. Es ist nicht möglich, mittels Regular-Expressions eine Eingabe zu verlangen, dafür muss ein Pflichtfeld-Typ NNUL_ oder NNMAIL_ verwendet werden. Ebenfalls ist die Regular-Expression stets als "enthält" zu verstehen wenn nicht explizit Feldanfang und -ende angegeben wird. \d+ heisst also, dass das Feld eine oder mehrere Zahlen enthalten muss, kann aber auch noch andere Zeichen haben. "123" aber auch "abc123def" sind somit gültige Feldinhalte.

6. Beispiel

Nachfolgend wird anhand einigen Beispiel-Szenarien der Aufbau des Formulares sowie des Mail-Templates genauer beschrieben. Ebenfalls befinden sich noch zwei Beispiel-Templates im ZIP-Archiv: simple.htm/simple.template bzw. mime.htm/mime.template. Die hier aufgeführten Formulare enthalten keine Formatierung, um nicht die zentralen Elemente durch Formatierungen zu verstecken.

Die hier aufgeführten Formulare sowie die Beispiele im ZIP-Archiv basieren auf dem Konfigurationsmode 1 "Templatekonfiguration innerhalb des Scriptes".

6.1. Beispiel 1: Homepage weiterempfehlen

Konfiguration im Script:
&addTemplate("recomment.template");

In diesem Beispiel gestalten wir ein Weiterempfehlungsformular, mit dem Besucher andere Besucher auf Ihre Homepage aufmerksam machen können. Eine Blindkopie jedes abgeschickten Mails wird ebenfalls noch an den Webmaster versendet. Dazu benötigen wir folgende Formularfelder:

Absender- und Empfängernamen definieren wir als normale Felder; natürlich sollten die Felder ausgefüllt sein, für die Funktion des Formulares ist es jedoch nicht zwingend notwendig, also wollen wir den Besucher nicht schikanieren. Wenn der Absendername nicht ausgefüllt ist, wollen wir aber einen Default-Wert verwenden.

Die Absendermailadresse soll optional sein, jedoch wenn ausgefüllt eine Mailadresse sein, auch hier nehmen wir bei leerem Feld eine Default-Mailadresse.

Die Empfängeradresse muss zwingend eine ausgefüllte Mailadresse sein, sonst kann das Mail nicht zugestellt werden.

Wir kreieren also folgendes Formular:

<form action="http://www.server.ch/cgi-bin/formmailer/formmailer.cgi" method="post">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm">
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm">
Absendername: <input type="text" name="sendername">
Absendermail: <input type="text" name="MAIL_sendermail">
Empfängername: <input type="text" name="rcptname">
Empfängermail: <input type="text" name="NNMAIL_rcptmail">
Anmerkung <textarea name="addcomment"></textarea>
<input type="submit" value="Seite weiterempfehlen">
</form>

Wir haben die Felder

Das dazu passende Mail-Template (recommend.template) könnte wie folgt aussehen:

From: <!--MAIL_sendermail--><!--if:MAIL_sendermail=§noreply@server.ch-->
To: <!--NNMAIL_rcptmail-->
BCC: webmaster@server.ch
Date: <!--date-->
Message-ID: <!--msgid-->
Subject: Tolle Homepage gefunden: http://www.server.ch

Hallo <!--rcptname-->
<!--sendername--><!--if:sendername=§Ein Besucher--> möchte dich auf die Homepage http://www.server.ch aufmerksam machen.
server.ch bietet jede Menge ... sowie ... und ist damit die erste Anlaufsstelle rund um ...
Besuche doch auch du mal http://www.server.ch und überzeuge dich selbst!

<!--sendername--> hat zu dieser Homepage noch folgende Anmerkung:
<!--addcomment-->

Die optionalen Felder werden nun mit einer IF-Abfrage so behandelt, dass diese - sofern sie nicht ausgefüllt sind - durch einen Standard-Text ersetzt werden. Das wäre schon alles: das Weiterempfehlungsformular ist einsatzbereit!

6.2. Beispiel 2: Foto für Bildergalerie

Konfiguration im Script:
&addTemplate("foto.template");
&addTemplate("fotosender.template");

In diesem Beispiel gestalten wir ein kleines Formular, mit dem der Besucher bis zu drei Fotos an den Webmaster senden kann. Der Besucher soll seinen Namen und seine Mailadresse (zwingend) angeben und kann noch einen kurzen Kommentar abgeben. Ebenfalls stellen wir mehrere Kategorien zur Verfügung, welche mittels Dropdown ausgewählt werden können. Dazu benötigen wir folgende Formularfelder:

Absendernamen definieren wir Pflichtfeld

Absendermail ist ebenfalls ein Pflichtfeld und muss eine Mailadresse sein.

Die Bilder sollen geprüft werden.

Kategorie ist ein Dropdown

<form action="http://www.server.ch/cgi-bin/formmailer/formmailer.cgi" method="post" enctype="multipart/form-data">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm">
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm">
Absendername: <input type="text" name="NNUL_sendername">
Absendermail: <input type="text" name="NNMAIL_sendermail">
Kategorie: <select name="ONELINE_cat">
<option value="Kategorie 1">Kategorie 1</option>
<option value="Kategorie 2">Kategorie 2</option>
</select>
Anmerkung <textarea name="addcomment"></textarea>
Foto1: <input type="file" name="IMG_bild1">
Foto2: <input type="file" name="IMG_bild2">
Foto3: <input type="file" name="IMG_bild3">
<input type="submit" value="Fotos senden">
</form>

Wir haben die Felder

Wichtig bei MIME-Mails ist unbedingt, dass der enctype gesetzt wird und die method=post ist: method="post" enctype="multipart/form-data"

Das dazu passende Mail-Template (foto.template) könnte wie folgt aussehen:

From: <!--NNMAIL_sendermail-->
To: fotos@server.ch
Date: <!--date-->
Message-ID: <!--msgid-->
Subject: Neue Fotos für <!--ONELINE_cat-->
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="<!--boundary-->"

--<!--boundary-->
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit

<!--NNUL_sendername--> (<!--NNMAIL_sendermail-->) hat die angehängten Fotos für die Kategorie
<!--ONELINE_cat--> zugeschickt. Dabei wurde noch folgender Kommentar verfasst:
<!--addcomment-->

<!--IMG_bild1-->
<!--IMG_bild2-->
<!--IMG_bild3-->
--<!--boundary-->--

Die Zeilen mit Content-Type und Boundary müssen im Template stehen, damit die Dateianhänge korrekt gehandhabt werden.

Nun wollen wir es aber perfekt und erstellen noch ein zweites Template (fotosender.template; tragen wir als zusätzliches &addTemplate ein), welches sich beim Absender bedankt. Dieses Mail ist einfacher aufgebaut:

From: fotos@server.ch
To: <!--NNMAIL_sendermail-->
Date: <!--date-->
Message-ID: <!--msgid-->
Subject: Deine Fotos an server.ch

Hallo <!--NNUL_sendername-->

Vielen Dank für deine Fotos. Wir werden die Fotos so schnell wie möglich in unserer Gallerie veröffentlichen.
Bei allfälligen Fragen wende dich bitte an fotos@server.ch.

--
Dies ist ein automatisch generiertes Mail.

Nun hätten wir auch das geschafft!

6.3. Beispiel 3: Feedback mit zusätzlicher Speicherung in Datei

Konfiguration im Script:
&addTemplate("feedback.template");
&addFTemplate("feedbackcsv.template");

In diesem Beispiel gestalten wir ein kleines Formular, mit dem ein Benutzer ein kurzes Feedback abgeben kann. Das Formular gestalten wir bewusst sehr rudimentär, wichtig in diesem Beispiel ist die Möglichkeit, die Daten noch als CSV-Datei zu speichern.

Wir definieren also ein kleines Formular:

<form action="http://www.server.ch/cgi-bin/formmailer/formmailer.cgi" method="post">
<input type="hidden" name="okurl" value="http://www.server.ch/danke.htm">
<input type="hidden" name="notokurl" value="http://www.server.ch/fehler.htm">
Absendername: <input type="text" name="NNUL_sendername">
Absendermail: <input type="text" name="MAIL_sendermail">
Anmerkung <textarea name="NNUL_comment"></textarea>
<input type="submit" value="Feedback senden">
</form>

Absendername und Feedback sind Pflichtfelder, die Mailadresse ist optional. Im Script definieren wir nun mehrere Templates: &addTemplate("feedback.template"); für das Mail-Formular und &addFTemplate("feedbackcsv.template"); für die Datenbank (Wichtig: "F" in addFTemplate beachten!).

Nun definieren wir das Mail-Template (feedback.template)

From: sender@server.ch
To: rcpt@server.ch
Date: <!--date-->
Message-ID: <!--msgid-->
Subject: Feedback

<!--NNUL_sendername--> (<!--MAIL_sendermail-->) hat folgendes Feedback abgegeben:
<!--NNUL_comment-->

Ebenfalls erstellen wir nun noch ein Template für die CSV-Datei (feedbackcsv.template):

<!--NNUL_sendername-->;<!--MAIL_sendermail-->;<!--NNUL_comment-->

Füllt nun jemand das Formular aus, wird ein Mail an rcpt@server.ch mit unserem Mail-Template gesendet und das Feedback ebenfalls noch in einer Datei feedbackcsv.csv im Scriptverzeichnis gespeichert (eine Zeile pro Feedback). Die CSV-Datei kann für spätere Auswertungen verwendet werden und dient als Archiv.

7. Regular Expressions in Kürze

Perl Regular-Expressions dienen der Mustererkennung von Text-Feldern. Weiterführende Informationen findet man z.B. unter http://de.wikipedia.org/wiki/Reguläre_Ausdrücke. Nachfolgend sollten die wichtigsten Funktionen aufgeführt werden. Die Regular-Expressions werden im FormMailer bei den Texteinschränkungen im Adminbereich und dem Feldauflistungstag verwendet.

. Beliebiges Zeichen
\d Ziffer (0-9), auch schreibbar als [0-9]
\D Keine Ziffer (alles ausser 0-9), auch schreibbar als [^0-9]
\w Alphanumerische Zeichen inkl. _ und Zahlen aber ohne Umlaute, auch schreibbar als [a-zA-z0-9_]
\W Nicht-Alphanumerisches Zeichen, auch schreibbar als [^a-zA-Z0-9_]
\s Leerzeichen und andere White-Spaces (\n \r \t \f [FormFeed]), auch schreibbar als [ \t\r\n\f]
\S Kein Leerzeichen, auch schreibbar als [^ \t\r\n\f]
\A oder ^ Beginn des Strings
\Z oder $ String-Ende
[] Auswahlmöglichkeiten einzelner Zeichen / ODER
(abc|def) Auswahlmöglichkeiten mehrer Zeichen / ODER (abc oder def)
\. \[ \] \( \) \{ \} \? + Die Zeichen . [ ] ( ) { } ? +
\n \t \r \f haben ihre normale Bedeutung (Zeilenumbruch, Tabulator, Carriage-Return, Form-Feed


Zudem gibt es noch spezielle Tags für Mengenangaben, wie oft ein Zeichen hintereinander vorkommen muss.

? Kein- oder einmal, {0,1}
* Keinmal bis beliebig oft {0,}
+ Ein- oder mehrmal {1,}
{7} siebenmal
{3,5} Drei- bis fünfmal
{4,} Viermal oder mehr

7.1. Beispiele

In ein paar praktischen Beispielen kann das wie folgt aussehen:

.{5} Wert muss 5 beliebige Zeichen enthalten
Hans.*Muster Muss die zwei Wörter "Hans" und "Muster" enthalten (zuerst Hans, dann Muster, dazwischen darf sich beliebiger Text befinden)
(Meer|Strand|Sand) Muss mindestens eines der erwähnten Wörter beinhalten
\d{3}\s\d{2}\s\d{2} Muss eine Kombination wie "099 99 99" enthalten (Telefonnummer, Block mit 3, 2 und 2 Zahlen, dazwischen jeweils ein Leerzeichen
[12]?\d?\d\.[12]?\d?\d\.[12]?\d?\d Muss eine IP-Adresse enthalten
^Ich.*!$ Text muss mit "Ich" beginnen und "!" enden
\d Wert muss mindestens eine Zahl enthalten (darf aber auch noch weitere Zeichen enthalten)
^\d*$ Wert darf nur Zahlen enthalten (0 bis unendlich Stellen). Sinnvoll, um ein Pflichtfeld (NNUL_) als Zahlenfeld zu definieren.

Und hier noch ein etwas ausführlicheres Beispiel für ein Zahlenfeld mit Kommastellen:

meinfeld~=~^-?[0-9]*[\.,]?[0-9]+$

Heisst:

^ Beginn des Feldes
-? Minuszeichen muss 0 oder 1x vorkommen
[0-9]* beliebige Anzahl Zahlen (0 bis unendlich)
[\.,]? ein Punkt oder ein Komma (länderspezifisches Dezimaltrennzeichen) muss 0 oder einmal vorkommen
[0-9]+ mind. 1 Zahl
$ Ende des Feldes

Somit wäre

erlaubt. Wichtig: das Erste [0-9] muss unbedingt mit einem * und nicht - was eigentlich logisch wäre - einem + geschrieben werden. Dies würde zwar bedeuten, dass bei Kommazahlen zwingend eine Zahl vor dem Punkt eingegeben werden muss (das wäre wohl beabsichtigt), heisst aber auch, dass mind. 1 Zahl kommen muss, dann optional ein Punkt und dann wieder mind. 1 Zahl. Somit erfüllt eine einstellige Zahl die erste Regel (mind. eine Zahl), die zweite (0 oder 1 Punkt, in diesem Fall 0) aber nicht die dritte (nochmals eine Zahl). Mit dieser Regel wären also nur Zahlen mit mind. 2 Stellen erlaubt.

 
 

Copyright © 2012 by Jürg Sommer, scripts@cgicorner.ch
http://www.cgicorner.ch
Letzte Änderung: 29. Januar 2012