Sindbad~EG File Manager
<?php
session_start();
require_once '../config/database.php';
require_once '../includes/functions.php';
if (!isset($_SESSION['user_id'])) {
header('Location: ../login.php');
exit();
}
// Check permission for audit access
if (!checkPermission('admin') && $_SESSION['user_level'] !== 'superuser') {
header('Location: ' . $_SESSION['user_level'] . '.php?error=access_denied');
exit();
}
$page_title = 'Audit Logs';
$page_description = 'System activity and change tracking';
// Get filters
$user_filter = isset($_GET['user']) ? (int)$_GET['user'] : 0;
$action_filter = isset($_GET['action']) ? sanitizeInput($_GET['action']) : '';
$date_from = isset($_GET['date_from']) ? sanitizeInput($_GET['date_from']) : '';
$date_to = isset($_GET['date_to']) ? sanitizeInput($_GET['date_to']) : '';
// Pagination
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$per_page = 50;
$offset = ($page - 1) * $per_page;
// Build query conditions
$where_conditions = [];
$params = [];
if ($user_filter > 0) {
$where_conditions[] = "al.user_id = :user_id";
$params[':user_id'] = $user_filter;
}
if (!empty($action_filter)) {
$where_conditions[] = "al.action = :action";
$params[':action'] = $action_filter;
}
if (!empty($date_from)) {
$where_conditions[] = "DATE(al.created_at) >= :date_from";
$params[':date_from'] = $date_from;
}
if (!empty($date_to)) {
$where_conditions[] = "DATE(al.created_at) <= :date_to";
$params[':date_to'] = $date_to;
}
// Apply user level restrictions
if ($_SESSION['user_level'] !== 'superuser') {
if ($_SESSION['user_level'] === 'area') {
$where_conditions[] = "u.area_id = :area_id";
$params[':area_id'] = $_SESSION['area_id'];
} elseif ($_SESSION['user_level'] === 'district') {
$where_conditions[] = "u.district_id = :district_id";
$params[':district_id'] = $_SESSION['district_id'];
} elseif ($_SESSION['user_level'] === 'assembly') {
$where_conditions[] = "u.assembly_id = :assembly_id";
$params[':assembly_id'] = $_SESSION['assembly_id'];
}
}
$where_clause = !empty($where_conditions) ? 'WHERE ' . implode(' AND ', $where_conditions) : '';
// Count total records
$count_query = "SELECT COUNT(*) as total
FROM audit_logs al
JOIN users u ON al.user_id = u.id
$where_clause";
$count_stmt = $db->prepare($count_query);
foreach ($params as $key => $value) {
$count_stmt->bindValue($key, $value);
}
$count_stmt->execute();
$total_records = $count_stmt->fetch(PDO::FETCH_ASSOC)['total'];
$total_pages = ceil($total_records / $per_page);
// Get audit logs
$audit_query = "SELECT al.*, u.first_name, u.last_name, u.username, u.user_level
FROM audit_logs al
JOIN users u ON al.user_id = u.id
$where_clause
ORDER BY al.created_at DESC
LIMIT :offset, :per_page";
$audit_stmt = $db->prepare($audit_query);
foreach ($params as $key => $value) {
$audit_stmt->bindValue($key, $value);
}
$audit_stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$audit_stmt->bindValue(':per_page', $per_page, PDO::PARAM_INT);
$audit_stmt->execute();
$audit_logs = $audit_stmt->fetchAll(PDO::FETCH_ASSOC);
// Get users for filter dropdown
$users_query = "SELECT id, first_name, last_name, username FROM users WHERE is_active = 1 ORDER BY first_name, last_name";
$users_stmt = $db->prepare($users_query);
$users_stmt->execute();
$users = $users_stmt->fetchAll(PDO::FETCH_ASSOC);
// Get unique actions for filter
$actions_query = "SELECT DISTINCT action FROM audit_logs ORDER BY action";
$actions_stmt = $db->prepare($actions_query);
$actions_stmt->execute();
$actions = $actions_stmt->fetchAll(PDO::FETCH_ASSOC);
include '../includes/header.php';
?>
<!-- Filters -->
<div class="bg-white rounded-lg shadow-sm mb-6">
<div class="p-6 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Filter Audit Logs</h3>
</div>
<div class="p-6">
<form method="GET" action="" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
<div>
<label for="user" class="block text-sm font-medium text-gray-700 mb-2">User</label>
<select id="user" name="user" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cop-blue focus:border-transparent">
<option value="">All Users</option>
<?php foreach ($users as $user): ?>
<option value="<?php echo $user['id']; ?>" <?php echo $user_filter == $user['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($user['first_name'] . ' ' . $user['last_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="action" class="block text-sm font-medium text-gray-700 mb-2">Action</label>
<select id="action" name="action" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cop-blue focus:border-transparent">
<option value="">All Actions</option>
<?php foreach ($actions as $action): ?>
<option value="<?php echo htmlspecialchars($action['action']); ?>" <?php echo $action_filter == $action['action'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($action['action']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="date_from" class="block text-sm font-medium text-gray-700 mb-2">From Date</label>
<input type="date"
id="date_from"
name="date_from"
value="<?php echo htmlspecialchars($date_from); ?>"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cop-blue focus:border-transparent">
</div>
<div>
<label for="date_to" class="block text-sm font-medium text-gray-700 mb-2">To Date</label>
<input type="date"
id="date_to"
name="date_to"
value="<?php echo htmlspecialchars($date_to); ?>"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cop-blue focus:border-transparent">
</div>
<div class="flex items-end">
<button type="submit" class="w-full px-4 py-2 bg-cop-blue text-white rounded-lg hover:bg-cop-light-blue transition duration-200">
<i class="fas fa-search mr-2"></i>Filter
</button>
</div>
</form>
<?php if ($user_filter || $action_filter || $date_from || $date_to): ?>
<div class="mt-4">
<a href="audit.php" class="text-sm text-gray-600 hover:text-gray-800">
<i class="fas fa-times mr-1"></i>Clear Filters
</a>
</div>
<?php endif; ?>
</div>
</div>
<!-- Audit Logs -->
<div class="bg-white rounded-lg shadow-sm">
<div class="p-6 border-b border-gray-200">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold text-gray-800">Audit Logs</h3>
<div class="text-sm text-gray-600">
Total: <?php echo number_format($total_records); ?> records
</div>
</div>
</div>
<div class="overflow-x-auto">
<?php if (empty($audit_logs)): ?>
<div class="text-center py-12">
<i class="fas fa-history text-4xl text-gray-400 mb-4"></i>
<h3 class="text-lg font-medium text-gray-600 mb-2">No audit logs found</h3>
<p class="text-gray-500">No activities match your current filters.</p>
</div>
<?php else: ?>
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Table</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Record ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">IP Address</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date/Time</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Details</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<?php foreach ($audit_logs as $log): ?>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center mr-3">
<span class="text-xs font-medium text-gray-600">
<?php echo strtoupper(substr($log['first_name'], 0, 1) . substr($log['last_name'], 0, 1)); ?>
</span>
</div>
<div>
<div class="text-sm font-medium text-gray-900">
<?php echo htmlspecialchars($log['first_name'] . ' ' . $log['last_name']); ?>
</div>
<div class="text-sm text-gray-500 capitalize">
<?php echo htmlspecialchars($log['user_level']); ?>
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
<?php
echo $log['action'] === 'CREATE' ? 'bg-green-100 text-green-800' :
($log['action'] === 'UPDATE' ? 'bg-blue-100 text-blue-800' :
($log['action'] === 'DELETE' ? 'bg-red-100 text-red-800' :
($log['action'] === 'LOGIN' ? 'bg-purple-100 text-purple-800' : 'bg-gray-100 text-gray-800')));
?>">
<?php echo htmlspecialchars($log['action']); ?>
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<?php echo htmlspecialchars($log['table_name']); ?>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<?php echo $log['record_id'] ? htmlspecialchars($log['record_id']) : '-'; ?>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<?php echo htmlspecialchars($log['ip_address']); ?>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<?php echo formatDateTime($log['created_at']); ?>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<?php if ($log['old_values'] || $log['new_values']): ?>
<button onclick="showAuditDetails(<?php echo htmlspecialchars(json_encode($log)); ?>)"
class="text-cop-blue hover:text-cop-light-blue">
<i class="fas fa-eye"></i>
</button>
<?php else: ?>
-
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<div class="px-6 py-4 border-t border-gray-200">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-600">
Showing <?php echo $offset + 1; ?> to <?php echo min($offset + $per_page, $total_records); ?> of <?php echo $total_records; ?> records
</div>
<div class="flex space-x-2">
<?php if ($page > 1): ?>
<a href="?page=<?php echo $page - 1; ?>&user=<?php echo $user_filter; ?>&action=<?php echo $action_filter; ?>&date_from=<?php echo $date_from; ?>&date_to=<?php echo $date_to; ?>"
class="px-3 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition duration-200">
<i class="fas fa-chevron-left"></i>
</a>
<?php endif; ?>
<?php for ($i = max(1, $page - 2); $i <= min($total_pages, $page + 2); $i++): ?>
<a href="?page=<?php echo $i; ?>&user=<?php echo $user_filter; ?>&action=<?php echo $action_filter; ?>&date_from=<?php echo $date_from; ?>&date_to=<?php echo $date_to; ?>"
class="px-3 py-2 rounded-lg transition duration-200 <?php echo $i === $page ? 'bg-cop-blue text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'; ?>">
<?php echo $i; ?>
</a>
<?php endfor; ?>
<?php if ($page < $total_pages): ?>
<a href="?page=<?php echo $page + 1; ?>&user=<?php echo $user_filter; ?>&action=<?php echo $action_filter; ?>&date_from=<?php echo $date_from; ?>&date_to=<?php echo $date_to; ?>"
class="px-3 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition duration-200">
<i class="fas fa-chevron-right"></i>
</a>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<!-- Audit Details Modal -->
<div id="auditModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden z-50">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-96 overflow-y-auto">
<div class="p-6 border-b border-gray-200">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold text-gray-800">Audit Details</h3>
<button onclick="closeAuditModal()" class="text-gray-400 hover:text-gray-600">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<div class="p-6">
<div id="auditDetailsContent"></div>
</div>
</div>
</div>
</div>
<script>
function showAuditDetails(log) {
const modal = document.getElementById('auditModal');
const content = document.getElementById('auditDetailsContent');
let html = `
<div class="space-y-4">
<div>
<h4 class="font-medium text-gray-800 mb-2">Action Information</h4>
<div class="bg-gray-50 rounded-lg p-4">
<div class="grid grid-cols-2 gap-4 text-sm">
<div><span class="font-medium">User:</span> ${log.first_name} ${log.last_name}</div>
<div><span class="font-medium">Action:</span> ${log.action}</div>
<div><span class="font-medium">Table:</span> ${log.table_name}</div>
<div><span class="font-medium">Record ID:</span> ${log.record_id || 'N/A'}</div>
<div><span class="font-medium">IP Address:</span> ${log.ip_address}</div>
<div><span class="font-medium">Date/Time:</span> ${new Date(log.created_at).toLocaleString()}</div>
</div>
</div>
</div>
`;
if (log.old_values) {
html += `
<div>
<h4 class="font-medium text-gray-800 mb-2">Old Values</h4>
<div class="bg-red-50 rounded-lg p-4">
<pre class="text-sm text-gray-700 whitespace-pre-wrap">${JSON.stringify(JSON.parse(log.old_values), null, 2)}</pre>
</div>
</div>
`;
}
if (log.new_values) {
html += `
<div>
<h4 class="font-medium text-gray-800 mb-2">New Values</h4>
<div class="bg-green-50 rounded-lg p-4">
<pre class="text-sm text-gray-700 whitespace-pre-wrap">${JSON.stringify(JSON.parse(log.new_values), null, 2)}</pre>
</div>
</div>
`;
}
html += '</div>';
content.innerHTML = html;
modal.classList.remove('hidden');
}
function closeAuditModal() {
document.getElementById('auditModal').classList.add('hidden');
}
// Close modal when clicking outside
document.getElementById('auditModal').addEventListener('click', function(e) {
if (e.target === this) {
closeAuditModal();
}
});
</script>
<?php include '../includes/footer.php'; ?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists