From c2f27097904c797c013a9efcc5e0c60177d1fb7b Mon Sep 17 00:00:00 2001
From: greggy
Date: Thu, 14 May 2026 19:12:43 +0000
Subject: [PATCH] feat(contact): server-side PHP mail handler for contact form
Fix #34: E-Mail-Versand via PHP
- PHP POST handler with server-side validation (name, email, message)
- mail() with From/Reply-To set to form email address
- Recipient: mki@kies-media.de
- Honeypot spam protection (hidden field)
- Minimum submit time check (3 seconds)
- Session-based rate limiting (60s between submissions)
- Header injection protection
- Error messages displayed above form
- Success message after successful send
- Form values preserved on validation errors
- Removed client-side mailto: JavaScript logic
- Added CSS for error display and honeypot hiding
---
css/haus-schleusingen.css | 30 ++++++++
index.php | 152 ++++++++++++++++++++++++++++++++++----
js/haus-schleusingen.js | 30 +-------
3 files changed, 170 insertions(+), 42 deletions(-)
diff --git a/css/haus-schleusingen.css b/css/haus-schleusingen.css
index 0bf8e52..68a09b1 100644
--- a/css/haus-schleusingen.css
+++ b/css/haus-schleusingen.css
@@ -991,6 +991,36 @@ nav.scrolled .nav-hamburger span::after {
transform: translateY(-1px);
}
+.form-errors {
+ background: #fdf2f2;
+ border: 1px solid #e8a0a0;
+ padding: 1rem 1.2rem;
+ margin-bottom: 1.2rem;
+}
+
+.form-errors ul {
+ margin: 0;
+ padding: 0 0 0 1.2rem;
+ list-style: disc;
+}
+
+.form-errors li {
+ font-size: 0.85rem;
+ color: #9e2c2c;
+ line-height: 1.6;
+}
+
+.hp-field {
+ position: absolute;
+ left: -9999px;
+ top: -9999px;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ opacity: 0;
+ pointer-events: none;
+}
+
.form-success {
display: none;
text-align: center;
diff --git a/index.php b/index.php
index b59badf..c1c1587 100644
--- a/index.php
+++ b/index.php
@@ -1,3 +1,104 @@
+ '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => ''];
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Collect and normalize input
+ $formData['fname'] = normalizeContactValue((string) ($_POST['fname'] ?? ''));
+ $formData['lname'] = normalizeContactValue((string) ($_POST['lname'] ?? ''));
+ $formData['email'] = normalizeContactValue((string) ($_POST['email'] ?? ''));
+ $formData['phone'] = normalizeContactValue((string) ($_POST['phone'] ?? ''));
+ $formData['interest'] = normalizeContactValue((string) ($_POST['interest'] ?? ''));
+ $formData['message'] = normalizeContactValue((string) ($_POST['message'] ?? ''));
+
+ // Honeypot check – hidden field must be empty
+ $honeypot = normalizeContactValue((string) ($_POST['website'] ?? ''));
+ if ($honeypot !== '') {
+ // Bot detected – pretend success
+ $formSuccess = true;
+ $formData = ['fname' => '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => ''];
+ } else {
+ // Server-side validation
+ if ($formData['fname'] === '') {
+ $formErrors[] = 'Bitte geben Sie Ihren Vornamen an.';
+ }
+ if ($formData['lname'] === '') {
+ $formErrors[] = 'Bitte geben Sie Ihren Nachnamen an.';
+ }
+ if ($formData['email'] === '' || !filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) {
+ $formErrors[] = 'Bitte geben Sie eine gültige E-Mail-Adresse an.';
+ }
+ if ($formData['message'] === '') {
+ $formErrors[] = 'Bitte geben Sie eine Nachricht ein.';
+ }
+
+ // Header injection check
+ if (containsHeaderInjection($formData['email']) || containsHeaderInjection($formData['fname'] . ' ' . $formData['lname'])) {
+ $formErrors[] = 'Ungültige Zeichen in den Eingabefeldern.';
+ }
+
+ // Minimum time check – form submitted too fast (< 3 seconds)
+ $formTime = isset($_POST['form_time']) ? (int) $_POST['form_time'] : 0;
+ if ($formTime > 0 && (time() - $formTime) < 3) {
+ $formErrors[] = 'Das Formular wurde zu schnell abgeschickt. Bitte versuchen Sie es erneut.';
+ }
+
+ // Session rate limit – max 1 submission per 60 seconds
+ $lastSubmit = $_SESSION['last_contact_submit'] ?? 0;
+ if ($lastSubmit && (time() - $lastSubmit) < 60) {
+ $formErrors[] = 'Bitte warten Sie einen Moment vor der nächsten Anfrage.';
+ }
+
+ // Send email if no errors
+ if (empty($formErrors)) {
+ $to = 'mki@kies-media.de';
+ $subject = 'Kontaktanfrage: ' . $formData['interest'];
+ $body = "Von: {$formData['fname']} {$formData['lname']}\n"
+ . "E-Mail: {$formData['email']}\n";
+ if ($formData['phone'] !== '') {
+ $body .= "Telefon: {$formData['phone']}\n";
+ }
+ $body .= "Anliegen: {$formData['interest']}\n\n"
+ . $formData['message'];
+
+ $headers = "From: {$formData['email']}\r\n";
+ $headers .= "Reply-To: {$formData['email']}\r\n";
+ $headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
+ $headers .= "X-Mailer: PHP/" . phpversion();
+
+ $mailSent = mail($to, $subject, $body, $headers);
+
+ if ($mailSent) {
+ $formSuccess = true;
+ $_SESSION['last_contact_submit'] = time();
+ $formData = ['fname' => '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => ''];
+ } else {
+ $formErrors[] = 'Leider konnte die E-Mail nicht gesendet werden. Bitte versuchen Sie es später erneut oder schreiben Sie uns direkt an mki@kies-media.de.';
+ }
+ }
+ }
+}
+?>
@@ -531,15 +632,31 @@
paar Terminvorschläge an.
@@ -576,16 +698,20 @@
name="message"
rows="4"
placeholder="Ihre Nachricht ..."
- >
+ required
+ >= escapeContactValue($formData['message']) ?>
+
+
+
+
+
+
+
-
+