Charity costs added
This commit is contained in:
@@ -3,13 +3,34 @@ session_start();
|
||||
|
||||
// Honeypot: if a bot filled in a hidden field, silently discard
|
||||
if (!empty($_POST['website'])) {
|
||||
header('Location: index.php?sent=1#contact');
|
||||
header('Location: /?sent=1#contact');
|
||||
exit;
|
||||
}
|
||||
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$message = trim($_POST['message'] ?? '');
|
||||
// Rate Limiting: Session and IP-based cooldown
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$cooldown_time = 300; // 5 minutes
|
||||
|
||||
// Session-based cooldown
|
||||
if (isset($_SESSION['last_submission']) && (time() - $_SESSION['last_submission'] < $cooldown_time)) {
|
||||
header('Location: /?error=too_fast#contact');
|
||||
exit;
|
||||
}
|
||||
|
||||
// IP-based cooldown using a temporary file
|
||||
$ip_file = sys_get_temp_dir() . '/fraxle_rate_' . md5($ip);
|
||||
if (file_exists($ip_file)) {
|
||||
$last_hit = (int)file_get_contents($ip_file);
|
||||
if ((time() - $last_hit) < $cooldown_time) {
|
||||
header('Location: /?error=too_fast#contact');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
file_put_contents($ip_file, time());
|
||||
|
||||
$name = str_replace(["\r", "\n"], '', trim($_POST['name'] ?? ''));
|
||||
$email = str_replace(["\r", "\n"], '', trim($_POST['email'] ?? ''));
|
||||
$message = str_replace(["\r", "\n"], '', trim($_POST['message'] ?? ''));
|
||||
$captcha = intval($_POST['captcha'] ?? -9999);
|
||||
$expected = intval($_SESSION['captcha_answer'] ?? -1);
|
||||
|
||||
@@ -17,22 +38,35 @@ $expected = intval($_SESSION['captcha_answer'] ?? -1);
|
||||
unset($_SESSION['captcha_answer']);
|
||||
|
||||
// Validate
|
||||
$valid = true;
|
||||
$csrf_valid = isset($_POST['csrf_token'], $_SESSION['csrf_token'])
|
||||
&& hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']);
|
||||
|
||||
$fails = [];
|
||||
if (!$csrf_valid) {
|
||||
$fails[] = 'csrf-invalid';
|
||||
}
|
||||
if (empty($name) || strlen($name) > 200) {
|
||||
$valid = false;
|
||||
$fails[] = 'name';
|
||||
}
|
||||
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$valid = false;
|
||||
$fails[] = 'email';
|
||||
}
|
||||
if (empty($message) || strlen($message) > 5000) {
|
||||
$valid = false;
|
||||
$fails[] = 'message';
|
||||
}
|
||||
if ($captcha !== $expected || $expected === -1) {
|
||||
$valid = false;
|
||||
if ($expected === -1) {
|
||||
$fails[] = 'captcha-no-session';
|
||||
} elseif ($captcha !== $expected) {
|
||||
$fails[] = 'captcha-mismatch';
|
||||
}
|
||||
|
||||
if (!$valid) {
|
||||
header('Location: index.php?error=1#contact');
|
||||
if ($fails) {
|
||||
error_log('fraxle contact form rejected: ' . implode(',', $fails)
|
||||
. ' | got=' . $captcha . ' expected=' . $expected
|
||||
. ' | sid=' . session_id()
|
||||
. ' | host=' . ($_SERVER['HTTP_HOST'] ?? '?')
|
||||
. ' | ref=' . ($_SERVER['HTTP_REFERER'] ?? '?'));
|
||||
header('Location: /?error=details#contact');
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -55,8 +89,11 @@ $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
|
||||
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
||||
|
||||
if (mail($to, $subject, $body, $headers)) {
|
||||
header('Location: index.php?sent=1#contact');
|
||||
$_SESSION['last_submission'] = time();
|
||||
header('Location: /?sent=1#contact');
|
||||
} else {
|
||||
header('Location: index.php?error=1#contact');
|
||||
error_log('fraxle contact form: mail() failed for ' . $safeEmail
|
||||
. ' — ' . (error_get_last()['message'] ?? 'no PHP error reported'));
|
||||
header('Location: /?error=mail#contact');
|
||||
}
|
||||
exit;
|
||||
|
||||
Reference in New Issue
Block a user