233 lines
9.1 KiB
PHP
233 lines
9.1 KiB
PHP
<?php
|
|
// Spam Analysis Dashboard
|
|
session_start();
|
|
|
|
// Simple authentication check (you should implement proper admin authentication)
|
|
$authKey = $_GET['key'] ?? '';
|
|
if ($authKey !== 'your-secret-admin-key-2024') {
|
|
header('HTTP/1.0 403 Forbidden');
|
|
exit('Access Denied');
|
|
}
|
|
|
|
// Function to parse log files
|
|
function parseLogFile($filename) {
|
|
if (!file_exists($filename)) {
|
|
return [];
|
|
}
|
|
|
|
$entries = [];
|
|
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
|
|
|
foreach ($lines as $line) {
|
|
if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - (.+)$/', $line, $matches)) {
|
|
$entries[] = [
|
|
'timestamp' => $matches[1],
|
|
'message' => $matches[2]
|
|
];
|
|
}
|
|
}
|
|
|
|
return array_reverse($entries); // Most recent first
|
|
}
|
|
|
|
// Get log data
|
|
$contactSubmissions = parseLogFile('../logs/contact-submissions.log');
|
|
$contactErrors = parseLogFile('../logs/contact-errors.log');
|
|
$blockedIPs = file_exists('../logs/blocked-ips.txt') ? file('../logs/blocked-ips.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : [];
|
|
|
|
// Analyze spam patterns
|
|
$spamPatterns = [
|
|
'recaptcha_failures' => 0,
|
|
'direct_post_attempts' => 0,
|
|
'rate_limit_hits' => 0,
|
|
'low_interaction_scores' => 0,
|
|
'blocked_ips_count' => count($blockedIPs),
|
|
'hourly_distribution' => array_fill(0, 24, 0),
|
|
'top_ips' => []
|
|
];
|
|
|
|
$ipCounts = [];
|
|
|
|
foreach ($contactErrors as $error) {
|
|
if (strpos($error['message'], 'RECAPTCHA FAILED') !== false) {
|
|
$spamPatterns['recaptcha_failures']++;
|
|
}
|
|
if (strpos($error['message'], 'DIRECT POST') !== false) {
|
|
$spamPatterns['direct_post_attempts']++;
|
|
}
|
|
if (strpos($error['message'], 'Too many requests') !== false) {
|
|
$spamPatterns['rate_limit_hits']++;
|
|
}
|
|
if (strpos($error['message'], 'LOW INTERACTION SCORE') !== false) {
|
|
$spamPatterns['low_interaction_scores']++;
|
|
}
|
|
|
|
// Extract IP addresses
|
|
if (preg_match('/from ([0-9.]+)/', $error['message'], $matches)) {
|
|
$ip = $matches[1];
|
|
$ipCounts[$ip] = ($ipCounts[$ip] ?? 0) + 1;
|
|
}
|
|
|
|
// Track hourly distribution
|
|
$hour = (int)date('G', strtotime($error['timestamp']));
|
|
$spamPatterns['hourly_distribution'][$hour]++;
|
|
}
|
|
|
|
// Get top spam IPs
|
|
arsort($ipCounts);
|
|
$spamPatterns['top_ips'] = array_slice($ipCounts, 0, 10, true);
|
|
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Spam Analysis Dashboard - UK Data Services</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #333; }
|
|
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
|
h1 { margin-bottom: 30px; color: #764ba2; }
|
|
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 30px; }
|
|
.stat-card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
.stat-card h3 { font-size: 14px; color: #666; margin-bottom: 10px; }
|
|
.stat-card .value { font-size: 32px; font-weight: bold; color: #764ba2; }
|
|
.section { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; }
|
|
.section h2 { margin-bottom: 15px; color: #333; }
|
|
table { width: 100%; border-collapse: collapse; }
|
|
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
|
|
th { background: #f8f8f8; font-weight: 600; }
|
|
.log-entry { font-family: monospace; font-size: 12px; }
|
|
.error { color: #ef4444; }
|
|
.success { color: #10b981; }
|
|
.chart { margin: 20px 0; }
|
|
.bar { background: #764ba2; height: 20px; margin-bottom: 5px; transition: width 0.3s; }
|
|
.bar-label { font-size: 12px; color: #666; }
|
|
.blocked-ip { background: #fee; color: #c00; padding: 2px 6px; border-radius: 3px; font-family: monospace; font-size: 12px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>Spam Analysis Dashboard</h1>
|
|
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<h3>reCAPTCHA Failures</h3>
|
|
<div class="value"><?php echo $spamPatterns['recaptcha_failures']; ?></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Direct POST Attempts</h3>
|
|
<div class="value"><?php echo $spamPatterns['direct_post_attempts']; ?></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Rate Limit Hits</h3>
|
|
<div class="value"><?php echo $spamPatterns['rate_limit_hits']; ?></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Low Interaction Scores</h3>
|
|
<div class="value"><?php echo $spamPatterns['low_interaction_scores']; ?></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Blocked IPs</h3>
|
|
<div class="value"><?php echo $spamPatterns['blocked_ips_count']; ?></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Successful Submissions</h3>
|
|
<div class="value"><?php echo count($contactSubmissions); ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Hourly Spam Distribution</h2>
|
|
<div class="chart">
|
|
<?php
|
|
$maxHourly = max($spamPatterns['hourly_distribution']);
|
|
for ($hour = 0; $hour < 24; $hour++):
|
|
$count = $spamPatterns['hourly_distribution'][$hour];
|
|
$width = $maxHourly > 0 ? ($count / $maxHourly * 100) : 0;
|
|
?>
|
|
<div style="display: flex; align-items: center; margin-bottom: 5px;">
|
|
<div class="bar-label" style="width: 40px;"><?php echo str_pad($hour, 2, '0', STR_PAD_LEFT); ?>:00</div>
|
|
<div class="bar" style="width: <?php echo $width; ?>%;"></div>
|
|
<div class="bar-label" style="margin-left: 10px;"><?php echo $count; ?></div>
|
|
</div>
|
|
<?php endfor; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Top Spam Source IPs</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>IP Address</th>
|
|
<th>Attempts</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($spamPatterns['top_ips'] as $ip => $count): ?>
|
|
<tr>
|
|
<td><span class="blocked-ip"><?php echo htmlspecialchars($ip); ?></span></td>
|
|
<td><?php echo $count; ?></td>
|
|
<td>
|
|
<?php
|
|
$isBlocked = false;
|
|
foreach ($blockedIPs as $blockedEntry) {
|
|
if (strpos($blockedEntry, $ip . '|') === 0) {
|
|
$isBlocked = true;
|
|
break;
|
|
}
|
|
}
|
|
echo $isBlocked ? '<span class="error">Blocked</span>' : '<span class="success">Active</span>';
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Recent Error Log (Last 20)</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Timestamp</th>
|
|
<th>Error</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach (array_slice($contactErrors, 0, 20) as $error): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($error['timestamp']); ?></td>
|
|
<td class="log-entry"><?php echo htmlspecialchars($error['message']); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Recent Successful Submissions (Last 10)</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Timestamp</th>
|
|
<th>Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach (array_slice($contactSubmissions, 0, 10) as $submission): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($submission['timestamp']); ?></td>
|
|
<td class="log-entry"><?php echo htmlspecialchars($submission['message']); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|