0, 'time' => time()]; } $data = $_SESSION[$key]; // Reset counter if more than 1 hour has passed if (time() - $data['time'] > 3600) { $_SESSION[$key] = ['count' => 0, 'time' => time()]; $data = $_SESSION[$key]; } // Allow max 5 submissions per hour if ($data['count'] >= 5) { return false; } return true; } // Input validation and sanitization function validateInput($data, $type = 'text') { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8'); // Prevent header injection $data = str_replace(array("\r", "\n", "%0a", "%0d"), '', $data); switch ($type) { case 'email': $email = filter_var($data, FILTER_VALIDATE_EMAIL); // Additional email validation to prevent header injection if ($email && !preg_match('/[\r\n]/', $email)) { return $email; } return false; case 'phone': return preg_match('/^[\+]?[0-9\s\-\(\)]+$/', $data) ? $data : false; case 'text': return strlen($data) > 0 ? $data : false; case 'message': return strlen($data) >= 10 ? $data : false; default: return $data; } } // Response function function sendResponse($success, $message, $data = null) { $response = [ 'success' => $success, 'message' => $message ]; if ($data !== null) { $response['data'] = $data; } echo json_encode($response); exit; } // Handle POST requests only if ($_SERVER['REQUEST_METHOD'] !== 'POST') { sendResponse(false, 'Invalid request method'); } // Check referer to prevent external form submissions $allowed_referers = ['ukaiautomation.co.uk', 'www.ukaiautomation.co.uk', 'localhost']; $referer_valid = false; if (isset($_SERVER['HTTP_REFERER'])) { $referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); foreach ($allowed_referers as $allowed) { if ($referer_host === $allowed || strpos($referer_host, $allowed) !== false) { $referer_valid = true; break; } } } // Allow direct access for testing but log it if (!$referer_valid && !isset($_SERVER['HTTP_REFERER'])) { error_log("Contact form accessed without referer from IP: " . $_SERVER['REMOTE_ADDR']); } // Check for blocked IPs function checkBlockedIP() { $ip = $_SERVER['REMOTE_ADDR']; $blockFile = 'logs/blocked-ips.txt'; if (file_exists($blockFile)) { $blockedIPs = file($blockFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($blockedIPs as $blockedEntry) { $parts = explode('|', $blockedEntry); if (isset($parts[0]) && $parts[0] === $ip) { $blockTime = isset($parts[1]) ? (int)$parts[1] : 0; // Block for 24 hours if (time() - $blockTime < 86400) { return false; } } } } return true; } // Check for blocked IPs first if (!checkBlockedIP()) { sendResponse(false, 'Access temporarily restricted'); } // Check rate limiting if (!checkRateLimit()) { sendResponse(false, 'Too many requests. Please try again later.'); } // Verify reCAPTCHA v3 if (isset($_POST['recaptcha_response'])) { $recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify'; $recaptcha_secret = RECAPTCHA_SECRET_KEY; $recaptcha_response = $_POST['recaptcha_response']; $recaptcha_data = array( 'secret' => $recaptcha_secret, 'response' => $recaptcha_response, 'remoteip' => $_SERVER['REMOTE_ADDR'] ); $recaptcha_options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($recaptcha_data) ) ); $recaptcha_context = stream_context_create($recaptcha_options); $recaptcha_result = @file_get_contents($recaptcha_url, false, $recaptcha_context); if ($recaptcha_result === false) { // Log reCAPTCHA API failure but don't block submission error_log("reCAPTCHA API call failed for IP: " . $_SERVER['REMOTE_ADDR']); } else { $recaptcha_json = json_decode($recaptcha_result, true); // Temporarily disable reCAPTCHA check for test keys if (!$recaptcha_json['success']) { // Log suspicious activity but don't block for test keys $logEntry = date('Y-m-d H:i:s') . " - RECAPTCHA WARNING: " . json_encode($recaptcha_json) . " from " . $_SERVER['REMOTE_ADDR'] . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); } // Only block if score is extremely low and not using test keys if (isset($recaptcha_json['score']) && $recaptcha_json['score'] < 0.1 && RECAPTCHA_SITE_KEY !== '6LcdAtUUAAAAAPX-5YJaWKJmeq7QIMjeLTS7qy6s') { $logEntry = date('Y-m-d H:i:s') . " - RECAPTCHA BLOCKED: Score " . $recaptcha_json['score'] . " from " . $_SERVER['REMOTE_ADDR'] . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); sendResponse(false, 'Security verification failed. Please try again.'); } } } else { // No reCAPTCHA response - likely a bot sendResponse(false, 'Security verification required.'); } // Validate and sanitize inputs $name = validateInput($_POST['name'] ?? '', 'text'); $email = validateInput($_POST['email'] ?? '', 'email'); $company = validateInput($_POST['company'] ?? '', 'text'); $service = validateInput($_POST['service'] ?? '', 'text'); $message = validateInput($_POST['message'] ?? '', 'message'); // Validation $errors = []; if (!$name || strlen($name) < 2) { $errors[] = 'Please enter a valid name (minimum 2 characters)'; } if (!$email) { $errors[] = 'Please enter a valid email address'; } if (!$message) { $errors[] = 'Please provide project details (minimum 10 characters)'; } if (!empty($errors)) { sendResponse(false, implode('. ', $errors)); } // Spam protection - simple honeypot and content filtering if (isset($_POST['website']) && !empty($_POST['website'])) { // Honeypot field filled - likely spam sendResponse(false, 'Spam detected'); } // Enhanced spam protection - expanded keyword list $spamKeywords = [ 'viagra', 'cialis', 'casino', 'lottery', 'bitcoin', 'forex', 'loan', 'debt', 'pharmacy', 'click here', 'act now', 'limited time', 'risk free', 'guarantee', 'no obligation', 'free money', 'make money fast', 'work from home', 'get rich', 'investment opportunity', 'credit repair', 'refinance', 'consolidate debt', 'weight loss', 'miracle cure', 'lose weight', 'adult content', 'porn', 'sex', 'dating', 'singles', 'webcam', 'escort', 'massage', 'crypto', 'nft', 'blockchain', 'earn money', 'passive income', 'financial freedom', 'mlm', 'network marketing', 'online casino', 'gambling', 'betting', 'binary options' ]; // Check for disposable email domains $disposableEmailDomains = [ 'mailinator.com', 'guerrillamail.com', '10minutemail.com', 'temp-mail.org', 'throwawaymail.com', 'yopmail.com', 'mailnesia.com', 'trashmail.com', 'maildrop.cc', 'mailcatch.com', 'tempmail.com', 'email-fake.com', 'fakeinbox.com', 'sharklasers.com', 'guerrillamailblock.com' ]; $emailDomain = substr(strrchr($email, "@"), 1); if (in_array(strtolower($emailDomain), $disposableEmailDomains)) { sendResponse(false, 'Please use a valid business email address.'); } $messageContent = strtolower($message . ' ' . $name . ' ' . $company); foreach ($spamKeywords as $keyword) { if (strpos($messageContent, $keyword) !== false) { sendResponse(false, 'Invalid content detected'); } } // Bot detection - check for suspicious patterns $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $suspiciousAgents = ['curl', 'wget', 'python', 'bot', 'crawler', 'spider', 'scraper']; foreach ($suspiciousAgents as $agent) { if (stripos($userAgent, $agent) !== false) { sendResponse(false, 'Automated submissions not allowed'); } } // Check submission speed (too fast = likely bot) - More lenient timing if (isset($_SESSION['form_start_time'])) { $submissionTime = time() - $_SESSION['form_start_time']; if ($submissionTime < 2) { // Only block if under 2 seconds (very aggressive bots) sendResponse(false, 'Form submitted too quickly'); } } // Check for XMLHttpRequest header (JavaScript submission) if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest') { // Log direct POST attempt $logEntry = date('Y-m-d H:i:s') . " - DIRECT POST attempt from " . $_SERVER['REMOTE_ADDR'] . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); sendResponse(false, 'Invalid submission method'); } // Verify interaction token (human behavior verification) if (isset($_POST['interaction_token']) && !empty($_POST['interaction_token'])) { $tokenData = @json_decode(base64_decode($_POST['interaction_token']), true); if ($tokenData && isset($tokenData['score'])) { if ($tokenData["score"] < 3) { // Log low interaction score $logEntry = date('Y-m-d H:i:s') . " - LOW INTERACTION SCORE: " . $tokenData['score'] . " from " . $_SERVER['REMOTE_ADDR'] . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); sendResponse(false, 'Please complete the form normally'); } } } // Verify form timestamp (prevent replay attacks) - temporarily disabled for debugging // Timestamp validation is now very lenient - only blocks obviously invalid timestamps if (isset($_POST['form_timestamp']) && !empty($_POST['form_timestamp'])) { $formTimestamp = intval($_POST['form_timestamp']); // Only block if timestamp is 0 or clearly invalid (before year 2020) if ($formTimestamp > 0 && $formTimestamp < 1577836800000) { // Before Jan 1, 2020 $logEntry = date('Y-m-d H:i:s') . " - INVALID TIMESTAMP: " . $formTimestamp . " from " . $_SERVER['REMOTE_ADDR'] . "\n"; @file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); // Don't block, just log } } // Log all form submissions for debugging $debugLog = date('Y-m-d H:i:s') . " - DEBUG: timestamp=" . ($_POST['form_timestamp'] ?? 'NOT SET') . ", IP=" . $_SERVER['REMOTE_ADDR'] . "\n"; @file_put_contents('logs/contact-debug.log', $debugLog, FILE_APPEND | LOCK_EX); // Update rate limit counter $ip = $_SERVER['REMOTE_ADDR']; $key = 'contact_' . md5($ip); $_SESSION[$key]['count']++; // Prepare email content $to = 'info@ukaiautomation.co.uk'; $subject = 'New Contact Form Submission - UK AI Automation'; // Create HTML email $emailHTML = ' New Contact Form Submission

New Contact Form Submission

UK AI Automation

Name:
' . htmlspecialchars($name) . '
Email:
' . htmlspecialchars($email) . '
Company:
' . htmlspecialchars($company ?: 'Not provided') . '
Service Required:
' . htmlspecialchars($service ?: 'Not specified') . '
Project Details:
' . nl2br(htmlspecialchars($message)) . '
Submission Details:
IP Address: ' . htmlspecialchars($_SERVER['REMOTE_ADDR']) . '
User Agent: ' . htmlspecialchars($_SERVER['HTTP_USER_AGENT']) . '
Timestamp: ' . date('Y-m-d H:i:s') . ' UTC
Referrer: ' . htmlspecialchars($_SERVER['HTTP_REFERER'] ?? 'Direct') . '
'; // Email headers $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers .= "From: \"UK AI Automation Contact Form\" \r\n"; $headers .= "Reply-To: " . $email . "\r\n"; $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n"; $headers .= "X-Priority: 3\r\n"; // Create logs directory if it doesn't exist if (!file_exists('logs')) { mkdir('logs', 0755, true); } // Send email try { // Clear any previous errors error_clear_last(); // First, always log the submission details $submissionData = [ 'timestamp' => date('Y-m-d H:i:s'), 'name' => $name, 'email' => $email, 'company' => $company, 'service' => $service, 'message' => $message, 'ip' => $_SERVER['REMOTE_ADDR'], 'user_agent' => $_SERVER['HTTP_USER_AGENT'], 'referrer' => $_SERVER['HTTP_REFERER'] ?? 'Direct' ]; // Save submission to a JSON file as backup $submissionFile = 'logs/submissions-' . date('Y-m') . '.json'; $submissions = []; if (file_exists($submissionFile)) { $submissions = json_decode(file_get_contents($submissionFile), true) ?? []; } $submissions[] = $submissionData; file_put_contents($submissionFile, json_encode($submissions, JSON_PRETTY_PRINT), LOCK_EX); // Attempt to send email $emailSent = @mail($to, $subject, $emailHTML, $headers); if ($emailSent) { // Log successful submission $logEntry = date('Y-m-d H:i:s') . " - Contact form submission from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ")\n"; file_put_contents('logs/contact-submissions.log', $logEntry, FILE_APPEND | LOCK_EX); sendResponse(true, 'Thank you for your message! We will get back to you within 24 hours.'); } else { // Get detailed error information $lastError = error_get_last(); $errorMsg = $lastError ? $lastError['message'] : 'Mail function returned false'; // Log failed email with detailed error $logEntry = date('Y-m-d H:i:s') . " - MAIL FAILED but submission saved - from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ") - Error: " . $errorMsg . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); // Check if mail function exists if (!function_exists('mail')) { error_log("PHP mail() function not available"); } // Still return success since we saved the submission sendResponse(true, 'Thank you for your message! Your submission has been received and we will get back to you within 24 hours.'); } } catch (Exception $e) { // Log exception with full details $logEntry = date('Y-m-d H:i:s') . " - EXCEPTION: " . $e->getMessage() . " from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ") - File: " . $e->getFile() . " Line: " . $e->getLine() . "\n"; file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX); // Still save the submission try { $submissionFile = 'logs/submissions-emergency-' . date('Y-m-d') . '.txt'; $emergencyLog = date('Y-m-d H:i:s') . "\n" . "Name: " . $name . "\n" . "Email: " . $email . "\n" . "Company: " . $company . "\n" . "Service: " . $service . "\n" . "Message: " . $message . "\n" . "IP: " . $_SERVER['REMOTE_ADDR'] . "\n" . "---\n\n"; file_put_contents($submissionFile, $emergencyLog, FILE_APPEND | LOCK_EX); sendResponse(true, 'Thank you for your message! Your submission has been received and we will get back to you within 24 hours.'); } catch (Exception $e2) { sendResponse(false, 'There was an error processing your request. Please contact us directly at info@ukaiautomation.co.uk'); } } ?>