Initial commit: Frida-Fred Webseite

This commit is contained in:
2026-01-31 13:27:33 +01:00
parent 6ec7cedbfc
commit 1fccc96549
49 changed files with 3748 additions and 0 deletions

19
api/.htaccess Normal file
View File

@@ -0,0 +1,19 @@
# Verhindere direkten Zugriff auf config.php
<Files "config.php">
Order Allow,Deny
Deny from all
</Files>
# Verhindere direkten Zugriff auf send-mail.php via GET
<Files "send-mail.php">
<Limit GET>
Order Allow,Deny
Deny from all
</Limit>
</Files>
# Verstecke sensible Dateien
<FilesMatch "^(config\.php|config\.php\.example|\..*|composer\..*)">
Order Allow,Deny
Deny from all
</FilesMatch>

27
api/config.php.example Normal file
View File

@@ -0,0 +1,27 @@
<?php
/**
* Konfigurationsdatei VORLAGE für Frida & Fred Kontaktformular
*
* ANLEITUNG:
* 1. Kopiere diese Datei und benenne sie in "config.php" um
* 2. Trage deine echten SMTP-Zugangsdaten ein
* 3. config.php wird automatisch von Git ignoriert (.gitignore)
*/
// SMTP-Konfiguration
define('SMTP_HOST', 'mail.webfarben.net'); // SMTP-Server
define('SMTP_PORT', 587); // Port (587 für TLS, 465 für SSL)
define('SMTP_USERNAME', 'frida@webfarben.net'); // SMTP-Benutzername
define('SMTP_PASSWORD', 'DEIN_PASSWORT_HIER'); // ← PASSWORT HIER EINTRAGEN
define('SMTP_SECURE', 'tls'); // Verschlüsselung: 'tls' oder 'ssl'
define('SMTP_FROM_EMAIL', 'frida@webfarben.net'); // Absender-E-Mail
define('SMTP_FROM_NAME', 'Frida & Fred Kontaktformular'); // Absender-Name
// Empfänger
define('RECIPIENT_EMAIL', 'frida@webfarben.net'); // Empfänger der Kontaktanfragen
define('RECIPIENT_NAME', 'Frida & Fred'); // Name des Empfängers
// Weitere Einstellungen
define('FORM_NAME', 'Frida & Fred Kontaktformular');
define('RATE_LIMIT_SECONDS', 60); // Max. 1 Nachricht pro Minute
define('MAX_MESSAGE_LENGTH', 5000);

285
api/send-mail.php Normal file
View File

@@ -0,0 +1,285 @@
<?php
/**
* Kontaktformular Mailer für Frida & Fred
* SMTP E-Mail-Versand mit Spam-Schutz und Validierung
*/
// Output Buffering aktivieren, um saubere JSON-Antwort zu gewährleisten
ob_start();
// Fehleranzeige für Debugging (in Produktion ausschalten)
error_reporting(E_ALL);
ini_set('display_errors', 0); // Wichtig: Fehler nicht direkt ausgeben
ini_set('log_errors', 1);
// PHPMailer laden
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require __DIR__ . '/../vendor/autoload.php';
// Output Buffer leeren vor Session-Start
ob_clean();
// Session starten für Rate-Limiting
session_start();
// Konfiguration laden
if (!file_exists(__DIR__ . '/config.php')) {
ob_clean();
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Konfigurationsfehler. Bitte kontaktieren Sie den Administrator.'
]);
exit;
}
require_once __DIR__ . '/config.php';
// Header für JSON-Response setzen
header('Content-Type: application/json; charset=utf-8');
// Nur POST-Requests erlauben
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
ob_clean();
http_response_code(405);
echo json_encode([
'success' => false,
'message' => 'Nur POST-Requests erlaubt.'
]);
exit;
}
/**
* Rate-Limiting prüfen
*/
function checkRateLimit() {
if (isset($_SESSION['last_submission'])) {
$timeSinceLastSubmit = time() - $_SESSION['last_submission'];
if ($timeSinceLastSubmit < RATE_LIMIT_SECONDS) {
return [
'allowed' => false,
'wait_time' => RATE_LIMIT_SECONDS - $timeSinceLastSubmit
];
}
}
return ['allowed' => true];
}
/**
* Eingabe bereinigen und validieren
*/
function sanitizeInput($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
return $data;
}
/**
* E-Mail-Adresse validieren
*/
function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
/**
* CSRF-Token validieren (einfache Implementierung)
*/
function validateCSRF($token) {
// Erwarteter Token-Wert (sollte mit dem im Formular übereinstimmen)
return $token === 'frida-fred-csrf-2026';
}
// Rate-Limiting prüfen
$rateLimitCheck = checkRateLimit();
if (!$rateLimitCheck['allowed']) {
ob_clean();
http_response_code(429);
echo json_encode([
'success' => false,
'message' => 'Bitte warten Sie ' . $rateLimitCheck['wait_time'] . ' Sekunden, bevor Sie erneut eine Nachricht senden.'
]);
exit;
}
// Honeypot-Feld prüfen (sollte leer sein)
if (!empty($_POST['website'])) {
ob_clean();
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Spam erkannt.'
]);
exit;
}
// CSRF-Token prüfen
if (!isset($_POST['csrf_token']) || !validateCSRF($_POST['csrf_token'])) {
ob_clean();
http_response_code(403);
echo json_encode([
'success' => false,
'message' => 'Ungültiger Sicherheitstoken.'
]);
exit;
}
// Formularfelder auslesen und validieren
$name = isset($_POST['name']) ? sanitizeInput($_POST['name']) : '';
$email = isset($_POST['email']) ? sanitizeInput($_POST['email']) : '';
$subject = isset($_POST['subject']) ? sanitizeInput($_POST['subject']) : '';
$message = isset($_POST['message']) ? sanitizeInput($_POST['message']) : '';
// Pflichtfelder prüfen
if (empty($name) || empty($email) || empty($subject) || empty($message)) {
ob_clean();
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Bitte füllen Sie alle erforderlichen Felder aus.'
]);
exit;
}
// E-Mail-Adresse validieren
if (!validateEmail($email)) {
ob_clean();
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Bitte geben Sie eine gültige E-Mail-Adresse ein.'
]);
exit;
}
// Nachrichtenlänge prüfen
if (strlen($message) > MAX_MESSAGE_LENGTH) {
ob_clean();
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Ihre Nachricht ist zu lang. Maximal ' . MAX_MESSAGE_LENGTH . ' Zeichen erlaubt.'
]);
exit;
}
// E-Mail-Inhalt erstellen
$emailSubject = 'Kontaktanfrage: ' . $subject;
$emailBodyText = "Neue Kontaktanfrage über " . FORM_NAME . "\n\n";
$emailBodyText .= "Name: " . $name . "\n";
$emailBodyText .= "E-Mail: " . $email . "\n";
$emailBodyText .= "Betreff: " . $subject . "\n\n";
$emailBodyText .= "Nachricht:\n" . $message . "\n\n";
$emailBodyText .= "---\n";
$emailBodyText .= "Gesendet am: " . date('d.m.Y H:i:s') . "\n";
$emailBodyText .= "IP-Adresse: " . $_SERVER['REMOTE_ADDR'] . "\n";
// HTML-Version der E-Mail
$emailBodyHTML = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background-color: #C4B5A0; color: white; padding: 20px; text-align: center; }
.content { background-color: #f8f7f4; padding: 20px; margin-top: 20px; }
.field { margin-bottom: 15px; }
.label { font-weight: bold; color: #2c2c2c; }
.footer { margin-top: 20px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>Neue Kontaktanfrage</h2>
</div>
<div class="content">
<div class="field">
<span class="label">Von:</span> ' . htmlspecialchars($name) . '
</div>
<div class="field">
<span class="label">E-Mail:</span> <a href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($email) . '</a>
</div>
<div class="field">
<span class="label">Betreff:</span> ' . htmlspecialchars($subject) . '
</div>
<div class="field">
<span class="label">Nachricht:</span><br>
' . nl2br(htmlspecialchars($message)) . '
</div>
</div>
<div class="footer">
Gesendet am: ' . date('d.m.Y H:i:s') . '<br>
IP-Adresse: ' . $_SERVER['REMOTE_ADDR'] . '
</div>
</div>
</body>
</html>
';
// PHPMailer-Instanz erstellen
$mail = new PHPMailer(true);
try {
// SMTP-Konfiguration
$mail->isSMTP();
$mail->Host = SMTP_HOST;
$mail->SMTPAuth = true;
$mail->Username = SMTP_USERNAME;
$mail->Password = SMTP_PASSWORD;
$mail->SMTPSecure = SMTP_SECURE;
$mail->Port = SMTP_PORT;
$mail->CharSet = 'UTF-8';
// Debug-Ausgabe deaktivieren (für Produktion)
$mail->SMTPDebug = 0;
$mail->Debugoutput = function($str, $level) {
// Debug-Ausgaben unterdrücken
};
// Absender
$mail->setFrom(SMTP_FROM_EMAIL, SMTP_FROM_NAME);
$mail->addReplyTo($email, $name);
// Empfänger
$mail->addAddress(RECIPIENT_EMAIL, RECIPIENT_NAME);
// E-Mail-Inhalt
$mail->isHTML(true);
$mail->Subject = $emailSubject;
$mail->Body = $emailBodyHTML;
$mail->AltBody = $emailBodyText;
// E-Mail senden
$mail->send();
// Zeitstempel für Rate-Limiting speichern
$_SESSION['last_submission'] = time();
// Output Buffer leeren
ob_clean();
http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'Vielen Dank! Ihre Nachricht wurde erfolgreich versendet. Wir werden uns bald bei Ihnen melden.'
]);
} catch (Exception $e) {
// Fehler beim E-Mail-Versand
// Output Buffer leeren
ob_clean();
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Es gab ein Problem beim Senden Ihrer Nachricht. Bitte versuchen Sie es später erneut oder kontaktieren Sie uns direkt per E-Mail.'
// 'error' => $mail->ErrorInfo // Nur für Debugging aktivieren!
]);
}
exit;