Improve contact form styling with dedicated CSS file Move contact form styles from base.css to separate file Add security measures to custom directory with .htaccess Update honeypot field styling and implementation
277 lines
11 KiB
PHP
277 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[] = 'Ugyldig sikkerhetskode. Vennligst prøv igjen.';
|
|
}
|
|
|
|
// 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[] = 'Vennligst vent litt før du sender inn igjen.';
|
|
}
|
|
|
|
// 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[] = 'Vennligst oppgi navn.';
|
|
} elseif (strlen($formData['name']) > 100) {
|
|
$formErrors[] = 'Navnet er for langt.';
|
|
}
|
|
|
|
if (empty($formData['email'])) {
|
|
$formErrors[] = 'Vennligst oppgi e-postadresse.';
|
|
} elseif (!filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) {
|
|
$formErrors[] = 'Ugyldig e-postadresse.';
|
|
} elseif (strlen($formData['email']) > 100) {
|
|
$formErrors[] = 'E-postadressen er for lang.';
|
|
}
|
|
|
|
if (empty($formData['message'])) {
|
|
$formErrors[] = 'Vennligst skriv en melding.';
|
|
} elseif (strlen($formData['message']) < 10) {
|
|
$formErrors[] = 'Meldingen er for kort (minimum 10 tegn).';
|
|
} elseif (strlen($formData['message']) > 5000) {
|
|
$formErrors[] = 'Meldingen er for lang (maksimum 5000 tegn).';
|
|
}
|
|
|
|
// 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[] = 'Meldingen inneholder ikke tillatt innhold.';
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no errors, send email
|
|
if (empty($formErrors)) {
|
|
// Load SMTP configuration
|
|
$smtpConfig = require __DIR__ . '/../../custom/smtp-config.php';
|
|
|
|
// Prepare email body
|
|
$emailBody = "Ny henvendelse fra kontaktskjemaet på stopplidelsen.no\n\n";
|
|
$emailBody .= "Navn: " . $formData['name'] . "\n";
|
|
$emailBody .= "E-post: " . $formData['email'] . "\n";
|
|
$emailBody .= "IP-adresse: " . $_SERVER['REMOTE_ADDR'] . "\n";
|
|
$emailBody .= "Tidspunkt: " . date('Y-m-d H:i:s') . "\n\n";
|
|
$emailBody .= "Melding:\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[] = 'Det oppstod en feil ved sending av meldingen. Vennligst prøv igjen senere.';
|
|
}
|
|
|
|
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('Ny henvendelse fra kontaktskjema');
|
|
$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[] = 'Det oppstod en feil ved sending av meldingen. Vennligst prøv igjen senere.';
|
|
}
|
|
} catch (\Exception $e) {
|
|
$mailSent = false;
|
|
error_log("PHPMailer Exception: " . $e->getMessage());
|
|
$formErrors[] = 'Det oppstod en feil ved sending av meldingen. Vennligst prøv igjen senere.';
|
|
}
|
|
}
|
|
} 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', 'Ny henvendelse fra kontaktskjema', $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[] = 'Det oppstod en feil ved sending av meldingen. Vennligst prøv igjen senere.';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate form start time token
|
|
$currentTime = time();
|
|
?>
|
|
|
|
<article class="contain">
|
|
<h2>Kontaktskjema</h2>
|
|
|
|
<p>Har du spørsmål, innspill eller ønsker å delta i arbeidet vårt? Fyll ut skjemaet nedenfor! Men husk at det kan ta tid før du får svar, vi er ikke så mange og driver alt på frivillig basis.</p>
|
|
|
|
<section class="contact-form">
|
|
<?php if ($formSuccess): ?>
|
|
<div class="form-success">
|
|
<p><strong>Takk for din henvendelse!</strong></p>
|
|
<p>Vi har mottatt meldingen din og vil svare så snart som mulig.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($formErrors)): ?>
|
|
<div class="form-errors">
|
|
<p><strong>Vennligst rett opp følgende:</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">Navn <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">E-postadresse <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">Melding <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 tegn, maksimum 5000 tegn.</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<button type="submit" name="contact_form_submit" class="button">Send melding</button>
|
|
</div>
|
|
</form>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
</article>
|