first commit

This commit is contained in:
2026-02-03 09:01:55 +01:00
commit 52e26e3989
114 changed files with 94751 additions and 0 deletions

36
forms/.htaccess Normal file
View File

@@ -0,0 +1,36 @@
# Schütze config.php und andere sensible Dateien
<Files "config.php">
Require all denied
</Files>
<Files "test-*.php">
Require all denied
</Files>
# Verhindere Directory Listing
Options -Indexes
# Blockiere Zugriff auf Backup-Dateien
<FilesMatch "\.(bak|backup|old|orig|save|swp|tmp)$">
Require all denied
</FilesMatch>
# Verhindere Zugriff auf versteckte Dateien
<FilesMatch "^\.">
Require all denied
</FilesMatch>
# PHP-Sicherheitseinstellungen
<IfModule mod_php7.c>
php_flag display_errors off
php_flag log_errors on
php_value upload_max_filesize 20M
php_value post_max_size 20M
</IfModule>
# Zusätzliche Sicherheits-Header
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
</IfModule>

2
forms/Readme.txt Normal file
View File

@@ -0,0 +1,2 @@
Fully working PHP/AJAX contact form script is available in the pro version of the template.
You can buy it from: https://bootstrapmade.com/day-multipurpose-html-template-for-free/

54
forms/config.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
/**
* WICHTIG: Diese Datei ist veraltet!
* Bitte verwenden Sie stattdessen die neue config.php im Hauptverzeichnis
* oder noch besser: Verschieben Sie die Config außerhalb des Webroots
*
* Diese Datei wird aus Kompatibilitätsgründen beibehalten, sollte aber
* durch die neue Sicherheitskonfiguration ersetzt werden.
*
* Siehe: /config.php oder /SECURITY.md für Anweisungen
*/
// Sicherheitskonstante setzen
define('CONFIG_LOADED', true);
// Empfänger-E-Mail-Adresse
define('RECEIVING_EMAIL', 'webkontakt@hkw-anwaelte.de');
// SMTP-Konfiguration
// WARNUNG: Diese Credentials sollten in Umgebungsvariablen gespeichert werden!
define('SMTP_CONFIG', [
'host' => 'mail.webfarben.net',
'username' => 'hkw@webfarben.net',
'password' => 'B^o16ei32', // ACHTUNG: Bitte in .env auslagern!
'port' => '465',
'secure' => 'ssl',
'auth' => true
]);
// reCAPTCHA Secret Key
// WARNUNG: Sollte in Umgebungsvariablen gespeichert werden!
define('RECAPTCHA_SECRET', '6LfXn6kqAAAAAJGZ3H371N7kFeNYj7-HW8osLgLq');
// Sicherheitseinstellungen
define('RATE_LIMIT_MAX', 5);
define('RATE_LIMIT_WINDOW', 3600);
define('MIN_FORM_TIME', 5);
define('MAX_FILE_SIZE', 20 * 1024 * 1024);
// Erlaubte Dateitypen
define('ALLOWED_FILE_TYPES', ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png']);
// Spam-Wort-Blacklist
define('SPAM_WORDS', [
'casino', 'viagra', 'lottery', 'winner', 'cialis',
'sex', 'porn', 'loan', 'bitcoin', 'escort', 'xxx',
'pharmacy', 'earn money', 'credit', 'crypto'
]);
// E-Mail-Domain-Blacklist
define('SPAM_DOMAINS', [
'mail.ru', 'yopmail.com', 'tempmail', 'trashmail',
'10minutemail', 'guerrillamail', 'mailinator'
]);

261
forms/contact.php Normal file
View File

@@ -0,0 +1,261 @@
<?php
// Fehlerausgabe komplett deaktivieren
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/error.log'); // Optional: Fehler in Log-Datei schreiben
// Buffer starten
ob_start();
// Sicherheitskonstante setzen
define('CONFIG_LOADED', true);
// Config laden (prüfe zuerst außerhalb des webroot)
if (file_exists(__DIR__ . '/../config.php')) {
require_once __DIR__ . '/../config.php';
} elseif (file_exists(__DIR__ . '/config.php')) {
require_once __DIR__ . '/config.php';
} else {
die('Configuration file not found');
}
require_once __DIR__ . '/../assets/vendor/php-email-form/php-email-form.php';
// Rate Limiting mit Konstanten aus Config
function checkRateLimit() {
$ip = $_SERVER['REMOTE_ADDR'];
$file = sys_get_temp_dir() . '/email_' . hash('sha256', $ip . date('Y-m-d-H'));
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
$now = time();
// Max RATE_LIMIT_MAX E-Mails pro RATE_LIMIT_WINDOW
if ($data['count'] >= RATE_LIMIT_MAX && ($now - $data['timestamp']) < RATE_LIMIT_WINDOW) {
return false;
}
if (($now - $data['timestamp']) >= RATE_LIMIT_WINDOW) {
$data = ['count' => 1, 'timestamp' => $now];
} else {
$data['count']++;
}
} else {
$data = ['count' => 1, 'timestamp' => time()];
}
file_put_contents($file, json_encode($data), LOCK_EX);
return true;
}
// Erweiterte Validierung mit XSS-Schutz
function validateInput($data) {
// Leere Felder prüfen
if (empty($data['name']) || empty($data['email']) || empty($data['message'])) {
return ['valid' => false, 'message' => 'Bitte füllen Sie alle Pflichtfelder aus.'];
}
// E-Mail-Format prüfen
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return ['valid' => false, 'message' => 'Bitte geben Sie eine gültige E-Mail-Adresse ein.'];
}
// Zusätzliche E-Mail-Validierung (keine Header-Injection)
if (preg_match('/[\r\n]/', $data['email']) || preg_match('/[\r\n]/', $data['name'])) {
return ['valid' => false, 'message' => 'Ungültige Zeichen erkannt.'];
}
// Längenbeschränkungen
if (strlen($data['name']) > 100) {
return ['valid' => false, 'message' => 'Der Name ist zu lang.'];
}
if (strlen($data['message']) < 10) {
return ['valid' => false, 'message' => 'Ihre Nachricht ist zu kurz.'];
}
if (strlen($data['message']) > 5000) {
return ['valid' => false, 'message' => 'Ihre Nachricht ist zu lang.'];
}
// Spam-Wörter aus Config prüfen
foreach (SPAM_WORDS as $word) {
if (stripos($data['message'], $word) !== false || stripos($data['name'], $word) !== false) {
return ['valid' => false, 'message' => 'Ihre Nachricht wurde als Spam erkannt.'];
}
}
return ['valid' => true];
}
// XSS-Schutz für Ausgaben
function sanitizeOutput($string) {
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
// reCAPTCHA Validierung mit Config-Konstante
function validateRecaptcha($recaptchaResponse) {
if (empty($recaptchaResponse)) {
return false;
}
$secret = RECAPTCHA_SECRET;
$url = 'https://www.google.com/recaptcha/api/siteverify';
$data = [
'secret' => $secret,
'response' => $recaptchaResponse,
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
'timeout' => 10
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
]
];
$context = stream_context_create($options);
$result = @file_get_contents($url, false, $context);
if ($result === false) {
error_log('reCAPTCHA API request failed');
return false;
}
$responseData = json_decode($result);
return isset($responseData->success) && $responseData->success === true;
}
// Honeypot-Feld prüfen
if (!empty($_POST['website'])) {
echo json_encode([
'success' => false,
'message' => 'Spam erkannt.'
]);
exit;
}
// Zeitbasierte Validierung mit Config-Konstante
if (isset($_POST['form_start'])) {
$delta = time() - intval($_POST['form_start'] / 1000);
if ($delta < MIN_FORM_TIME) { // Zu schnell ausgefüllt
echo json_encode([
'success' => false,
'message' => 'Zu schnell abgesendet. Bitte versuchen Sie es erneut.'
]);
exit;
}
}
// Hauptlogik
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Nur POST-Requests erlaubt']);
exit;
}
try {
// Rate Limit prüfen
if (!checkRateLimit()) {
echo json_encode([
'success' => false,
'message' => 'Aus Sicherheitsgründen können Sie nur 5 Nachrichten pro Stunde senden. Bitte versuchen Sie es später erneut.'
]);
exit;
}
// reCAPTCHA prüfen
$recaptchaResponse = $_POST['g-recaptcha-response'] ?? '';
if (!validateRecaptcha($recaptchaResponse)) {
echo json_encode([
'success' => false,
'message' => 'Bitte bestätigen Sie, dass Sie kein Robot sind.'
]);
exit;
}
// Formulardaten sammeln und bereinigen
$formData = [
'name' => trim($_POST['name'] ?? ''),
'email' => trim($_POST['email'] ?? ''),
'mobile' => trim($_POST['mobilenumber'] ?? ''),
'message' => trim($_POST['message'] ?? '')
];
// E-Mail-Domain-Blacklist aus Config
foreach (SPAM_DOMAINS as $domain) {
if (stripos($formData['email'], $domain) !== false) {
echo json_encode([
'success' => false,
'message' => 'Bitte verwenden Sie eine echte E-Mail-Adresse.'
]);
exit;
}
}
// Eingaben validieren
$validation = validateInput($formData);
if (!$validation['valid']) {
echo json_encode([
'success' => false,
'message' => $validation['message']
]);
exit;
}
// E-Mail erstellen
$contact = new PHP_Email_Form;
$contact->ajax = true;
$contact->to = RECEIVING_EMAIL;
$contact->from_name = $formData['name'];
$contact->from_email = 'hkw@webfarben.net';
$contact->reply_to = $formData['email'];
$contact->subject = "Neue Kontaktanfrage von " . $formData['name'];
$contact->smtp = SMTP_CONFIG;
// Nachricht zusammenbauen
$contact->add_message($formData['name'], 'Name');
$contact->add_message($formData['email'], 'E-Mail');
$contact->add_message($formData['mobile'], 'Telefon');
$contact->add_message($formData['message'], 'Nachricht');
// Dateianhang verarbeiten mit Sicherheitschecks
if (isset($_FILES['resume']) && $_FILES['resume']['error'] == UPLOAD_ERR_OK) {
// Dateigröße prüfen
if ($_FILES['resume']['size'] > MAX_FILE_SIZE) {
echo json_encode([
'success' => false,
'message' => 'Die Datei ist zu groß (max. 20 MB).'
]);
exit;
}
$contact->add_attachment('resume', 20, ALLOWED_FILE_TYPES);
}
// E-Mail senden
$result = $contact->send();
echo json_encode([
'success' => ($result === 'OK'),
'message' => ($result === 'OK')
? "Ihre Nachricht wurde erfolgreich gesendet an: " . RECEIVING_EMAIL
: "Fehler beim Senden: " . $result
]);
} catch (Exception $e) {
error_log("Mailer Error: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => "Ein Fehler ist aufgetreten: " . $e->getMessage()
]);
}

78
forms/test-form.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
<!DOCTYPE html>
<html>
<head>
<title>Kontaktformular Test</title>
<style>
.success-message { color: green; padding: 10px; }
.error-message { color: red; padding: 10px; }
</style>
</head>
<body>
<h2>Kontaktformular Test</h2>
<div id="response-message"></div>
<form action="contact.php" method="POST" enctype="multipart/form-data">
<p>
<label>Name:</label><br>
<input type="text" name="name" value="Test Person">
</p>
<p>
<label>E-Mail:</label><br>
<input type="email" name="email" value="test@example.com">
</p>
<p>
<label>Telefon:</label><br>
<input type="text" name="mobilenumber" value="0123456789">
</p>
<p>
<label>Nachricht:</label><br>
<textarea name="message">Dies ist eine Test-Nachricht</textarea>
</p>
<p>
<label>Anhang (optional):</label><br>
<input type="file" name="resume">
</p>
<button type="submit">Senden</button>
</form>
<script>
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
let formData = new FormData(this);
fetch('contact.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
const messageDiv = document.getElementById('response-message');
messageDiv.className = data.success ? 'success-message' : 'error-message';
messageDiv.textContent = data.message;
if (data.success) {
// Optional: Formular zurücksetzen
this.reset();
}
})
.catch(error => {
console.error('Error:', error);
const messageDiv = document.getElementById('response-message');
messageDiv.className = 'error-message';
messageDiv.textContent = 'Ein Fehler ist aufgetreten';
});
});
</script>
</body>
</html>

26
forms/test-paths.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$vendorDir = dirname(__DIR__) . '/assets/vendor';
$files = [
'/phpmailer/src/Exception.php',
'/phpmailer/src/PHPMailer.php',
'/phpmailer/src/SMTP.php'
];
echo "<h2>Pfad-Test</h2>";
echo "Vendor Directory: " . $vendorDir . "<br><br>";
foreach ($files as $file) {
$fullPath = $vendorDir . $file;
echo "Checking: " . $fullPath . "<br>";
if (file_exists($fullPath)) {
echo "✅ Datei existiert<br>";
echo "Dateirechte: " . substr(sprintf('%o', fileperms($fullPath)), -4) . "<br>";
echo "Dateigröße: " . filesize($fullPath) . " bytes<br>";
} else {
echo "❌ Datei nicht gefunden<br>";
}
echo "<br>";
}