📧 FormIt (Kontaktformular)
FormIt nutze ich als Kontaktformular, es kann aber deutlich mehr und lässt sich zum Beispiel auch als Gästebuch (nutzt das noch jemand?) oder Kommentarbereich einsetzen.
formit V 5.1.1-pl
- https://docs.modx.com/3.x/en/extras/formit/formit.tutorials-and-examples
- https://extras.modx.com/package/formit
- https://sterc.com/en/modx/modx-extras
AjaxUpload 2.0.4-pl
- https://docs.modx.com/current/en/extras/ajaxupload
- https://extras.modx.com/package/ajaxupload2
- https://jako.github.io/AjaxUpload
Chunk Beispiel: modxKontakt
(E-Mail-Adressen werden über eine eigene Verschlüsselung geschützt)
<!-- FormIt-Aufruf mit AjaxUpload, SaveForm, fiEmailEncrypt/fiDecryptMailAn -->
<!-- Felder, die von FormItSaveForm gespeichert werden -->
<!-- Anzeigenamen für FormItSaveForm müssen ALLE Felder aus &formFields abdecken -->
[[!FormIt?
&preHooks=`Formit2AjaxUpload`
&hooks=`spam,math,userAgent,fiDecryptMailAn,FormItSaveForm,AjaxUpload2Formit,AjaxUploadAttachments,email,AjaxUploadRemove,redirect`
&formName=`contactForm`
&formFields=`typ,mailAn,firstname,name,ort,telefon,email,text,row1,row2,row3,attachweb`
&fieldNames=`email==E-Mail,
firstname==Vorname,
name==Name,
typ==Darum geht's,
mailAn==Empfänger,
ort==Ort,
telefon==Telefon,
text==Nachricht,
row1==REMOTE_ADDR,
row2==REMOTE_HOST,
row3==HTTP_USER_AGENT,
attachweb==Anhänge`
&ajaxuploadTarget=`uploads/`
&ajaxuploadUid=`attachweb`
&emailTpl=`contactEmailTpl`
&emailTo=`[[+mailAn]]`
&emailSubject=`Gesendet vom Kontaktformular [[++site_name]]`
&redirectTo=`42`
&mathMinRange=`1`
&mathMaxRange=`12`
&validate=`math:required,
firstname:required:maxLength=50,
name:required:maxLength=50,
email:email:required:maxLength=60,
text:required:stripTags:maxLength=2000,
typ:required,
mailAn:required,
datenschutz:required,
name2:blank`
]]
<!-- Hinweis:
Damit FormItSaveForm keine "Undefined array key" Warnings erzeugt,
müssen alle Einträge in &formFields auch in &fieldNames vorhanden sein.
Nur wenn jedes Feld eindeutig gemappt ist, greift FormIt nicht auf
nicht existierende Keys in $fieldLabels zu. -->
[[!+fi.error.error_message:notempty=`<p class="text-danger">[[!+fi.error.error_message]]</p>`]]
<form action="[[~[[*id]]]]" method="post" class="mb-3" enctype="multipart/form-data">
<input type="hidden" name="name2" value="">
<input name="resource_id" type="hidden" value="[[+fi.id]]">
<div class="mb-3">
<p class="mb-1">
Hier könnt ihr Mitteilungen per Formular senden.
</p>
</div>
<hr>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label for="typ" class="form-label">Darum geht's</label>
<select required name="typ" id="typ" class="form-select">
<option value="">Auswahl...</option>
<option value="ThemaA" [[!+fi.typ:FormItIsSelected=`ThemaA`]]>Thema A</option>
<option value="ThemaB" [[!+fi.typ:FormItIsSelected=`ThemaB`]]>Thema B</option>
<option value="ThemaC" [[!+fi.typ:FormItIsSelected=`ThemaC`]]>Thema C</option>
<option value="ThemaD" [[!+fi.typ:FormItIsSelected=`ThemaD`]]>Thema D</option>
<option value="Sonstiges" [[!+fi.typ:FormItIsSelected=`Sonstiges`]]>Sonstiges</option>
</select>
[[+fi.error.typ:notempty=`<div class="text-danger small">[[+fi.error.typ]]</div>`]]
</div>
<div class="col-md-6">
<label for="mailAn" class="form-label">E-Mail an</label>
<select required name="mailAn" id="mailAn" class="form-select">
<option value="">Auswahl...</option>
<!-- Platzhalter-Empfänger für Anleitung -->
<option value="[[fiEmailEncrypt? &input=`empfaenger1@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`empfaenger1@example.com`]]>
Ansprechpartner 1
</option>
<option value="[[fiEmailEncrypt? &input=`empfaenger2@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`empfaenger2@example.com`]]>
Ansprechpartner 2
</option>
<option value="[[fiEmailEncrypt? &input=`empfaenger3@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`empfaenger3@example.com`]]>
Ansprechpartner 3
</option>
<option value="[[fiEmailEncrypt? &input=`admin@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`admin@example.com`]]>
Website-Administrator
</option>
</select>
[[+fi.error.mailAn:notempty=`<div class="text-danger small">[[+fi.error.mailAn]]</div>`]]
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<input required type="text" class="form-control" placeholder="Vorname"
name="firstname" id="firstname"
value="[[!+fi.firstname:htmlent]]">
[[+fi.error.firstname:notempty=`<div class="text-danger small">[[+fi.error.firstname]]</div>`]]
</div>
<div class="col-md-6">
<input required type="text" class="form-control" placeholder="Name"
name="name" id="name"
value="[[!+fi.name:htmlent]]">
[[+fi.error.name:notempty=`<div class="text-danger small">[[+fi.error.name]]</div>`]]
</div>
<div class="col-md-6">
<input type="text" class="form-control" placeholder="Ort"
name="ort" id="ort"
value="[[!+fi.ort:htmlent]]">
[[+fi.error.ort:notempty=`<div class="text-danger small">[[+fi.error.ort]]</div>`]]
</div>
<div class="col-md-6">
<input type="tel" class="form-control" placeholder="Telefon"
name="telefon" id="telefon"
value="[[!+fi.telefon:htmlent]]">
[[+fi.error.telefon:notempty=`<div class="text-danger small">[[+fi.error.telefon]]</div>`]]
</div>
<div class="col-md-6">
<input required type="email" class="form-control" placeholder="E-Mail"
name="email" id="email"
value="[[!+fi.email:htmlent]]">
[[+fi.error.email:notempty=`<div class="text-danger small">[[+fi.error.email]]</div>`]]
</div>
</div>
<div class="mb-3">
<div class="d-flex align-items-start mb-2">
<img src="[[++assets_url]]icons/32x32/text-x-generic.png" alt="Text" width="32" height="32" class="me-2">
<label for="text" class="form-label mb-0">Deine Nachricht</label>
</div>
<textarea class="form-control" placeholder="Deine Nachricht"
style="height:200px;" required
name="text" id="text">[[!+fi.text:htmlent]]</textarea>
[[+fi.error.text:notempty=`<div class="text-danger small">[[+fi.error.text]]</div>`]]
</div>
<div class="mb-3 hidden-print">
[[!AjaxUpload?
&uid=`attachweb`
&acceptedFileTypes=`image/jpeg,image/gif,image/png,image/webp,application/pdf,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document`
&maxFileSize=`8MB`
&maxFiles=`5`
&showCredits=`0`
&addCss=`1`
&addJscript=`1`
]]
<small class="form-text text-muted">(max. 5 Dateien und 8 MB!)</small>
</div>
<div class="mb-3">
<fieldset class="mb-2">
<label class="form-label">
Was ist [[!fiZahl2Text? &input=`[[!+fi.op1]]`]]
[[!+fi.operator:is=`-`:then=`weniger`:else=`und`]]
[[!fiZahl2Text? &input=`[[!+fi.op2]]`]]?
</label>
[[+fi.error.math:notempty=`<div class="text-danger small">[[+fi.error.math]]</div>`]]
<input required type="text" class="form-control w-auto"
placeholder="Scheetz uas fir Mest"
name="math" value="[[!+fi.math]]">
<input type="hidden" name="operator" value="[[!+fi.operator]]">
</fieldset>
</div>
<div class="mb-3">
<div class="form-check">
<input type="hidden" name="datenschutz[]" value="0">
<input required type="checkbox" class="form-check-input"
name="datenschutz[]" id="datenschutz"
value="1" [[!+fi.datenschutz:FormItIsChecked=`1`]]>
<label for="datenschutz" class="form-check-label">
Ich habe die <a href="[[~123]]" target="_blank">Datenschutzerklärung</a> gelesen und akzeptiert
</label>
</div>
[[+fi.error.datenschutz:notempty=`<div class="text-danger small">[[+fi.error.datenschutz]]</div>`]]
</div>
<div class="mb-3 hidden-print">
<button type="submit" class="btn btn-primary">
Abschicken
</button>
</div>
</form>
<hr>
Hinweis:
Ab AjaxUpload V2 musst du darauf achten, dass dieuidausschließlich in Kleinbuchstaben gesetzt wird, damit der Upload korrekt funktioniert. Danke an halftrainedharry.
Snippet: fiZahl2Text
<?php
# V22.11.001
# fiZahl2Text
#
# Mit dem Math Hook können Formular mit einer mathematischen Frage versehen werden, um Spam zu verhindern.
# Dieses Snippet wandelt Zahlen in einen Text um, was Spam-Bots das Berechnen erschweren sollte.
#
# Z.B.: <label>Was ist [[!fiZahl2Text? &input=`[[!+fi.op1]]`]] [[!+fi.operator:is=`-`:then=`weniger`:else=`und`]] [[!fiZahl2Text? &input=`[[!+fi.op2]]`]]?</label>
# Math Range zwischen 0 und 12, ansonsten das Snippet anpassen!
$intZahl=(int)$input;
switch ($intZahl) {
case 0:
$strZahl = 'null';
break;
case 1:
$strZahl = 'eins';
break;
case 2:
$strZahl = 'zwei';
break;
case 3:
$strZahl = 'drei';
break;
case 4:
$strZahl = 'vier';
break;
case 5:
$strZahl = 'fünf';
break;
case 6:
$strZahl = 'sechs';
break;
case 7:
$strZahl = 'sieben';
break;
case 8:
$strZahl = 'acht';
break;
case 9:
$strZahl = 'neun';
break;
case 10:
$strZahl = 'zehn';
break;
case 11:
$strZahl = 'elf';
break;
case 12:
$strZahl = 'zwölf';
break;
default:
$strZahl = 'unknown';
break;
}
return $strZahl;
Snippet: userAgent
<?php
# V 22.12.001
# Remark: Setzt für FormIt die technischen Absenderdaten.
# row1 = IP-Adresse des Besuchers
# row2 = Hostname per Reverse DNS (REMOTE_HOST ist oft nicht verfügbar)
# row3 = Browser-User-Agent
# Diese Werte werden im FormIt-Aufruf als zusätzliche Felder verwendet.
$hook->setValue('row1', $_SERVER['REMOTE_ADDR']);
# $hook->setValue('row2', $_SERVER['REMOTE_HOST']);
# Error Log: PHP warning Undefined array key $_SERVER['REMOTE_HOST']
# therefore:
$hook->setValue('row2', gethostbyaddr($_SERVER['REMOTE_ADDR']));
$hook->setValue('row3', $_SERVER['HTTP_USER_AGENT']);
return true;
🛡️ FormIt-Aufruf mit eigener Verschlüsselung um E-Mail Adressen zu schützen
- Im gezeigten FormIt-Aufruf werden E-Mail-Adressen über eine eigene Verschlüsselung geschützt.
- Dazu werden zwei Snippets benötigt.
💡 Idee
Statt E-Mail-Adressen im Klartext im HTML zu zeigen, werden sie:
- beim Rendern im Formular verschlüsselt (Snippet
fiEmailEncrypt)- beim Absenden im FormIt-Hook wieder entschlüsselt (
fiDecryptMailAn)- an den
So sieht ein Bot im HTML nur kryptische Base64-Strings, aber der Mailversand funktioniert sauber.
1) Snippet fiEmailEncrypt (E-Mail verschlüsseln)
In MODX unter Elemente → Snippets anlegen:
Name: fiEmailEncrypt
<?php
/**
* E-Mail-Adresse für Formulare verschlüsseln
* Verwendung:
* [[fiEmailEncrypt? &input=`person@example.org`]]
*/
if (empty($input)) {
return '';
}
// Schlüssel – in beiden Snippets identisch halten
$key = 'MeinGeheimerKey123';
$plain = trim($input);
$plen = strlen($plain);
$klen = strlen($key);
$outBin = '';
for ($i = 0; $i < $plen; $i++) {
$outBin .= chr(ord($plain[$i]) ^ ord($key[$i % $klen]));
}
return base64_encode($outBin);
2) Snippet fiDecryptMailAn (FormIt-Hook)
In MODX unter Elemente → Snippets anlegen:
Name: fiDecryptMailAn
<?php
/**
* FormIt-Hook: entschlüsselt mailAn
* Muss VOR dem email-Hook ausgeführt werden
*/
/** @var fiHooks $hook */
$modx = $hook->modx;
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
if ($method !== 'POST') {
return true;
}
$values = $hook->getValues();
if (!is_array($values)) {
return true;
}
$cipher = $values['mailAn'] ?? '';
if ($cipher === '') {
return true;
}
// gleicher key wie in fiEmailEncrypt
$key = 'MeinGeheimerKey123';
$klen = strlen($key);
$data = base64_decode($cipher, true);
if ($data === false) {
$hook->addError('mailAn', 'Ungültige Empfänger-Adresse (Dekodierfehler).');
return false;
}
$dlen = strlen($data);
$plain = '';
for ($i = 0; $i < $dlen; $i++) {
$plain .= chr(ord($data[$i]) ^ ord($key[$i % $klen]));
}
if (strpos($plain, '@') === false) {
$hook->addError('mailAn', 'Ungültige Empfänger-Adresse.');
return false;
}
$values['mailAn'] = $plain;
$hook->setValues($values);
return true;
3) FormIt-Aufruf (relevanter Teil)
Wichtig: fiDecryptMailAn vor email.
&hooks=`spam,math,userAgent,fiDecryptMailAn,FormItSaveForm,AjaxUpload2Formit,AjaxUploadAttachments,email,AjaxUploadRemove,redirect`
4) Select-Feld im Formular mit verschlüsselten Empfängern
<select name="mailAn" required>
<option value="">Auswahl...</option>
<option value="[[fiEmailEncrypt? &input=`empfaenger1@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`empfaenger1@example.com`]]>
Ansprechpartner 1
</option>
<option value="[[fiEmailEncrypt? &input=`empfaenger2@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`empfaenger2@example.com`]]>
Ansprechpartner 2
</option>
<option value="[[fiEmailEncrypt? &input=`admin@example.com`]]"
[[!+fi.mailAn:FormItIsSelected=`admin@example.com`]]>
Website-Administrator
</option>
</select>
✅ Ergebnis
- Keine Klartext-E-Mail-Adressen im HTML.
- Klartext wird erst im Hook wiederhergestellt.
- Voll kompatibel mit FormItSaveForm + email-Hook.
- Selektierte Optionen funktionieren wie gewohnt.
Empfehlung
Der Versand über einen echten SMTP-Server mit Authentifizierung und SSL/TLS ist deutlich zuverlässiger als die Nutzung von localhost.
Sobald alles funktioniert, solltest du daher auf SMTP umstellen. Weitere Details findest du unter „SMTP E-Mail Einrichtung“.
