303 lines
8.2 KiB
Markdown
303 lines
8.2 KiB
Markdown
# 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
|
||
|
||
```bash
|
||
composer require acme/contact-form
|
||
```
|
||
|
||
Für lokale Entwicklung (Path-Repository):
|
||
|
||
```json
|
||
{
|
||
"repositories": [
|
||
{
|
||
"type": "path",
|
||
"url": "package/acme/contact-form"
|
||
}
|
||
],
|
||
"require": {
|
||
"acme/contact-form": "@dev"
|
||
}
|
||
}
|
||
```
|
||
|
||
```bash
|
||
composer update acme/contact-form
|
||
```
|
||
|
||
### 2. Konfiguration
|
||
|
||
```bash
|
||
php artisan vendor:publish --tag=contact-form-config
|
||
```
|
||
|
||
In `.env`:
|
||
|
||
```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)
|
||
|
||
```bash
|
||
php artisan vendor:publish --tag=contact-form-lang
|
||
```
|
||
|
||
## Verwendung
|
||
|
||
### Einfaches Formular (Preset: simple)
|
||
|
||
Name, E-Mail, Nachricht, Datenschutz-Checkbox:
|
||
|
||
```blade
|
||
<livewire:contact-form />
|
||
```
|
||
|
||
Oder mit explizitem Preset:
|
||
|
||
```blade
|
||
<livewire:contact-form preset="simple" subject="Kontaktanfrage" />
|
||
```
|
||
|
||
### Vollständiges Formular (Preset: full)
|
||
|
||
Vorname, Nachname, E-Mail, Telefon, Unternehmen, Nachricht, Datenschutz:
|
||
|
||
```blade
|
||
<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`, `honeypot`
|
||
- `rules`: 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ür `select` – Array [value => label] (optional)
|
||
|
||
**Beispiel: Minimales Formular (nur E-Mail + Nachricht)**
|
||
|
||
```blade
|
||
<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**
|
||
|
||
```blade
|
||
<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:
|
||
|
||
```php
|
||
'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:
|
||
|
||
```blade
|
||
<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:
|
||
|
||
```php
|
||
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:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```blade
|
||
<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
|