File "contact-handler.php"
Full path: /home/zvmcccat/public_html/adn/contact-handler.php
File
size: 3.92 B
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor &nnbsp; Back
<?php
require_once __DIR__ . '/includes/config.php';
session_start();
function alpha_redirect(string $status): void
{
header('Location: contact.php?status=' . urlencode($status));
exit;
}
/**
* Strips CR/LF and other control characters from a value that will end up
* in an email header or subject line. Without this, a field like "name"
* could contain "\r\nBcc: spamlist@evil.com" and turn the form into an open
* mail relay (classic PHP mail() header-injection attack on contact forms).
* Also caps length as a basic abuse guard.
*/
function alpha_header_safe(string $value, int $maxLen = 200): string
{
$value = preg_replace('/[\r\n\x00-\x1F\x7F]+/', ' ', $value) ?? '';
$value = trim($value);
return mb_substr($value, 0, $maxLen);
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: contact.php');
exit;
}
// CSRF check
$submittedToken = $_POST['csrf_token'] ?? '';
if (empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $submittedToken)) {
alpha_redirect('error');
}
// Honeypot — real users never see or fill this field. If it's filled,
// silently pretend success so bots don't learn to avoid it.
if (!empty($_POST['website'])) {
alpha_redirect('sent');
}
// Timing check — a form submitted less than 2 seconds after it rendered
// almost certainly wasn't filled out by a human. Silently "succeed" like
// the honeypot, for the same reason (don't tip off the bot).
$renderedAt = $_SESSION['contact_form_rendered_at'] ?? 0;
if ($renderedAt === 0 || (time() - $renderedAt) < 2) {
alpha_redirect('sent');
}
// Basic per-session rate limit — 5 submissions per 10 minutes. Cheap abuse
// guard that needs no database; resets when the session/cookie does.
$now = time();
$_SESSION['contact_submissions'] = array_filter(
$_SESSION['contact_submissions'] ?? [],
function ($t) use ($now) {
return $now - $t < 600;
}
);
if (count($_SESSION['contact_submissions']) >= 5) {
alpha_redirect('error');
}
$name = alpha_header_safe(strip_tags($_POST['name'] ?? ''));
$email = alpha_header_safe($_POST['email'] ?? '', 254);
$company = alpha_header_safe(strip_tags($_POST['company'] ?? ''));
$phone = alpha_header_safe(strip_tags($_POST['phone'] ?? ''), 50);
$interest = alpha_header_safe(strip_tags($_POST['interest'] ?? 'General Inquiry'));
// Message goes in the body, not a header, so it isn't run through
// alpha_header_safe() — but it is length-capped and tag-stripped.
$message = mb_substr(trim(strip_tags($_POST['message'] ?? '')), 0, 5000);
if (
$name === ''
|| $message === ''
|| !filter_var($email, FILTER_VALIDATE_EMAIL)
|| strpbrk($email, "\r\n") !== false
) {
alpha_redirect('error');
}
$_SESSION['contact_submissions'][] = $now;
$host = parse_url(SITE_URL, PHP_URL_HOST) ?: 'alphadnet.net';
$fromAddress = 'no-reply@' . $host;
$subject = alpha_header_safe('Website enquiry — ' . $interest . ' — ' . $name, 250);
$bodyLines = [
'New enquiry from the alphadnet.net contact form.',
'',
'Name: ' . $name,
'Company: ' . ($company !== '' ? $company : '—'),
'Email: ' . $email,
'Phone: ' . ($phone !== '' ? $phone : '—'),
'Interested in: ' . $interest,
'',
'Message:',
$message,
];
$body = implode("\r\n", $bodyLines);
$headers = [
'From: ' . SITE_NAME . ' Website <' . $fromAddress . '>',
'Reply-To: ' . $email,
'X-Mailer: PHP/' . phpversion(),
];
$sent = @mail(CONTACT_EMAIL_SALES, $subject, $body, implode("\r\n", $headers));
if (!$sent) {
// No MTA configured (e.g. local Docker testing) — log instead so the
// submission isn't silently lost. This file lives under includes/,
// which .htaccess already blocks from direct web access.
$logPath = __DIR__ . '/includes/contact-submissions.log';
$logEntry = '[' . date('c') . "] mail() failed — would have sent:\n" . $body . "\n---\n";
@file_put_contents($logPath, $logEntry, FILE_APPEND | LOCK_EX);
}
alpha_redirect('sent');