b2in/packages/acme/contact-form/README.md
2026-04-10 17:18:17 +02:00

303 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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