Fix consultation form CSRF validation and improve site optimization
- Fix CSRF token validation for quote form by adding proper session handling and credentials to AJAX requests - Replace alert boxes with styled error/success messages and HTML response pages for better UX - Add visual indicators (*) to required form fields for better accessibility - Standardize navigation links to use absolute paths for consistency - Update JavaScript references to use minified version (main.min.js) for better performance - Archive large error log file and clean up sitemap by removing broken image references - Add comprehensive documentation to reCAPTCHA configuration about test vs production keys - Update sitemap lastmod dates to current timestamp 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
<?php
|
||||
// Quote Form Handler with Enhanced Security
|
||||
// Ensure session cookie is available for AJAX requests
|
||||
ini_set('session.cookie_samesite', 'Lax');
|
||||
ini_set('session.cookie_httponly', '1');
|
||||
ini_set('session.cookie_secure', '0'); // Set to '1' if using HTTPS
|
||||
session_start();
|
||||
|
||||
// Security headers
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('X-Frame-Options: DENY');
|
||||
header('X-XSS-Protection: 1; mode=block');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// CSRF Protection
|
||||
function generateCSRFToken() {
|
||||
@@ -63,18 +66,267 @@ function validateInput($data, $type = 'text') {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if request is AJAX
|
||||
function isAjaxRequest() {
|
||||
return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
||||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
|
||||
}
|
||||
|
||||
// Response function
|
||||
function sendResponse($success, $message, $data = null) {
|
||||
$response = [
|
||||
'success' => $success,
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
if ($data !== null) {
|
||||
$response['data'] = $data;
|
||||
// If AJAX request, send JSON
|
||||
if (isAjaxRequest()) {
|
||||
$response = [
|
||||
'success' => $success,
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
if ($data !== null) {
|
||||
$response['data'] = $data;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
// Otherwise, display HTML response page
|
||||
displayHTMLResponse($success, $message);
|
||||
}
|
||||
|
||||
// Display HTML response page
|
||||
function displayHTMLResponse($success, $message) {
|
||||
$pageTitle = $success ? 'Quote Request Sent Successfully' : 'Quote Submission Error';
|
||||
$messageClass = $success ? 'success' : 'error';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo htmlspecialchars($pageTitle); ?> - UK Data Services</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.response-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
animation: slideUp 0.4s ease;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
height: 50px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto 20px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.icon.success {
|
||||
background: rgba(23, 158, 131, 0.1);
|
||||
color: #179e83;
|
||||
}
|
||||
|
||||
.icon.error {
|
||||
background: rgba(231, 76, 60, 0.1);
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
margin-bottom: 15px;
|
||||
color: #1a1a1a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
color: #721c24;
|
||||
background: #fee;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #fcc;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
color: #155724;
|
||||
background: #efe;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #cfc;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 14px 32px;
|
||||
border-radius: 50px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #179e83;
|
||||
color: white;
|
||||
box-shadow: 0 4px 14px rgba(23, 158, 131, 0.25);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(23, 158, 131, 0.35);
|
||||
background: #15896f;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: #764ba2;
|
||||
border: 2px solid #764ba2;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #764ba2;
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(118, 75, 162, 0.25);
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
margin-top: 30px;
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid #e1e5e9;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.contact-info a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.contact-info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="response-container">
|
||||
<div class="logo">
|
||||
<img src="/assets/images/ukds-main-logo.webp" alt="UK Data Services" onerror="this.onerror=null; this.src='/assets/images/ukds-main-logo.png';">
|
||||
</div>
|
||||
|
||||
<div class="icon <?php echo $messageClass; ?>">
|
||||
<?php echo $success ? '✓' : '✕'; ?>
|
||||
</div>
|
||||
|
||||
<h1><?php echo $success ? 'Thank You!' : 'Oops! Something Went Wrong'; ?></h1>
|
||||
|
||||
<div class="message <?php echo $messageClass; ?>">
|
||||
<?php
|
||||
if ($success) {
|
||||
echo htmlspecialchars($message);
|
||||
} else {
|
||||
// Parse multiple error messages if present
|
||||
if (strpos($message, '. ') !== false) {
|
||||
$errors = explode('. ', $message);
|
||||
echo '<ul style="text-align: left; padding-left: 20px; list-style: disc;">';
|
||||
foreach ($errors as $error) {
|
||||
if (trim($error)) {
|
||||
echo '<li>' . htmlspecialchars(trim($error)) . '</li>';
|
||||
}
|
||||
}
|
||||
echo '</ul>';
|
||||
} else {
|
||||
echo htmlspecialchars($message);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<?php if ($success): ?>
|
||||
<a href="/" class="btn btn-primary">Return to Home</a>
|
||||
<a href="/blog/" class="btn btn-secondary">Read Our Blog</a>
|
||||
<?php else: ?>
|
||||
<button onclick="history.back()" class="btn btn-primary">Go Back & Try Again</button>
|
||||
<a href="/" class="btn btn-secondary">Return to Home</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="contact-info">
|
||||
<?php if ($success): ?>
|
||||
<p>We'll be in touch within 24 hours with a detailed proposal.</p>
|
||||
<p>Have questions? Email us at <a href="mailto:info@ukdataservices.co.uk">info@ukdataservices.co.uk</a></p>
|
||||
<?php else: ?>
|
||||
<p>If you continue to experience issues, please contact us directly:</p>
|
||||
<p>Email: <a href="mailto:info@ukdataservices.co.uk">info@ukdataservices.co.uk</a></p>
|
||||
<p>Phone: +44 1692 689150</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -83,8 +335,12 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
sendResponse(false, 'Invalid request method');
|
||||
}
|
||||
|
||||
// Validate CSRF token (if present)
|
||||
if (isset($_POST['csrf_token']) && !validateCSRFToken($_POST['csrf_token'])) {
|
||||
// Validate CSRF token
|
||||
if (!isset($_POST['csrf_token'])) {
|
||||
sendResponse(false, 'Security validation failed. Please refresh the page and try again.');
|
||||
}
|
||||
|
||||
if (!validateCSRFToken($_POST['csrf_token'])) {
|
||||
sendResponse(false, 'Security validation failed. Please refresh the page and try again.');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user