8.2 KiB
Acme Contact Form
Ein wiederverwendbares, spam-geschütztes Kontaktformular-Package für Laravel mit Livewire. Bietet Honeypot, zeitbasierte Prüfung, Inhaltsanalyse, Rate Limiting und mehr – ohne externe Dienste, DSGVO-konform.
Features
- Spam-Schutz: Honeypot, Zeitprüfung, Inhaltsanalyse, Wegwerf-E-Mails, Rate Limiting, IP-Blacklist, Bot-User-Agent-Erkennung
- Konfigurierbare Felder: Presets (simple, full) oder eigene Felddefinitionen
- Livewire: Reaktives Formular ohne Page-Reload
- Flexibel: Einfache Formulare bis komplexe Multi-Feld-Formulare
- DSGVO-konform: Keine externen Services, alles in-house
Voraussetzungen
- PHP 8.2+
- Laravel 10+ / 11+ / 12+
- Livewire 3+
Installation
1. Package installieren
composer require acme/contact-form
Für lokale Entwicklung (Path-Repository):
{
"repositories": [
{
"type": "path",
"url": "package/acme/contact-form"
}
],
"require": {
"acme/contact-form": "@dev"
}
}
composer update acme/contact-form
2. Konfiguration
php artisan vendor:publish --tag=contact-form-config
In .env:
CONTACT_FORM_RECIPIENT=kontakt@ihre-domain.de
CONTACT_FORM_MAX_ATTEMPTS=3
CONTACT_FORM_DECAY_MINUTES=15
CONTACT_FORM_MIN_FILL_TIME=3
3. Übersetzungen (optional)
php artisan vendor:publish --tag=contact-form-lang
Verwendung
Einfaches Formular (Preset: simple)
Name, E-Mail, Nachricht, Datenschutz-Checkbox:
<livewire:contact-form />
Oder mit explizitem Preset:
<livewire:contact-form preset="simple" subject="Kontaktanfrage" />
Vollständiges Formular (Preset: full)
Vorname, Nachname, E-Mail, Telefon, Unternehmen, Nachricht, Datenschutz:
<livewire:contact-form preset="full" subject="Neue Kontaktanfrage" />
Eigenes Formular mit benutzerdefinierten Feldern
Sie können beliebige Felder definieren. Jedes Feld benötigt:
type:text,email,tel,textarea,select,checkbox,honeypotrules: Laravel-Validierungsregeln (Array)label: Anzeigename (optional)placeholder: Platzhalter (optional)required: true/false (optional, wird aus rules abgeleitet)name: Formularfeld-Name (optional, Standard: Array-Key)options: Fürselect– Array [value => label] (optional)
Beispiel: Minimales Formular (nur E-Mail + Nachricht)
<livewire:contact-form
:fields="[
'email' => [
'type' => 'email',
'rules' => ['required', 'email:rfc,dns', 'max:150'],
'label' => 'Ihre E-Mail',
'placeholder' => 'name@beispiel.de',
],
'message' => [
'type' => 'textarea',
'rules' => ['required', 'string', 'max:2000'],
'label' => 'Nachricht',
],
'privacy' => [
'type' => 'checkbox',
'rules' => ['accepted'],
'label' => 'Ich stimme der Datenschutzerklärung zu.',
],
'honeypot' => [
'type' => 'honeypot',
'name' => 'website',
'rules' => ['nullable', 'string', 'max:0'],
],
]"
subject="Feedback"
/>
Beispiel: Formular mit Select-Feld
<livewire:contact-form
:fields="[
'name' => [
'type' => 'text',
'rules' => ['required', 'string', 'max:120'],
'label' => 'Name',
],
'email' => [
'type' => 'email',
'rules' => ['required', 'email:rfc,dns'],
'label' => 'E-Mail',
],
'topic' => [
'type' => 'select',
'rules' => ['required', 'string', 'in:general,support,sales'],
'label' => 'Betreff',
'placeholder' => 'Bitte wählen...',
'options' => [
'general' => 'Allgemeine Anfrage',
'support' => 'Technischer Support',
'sales' => 'Verkauf',
],
],
'message' => [
'type' => 'textarea',
'rules' => ['required', 'string', 'max:2000'],
'label' => 'Nachricht',
],
'privacy' => [
'type' => 'checkbox',
'rules' => ['accepted'],
'label' => 'Datenschutz akzeptiert',
],
'honeypot' => [
'type' => 'honeypot',
'name' => 'company_check',
'rules' => ['nullable', 'string', 'max:0'],
],
]"
subject="Anfrage über Kontaktformular"
/>
Wichtig: Jedes Formular sollte ein Honeypot-Feld enthalten. Das Feld wird für Nutzer unsichtbar dargestellt; Bots füllen es oft aus und werden so erkannt.
Eigene Presets in der Config
In config/contact-form.php können Sie eigene Presets definieren:
'presets' => [
'mein-formular' => [
'name' => [
'type' => 'text',
'rules' => ['required', 'string', 'max:120'],
'label' => 'Name',
],
'email' => [
'type' => 'email',
'rules' => ['required', 'email:rfc,dns'],
'label' => 'E-Mail',
],
'message' => [
'type' => 'textarea',
'rules' => ['required', 'string', 'max:2000'],
'label' => 'Nachricht',
],
'privacy' => [
'type' => 'checkbox',
'rules' => ['accepted'],
'label' => 'Datenschutz',
],
'honeypot' => [
'type' => 'honeypot',
'name' => 'website',
'rules' => ['nullable', 'string', 'max:0'],
],
],
],
Verwendung:
<livewire:contact-form preset="mein-formular" />
Spam-Schutz im Detail
| Maßnahme | Beschreibung |
|---|---|
| Honeypot | Verstecktes Feld – wenn ausgefüllt → Spam |
| Zeitprüfung | Formular < 3 Sek. ausgefüllt → Spam |
| Inhaltsanalyse | Spam-Keywords, URLs, XSS-Muster → Spam |
| Wegwerf-E-Mails | tempmail.com, mailinator.com etc. → Spam |
| Rate Limiting | Max. 3 Anfragen/IP in 15 Min. (konfigurierbar) |
| IP-Blacklist | Blockierte IPs in Config |
| Bot-User-Agent | curl, wget, python-requests etc. → Spam |
Bei Spam wird immer eine Erfolgsmeldung angezeigt (Täuschung von Bots), aber keine E-Mail versendet. Alle Anfragen werden geloggt.
Service und SpamDetector direkt nutzen
Falls Sie einen eigenen Controller oder eine eigene Livewire-Komponente verwenden möchten:
use Acme\ContactForm\ContactFormService;
use Acme\ContactForm\SpamDetector;
// Spam prüfen
$spamDetector = SpamDetector::fromConfig();
$isSpam = $spamDetector->detect($validatedData, $formLoadedAt);
// Anfrage verarbeiten
$service = app(ContactFormService::class);
$service->handle([
'name' => $request->input('name'),
'email' => $request->input('email'),
'message' => $request->input('message'),
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'is_spam' => $isSpam,
], 'Betreff der E-Mail', 'Log-Kontext');
Konfiguration
| Option | Beschreibung | Standard |
|---|---|---|
recipient |
E-Mail-Empfänger | aus .env |
rate_limit.max_attempts |
Max. Anfragen pro IP | 3 |
rate_limit.decay_minutes |
Zeitfenster in Minuten | 15 |
blacklisted_ips |
IP-Adressen blockieren | [] |
honeypot_fields |
Namen der Honeypot-Felder | company_check, website, url |
spam.min_fill_time_seconds |
Min. Zeit zum Ausfüllen | 3 |
spam.suspicious_patterns |
Regex für Spam-Erkennung | siehe Config |
spam.disposable_email_domains |
Wegwerf-Domains | siehe Config |
Styling anpassen
Die Standard-Views nutzen generische Klassen (border-gray-300, focus:ring-primary). Passen Sie sie an Ihr Design an:
php artisan vendor:publish --tag=contact-form-views
Die Views liegen dann unter resources/views/vendor/contact-form/.
Event nach Absenden
Nach erfolgreichem Absenden wird das Event contact-form-submitted dispatched. Sie können darauf reagieren:
<div x-data="{ submitted: false }"
x-on:contact-form-submitted.window="submitted = true">
<livewire:contact-form />
<template x-if="submitted">
<p>Vielen Dank für Ihre Nachricht!</p>
</template>
</div>
Lizenz
MIT License