Add contact form with spam protection

Add social media links to contact page

Move history content to dedicated page

Add SMTP configuration file

Update frontpage link styling
This commit is contained in:
Ruben 2025-11-04 22:19:58 +01:00
parent b3cefcdc57
commit c013c2cde3
9 changed files with 403 additions and 17 deletions

View file

@ -0,0 +1,263 @@
<?php
// Contact form processing with spam prevention
$formSubmitted = false;
$formSuccess = false;
$formErrors = [];
$formData = ['name' => '', 'email' => '', 'message' => ''];
// Process form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit'])) {
$formSubmitted = true;
// 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)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$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, '&#10007;') !== 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 mange og driver alt 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 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 style="position: absolute; left: -5000px;" aria-hidden="true">
<label for="website">Website</label>
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
</div>
<!-- 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>