274 lines
11 KiB
PHP
274 lines
11 KiB
PHP
<?php
|
|
// Contact form processing with spam prevention
|
|
$formSubmitted = false;
|
|
$formSuccess = false;
|
|
$formErrors = [];
|
|
$formData = ['name' => '', 'email' => '', 'message' => ''];
|
|
|
|
// Start session for CSRF token and rate limiting
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
// Generate CSRF token if not exists
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
}
|
|
|
|
// Process form submission
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit'])) {
|
|
$formSubmitted = true;
|
|
|
|
// Security: CSRF Token Validation
|
|
if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
|
$formErrors[] = 'Invalid security code. Please try again.';
|
|
}
|
|
|
|
// Spam Prevention 1: Honeypot field (should be empty)
|
|
if (!empty($_POST['website'])) {
|
|
$formErrors[] = 'Spam detected.';
|
|
}
|
|
|
|
// Spam Prevention 2: Time-based check (form must be visible for at least 3 seconds)
|
|
$formStartTime = isset($_POST['form_start_time']) ? (int)$_POST['form_start_time'] : 0;
|
|
$timeDiff = time() - $formStartTime;
|
|
if ($timeDiff < 3) {
|
|
$formErrors[] = 'Form submitted too quickly.';
|
|
}
|
|
|
|
// Spam Prevention 3: Referrer check (only if referrer is present and clearly from different domain)
|
|
if (!empty($_SERVER['HTTP_REFERER'])) {
|
|
$referrer = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
|
|
$currentHost = $_SERVER['HTTP_HOST'];
|
|
// Only block if referrer exists and doesn't match (allows empty referrer for privacy browsers)
|
|
if ($referrer && $referrer !== $currentHost && $referrer !== 'localhost') {
|
|
$formErrors[] = 'Invalid form submission.';
|
|
}
|
|
}
|
|
|
|
// Spam Prevention 4: Rate limiting (session-based)
|
|
$lastSubmitTime = isset($_SESSION['last_contact_submit']) ? $_SESSION['last_contact_submit'] : 0;
|
|
if (time() - $lastSubmitTime < 60) {
|
|
$formErrors[] = 'Please wait a bit before submitting again.';
|
|
}
|
|
|
|
// Get and sanitize form data
|
|
$formData['name'] = trim($_POST['name'] ?? '');
|
|
$formData['email'] = trim($_POST['email'] ?? '');
|
|
// Normalize line endings in message (convert \r\n to \n)
|
|
$formData['message'] = trim(str_replace("\r\n", "\n", $_POST['message'] ?? ''));
|
|
|
|
// Validation
|
|
if (empty($formData['name'])) {
|
|
$formErrors[] = 'Please provide your name.';
|
|
} elseif (strlen($formData['name']) > 100) {
|
|
$formErrors[] = 'The name is too long.';
|
|
}
|
|
|
|
if (empty($formData['email'])) {
|
|
$formErrors[] = 'Please provide your email address.';
|
|
} elseif (!filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) {
|
|
$formErrors[] = 'Invalid email address.';
|
|
} elseif (strlen($formData['email']) > 100) {
|
|
$formErrors[] = 'The email address is too long.';
|
|
}
|
|
|
|
if (empty($formData['message'])) {
|
|
$formErrors[] = 'Please write a message.';
|
|
} elseif (strlen($formData['message']) < 10) {
|
|
$formErrors[] = 'The message is too short (minimum 10 characters).';
|
|
} elseif (strlen($formData['message']) > 5000) {
|
|
$formErrors[] = 'The message is too long (maximum 5000 characters).';
|
|
}
|
|
|
|
// Spam Prevention 5: Check for suspicious patterns
|
|
$spamPatterns = [
|
|
'/\[url=/i',
|
|
'/\[link=/i',
|
|
'/<a href=/i',
|
|
'/viagra|cialis|casino|poker|lottery/i',
|
|
'/http.*http.*http/i', // Multiple URLs
|
|
];
|
|
|
|
$fullText = $formData['name'] . ' ' . $formData['email'] . ' ' . $formData['message'];
|
|
foreach ($spamPatterns as $pattern) {
|
|
if (preg_match($pattern, $fullText)) {
|
|
$formErrors[] = 'The message contains non-allowed content.';
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no errors, send email
|
|
if (empty($formErrors)) {
|
|
// Load SMTP configuration
|
|
$smtpConfig = require __DIR__ . '/../../custom/smtp-config.php';
|
|
|
|
// Prepare email body
|
|
$emailBody = "New inquiry from the contact form on stopplidelsen.no\n\n";
|
|
$emailBody .= "Name: " . $formData['name'] . "\n";
|
|
$emailBody .= "Email: " . $formData['email'] . "\n";
|
|
$emailBody .= "IP address: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
$emailBody .= "Timestamp: " . date('Y-m-d H:i:s') . "\n\n";
|
|
$emailBody .= "Message:\n" . $formData['message'] . "\n";
|
|
|
|
$mailSent = false;
|
|
|
|
// Try PHPMailer.Lite if SMTP is configured
|
|
if ($smtpConfig['enabled']) {
|
|
// Pre-flight check: Test SMTP connection before attempting to send
|
|
$smtpConnectable = false;
|
|
$fp = @fsockopen($smtpConfig['host'], $smtpConfig['port'], $errno, $errstr, 10);
|
|
if ($fp) {
|
|
// Successfully connected
|
|
$smtpConnectable = true;
|
|
fclose($fp);
|
|
} else {
|
|
error_log("SMTP Pre-flight check failed: Cannot connect to {$smtpConfig['host']}:{$smtpConfig['port']} - Error: $errno - $errstr");
|
|
$formErrors[] = 'An error occurred while sending the message. Please try again later.';
|
|
}
|
|
|
|
if ($smtpConnectable) {
|
|
try {
|
|
require_once __DIR__ . '/../../custom/vendor/PHPMailer.Lite.php';
|
|
|
|
$mail = new \codeworxtech\PHPMailerLite\PHPMailerLite();
|
|
|
|
// Enable debug output in development
|
|
// $mail->debug = 1; // Uncomment to see SMTP debug output
|
|
|
|
$mail->SetSMTPhost($smtpConfig['host']);
|
|
$mail->SetSMTPport($smtpConfig['port']);
|
|
$mail->SetSMTPuser($smtpConfig['username']);
|
|
$mail->SetSMTPpass($smtpConfig['password']);
|
|
|
|
$mail->SetSender([$smtpConfig['from_email'] => $smtpConfig['from_name']]);
|
|
$mail->AddRecipient([$smtpConfig['to_email'] => $smtpConfig['to_name']]);
|
|
$mail->AddReplyTo([$formData['email'] => $formData['name']]);
|
|
$mail->SetSubject('New inquiry from contact form');
|
|
$mail->SetBodyText($emailBody);
|
|
|
|
// Capture any output from PHPMailer.Lite (it might exit() on error)
|
|
ob_start();
|
|
$mailSent = @$mail->Send('smtp');
|
|
$smtpOutput = ob_get_clean();
|
|
|
|
// Check if there was an error in the output
|
|
if (!$mailSent || stripos($smtpOutput, 'error') !== false || stripos($smtpOutput, '✗') !== false) {
|
|
$mailSent = false;
|
|
error_log("SMTP Send failed. Output: " . strip_tags($smtpOutput));
|
|
$formErrors[] = 'An error occurred while sending the message. Please try again later.';
|
|
}
|
|
} catch (\Exception $e) {
|
|
$mailSent = false;
|
|
error_log("PHPMailer Exception: " . $e->getMessage());
|
|
$formErrors[] = 'An error occurred while sending the message. Please try again later.';
|
|
}
|
|
}
|
|
} else {
|
|
// Fallback to native mail() function
|
|
$headers = "From: kontaktskjema@stopplidelsen.no\r\n";
|
|
$headers .= "Reply-To: " . $formData['email'] . "\r\n";
|
|
$headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
|
|
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
|
|
|
$mailSent = mail('ruben@stopplidelsen.no', 'New inquiry from contact form', $emailBody, $headers);
|
|
}
|
|
|
|
if ($mailSent) {
|
|
$formSuccess = true;
|
|
$_SESSION['last_contact_submit'] = time();
|
|
|
|
// Clear form data on success
|
|
$formData = ['name' => '', 'email' => '', 'message' => ''];
|
|
} else {
|
|
if (empty($formErrors)) {
|
|
$formErrors[] = 'An error occurred while sending the message. Please try again later.';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate form start time token
|
|
$currentTime = time();
|
|
?>
|
|
|
|
<h2>Contact Form</h2>
|
|
|
|
<p>Do you have questions, suggestions or want to participate in our work? Fill out the form below! But remember that it may take time before you get a response, we are not many and run everything on a voluntary basis.</p>
|
|
|
|
<section class="contact-form">
|
|
<?php if ($formSuccess): ?>
|
|
<div class="form-success">
|
|
<p><strong>Thank you for your inquiry!</strong></p>
|
|
<p>We have received your message and will respond as soon as possible.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($formErrors)): ?>
|
|
<div class="form-errors">
|
|
<p><strong>Please correct the following:</strong></p>
|
|
<ul>
|
|
<?php foreach ($formErrors as $error): ?>
|
|
<li><?= htmlspecialchars($error) ?></li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!$formSuccess): ?>
|
|
<form method="post" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>" class="contact-form-inner">
|
|
<!-- Honeypot field (hidden from users, bots will fill it) -->
|
|
<div class="hp-field" aria-hidden="true">
|
|
<label for="website">Website</label>
|
|
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
|
|
</div>
|
|
|
|
<!-- CSRF Token -->
|
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
|
|
|
<!-- Time-based token -->
|
|
<input type="hidden" name="form_start_time" value="<?= $currentTime ?>">
|
|
|
|
<div class="form-group">
|
|
<label for="contact_name">Name <span class="required">*</span></label>
|
|
<input
|
|
type="text"
|
|
id="contact_name"
|
|
name="name"
|
|
value="<?= htmlspecialchars($formData['name']) ?>"
|
|
required
|
|
maxlength="100"
|
|
>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="contact_email">Email address <span class="required">*</span></label>
|
|
<input
|
|
type="email"
|
|
id="contact_email"
|
|
name="email"
|
|
value="<?= htmlspecialchars($formData['email']) ?>"
|
|
required
|
|
maxlength="100"
|
|
>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="contact_message">Message <span class="required">*</span></label>
|
|
<textarea
|
|
id="contact_message"
|
|
name="message"
|
|
rows="8"
|
|
required
|
|
minlength="10"
|
|
maxlength="5000"
|
|
><?= htmlspecialchars($formData['message']) ?></textarea>
|
|
<small>Minimum 10 characters, maximum 5000 characters.</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<button type="submit" name="contact_form_submit" class="button">Send message</button>
|
|
</div>
|
|
</form>
|
|
<?php endif; ?>
|
|
</section>
|