Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Die Klasse SpamProtectionFacade führt die Prüfungen in dieser Reihenfolge aus. Die erste fehlgeschlagene Prüfung beendet die Kette:
Eine Absendung muss alle aktivierten Prüfungen bestehen. Die Inhaltsvalidierung wird nur ausgeführt, wenn das Formular auswertbare Felder liefert. Die ALTCHA-Lösung wird vor dem Rate Limit geprüft und dabei als verbraucht markiert. Das Rate Limit zählt nur Absendungen, die die vorherigen Prüfungen bestanden haben.
Die Erweiterungen sind in metadata.php unter extend eingetragen:
| OXID-Klasse | Modul-Klasse | Zweck |
|---|---|---|
OxidEsales\Eshop\Core\ViewConfig |
Mmd\AltchaIntegration\Extension\Core\ViewConfig |
Hilfsmethoden für Templates |
OxidEsales\Eshop\Application\Controller\ContactController |
Mmd\AltchaIntegration\Extension\Controller\ContactController |
Prüfung vor send() |
OxidEsales\Eshop\Application\Controller\NewsletterController |
Mmd\AltchaIntegration\Extension\Controller\NewsletterController |
Prüfung vor send() |
OxidEsales\Eshop\Application\Component\UserComponent |
Mmd\AltchaIntegration\Extension\Component\UserComponent |
Prüfung vor createUser(), nur bei cl=register |
Zusätzlich registriert das Modul den Controller mmd_altcha_challenge (Mmd\AltchaIntegration\Controller\AltchaChallengeController) und das Template @mmd_altcha/widget/altcha_widget.
oxid7-altcha-integration/
├── metadata.php # Modul-ID mmd_altcha, Einstellungen, Events
├── services.yaml # Services (autowire, öffentlich)
├── src/
│ ├── Controller/ # AltchaChallengeController
│ ├── Core/ # ModuleEvents (onActivate, onDeactivate)
│ ├── Extension/ # Erweiterungen der OXID-Klassen
│ ├── Repository/ # RateLimitRepository, UsedChallengeRepository
│ ├── Service/ # Prüfservices und Einstellungen
│ └── Struct/ # SpamCheckRequest, SpamCheckResult, AltchaChallenge, AltchaSolution
├── translations/ # Frontend-Übersetzungen (de, en)
└── views/
├── admin_twig/ # Admin-Übersetzungen (de, en)
└── twig/ # Widget und Apex-Overrides
| Service | Aufgabe |
|---|---|
SpamProtectionFacade |
Führt die Prüfkette aus |
HoneypotService |
Prüft, ob das Honeypot-Feld nicht leer ist |
ContentValidationService |
Gibberish- und Wegwerf-Domain-Prüfung |
AltchaChallengeService |
Erzeugt Challenges und prüft Lösungen |
RateLimitService |
Rate Limit für Formulare |
ChallengeRateLimitService |
Rate Limit für den Challenge-Endpunkt |
ModuleSettingsService |
Liest die Einstellungen, mit Standardwerten als Rückfall |
RateLimitRepository, UsedChallengeRepository |
Datenbankzugriff |
Kann eine Einstellung nicht gelesen werden, verwendet ModuleSettingsService den Standardwert.
Die Aktivierung legt beide Tabellen mit CREATE TABLE IF NOT EXISTS an (InnoDB, utf8mb4).
Eine Zeile pro Anfrage:
| Spalte | Typ | Inhalt |
|---|---|---|
id |
BIGINT UNSIGNED | Primärschlüssel, aus Mikrosekunden-Zeitstempel und Zufallszahl gebildet |
ip_hash |
CHAR(64) | HMAC-SHA256 aus ip: plus Client-Adresse mit dem HMAC-Geheimschlüssel |
action |
VARCHAR(50) | contact_form, newsletter_subscribe, registration oder challenge |
requested_at |
DATETIME | Zeitpunkt der Anfrage |
created_at |
DATETIME | Zeitpunkt des Eintrags |
Indizes: idx_rate_check (ip_hash, action, requested_at) und idx_cleanup (requested_at). Das Limit zählt die Zeilen mit passendem Hash und passender Aktion, deren requested_at im Zeitfenster liegt. Erst wenn die Zahl kleiner als das Maximum ist, wird eine neue Zeile geschrieben.
| Spalte | Typ | Inhalt |
|---|---|---|
id |
BIGINT UNSIGNED | Primärschlüssel |
challenge_hash |
CHAR(64) | SHA-256 der verwendeten Challenge, eindeutig |
expires_at |
DATETIME | Zeitpunkt der Verwendung plus "Challenge-Gültigkeit (Sekunden)" |
created_at |
DATETIME | Zeitpunkt des Eintrags |
Der eindeutige Index auf challenge_hash macht das Eintragen atomar: Wer dieselbe Challenge ein zweites Mal einreicht, fügt keine Zeile hinzu und wird als Wiederverwendung abgelehnt. Index idx_cleanup liegt auf expires_at.
Das Modul löscht keine Zeilen. Die Methoden RateLimitService::cleanup(), RateLimitRepository::deleteOlderThan() und UsedChallengeRepository::deleteExpired() sind vorhanden, werden aber nirgends aufgerufen, es gibt weder einen Cronjob noch einen Hook. Beide Tabellen wachsen unbegrenzt, solange du sie nicht selbst aufräumst (Anleitung auf der Seite Datenschutz).
| Event | Verhalten |
|---|---|
onActivate |
Legt die beiden Tabellen an |
onDeactivate |
Tut nichts |
Die Frontend-Texte (Widget-Beschriftungen und Fehlermeldungen, Schlüssel mit Präfix MMD_ALTCHA_) stehen in translations/de/mmd_altcha_lang.php und translations/en/mmd_altcha_lang.php. Die Admin-Bezeichnungen der Einstellungen stehen in views/admin_twig/de/mmd_altcha_lang.php und views/admin_twig/en/mmd_altcha_lang.php.