- Implemented nodes management functionality in `nodes.php` including create, update, and delete actions. - Added form validation and error handling for node operations. - Created a new setup page in `setup.php` for initial administrator account creation. - Included user feedback messages for successful operations and errors. - Designed user interface for both nodes management and setup processes.
286 lines
7.7 KiB
PHP
286 lines
7.7 KiB
PHP
<?php
|
|
/**
|
|
* Logger Class
|
|
*
|
|
* Handles audit logging for the Pathvector admin dashboard
|
|
*/
|
|
|
|
require_once __DIR__ . '/FlatFileDB.php';
|
|
|
|
class Logger {
|
|
private FlatFileDB $db;
|
|
private int $maxEntries;
|
|
private array $validLevels = ['info', 'warning', 'error', 'success'];
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param string $logFile Path to the log file
|
|
* @param int $maxEntries Maximum number of log entries to keep
|
|
*/
|
|
public function __construct(string $logFile, int $maxEntries = 1000) {
|
|
$this->db = new FlatFileDB($logFile);
|
|
$this->maxEntries = $maxEntries;
|
|
|
|
// Initialize logs array if not exists
|
|
if (!$this->db->exists('logs')) {
|
|
$this->db->set('logs', []);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a log entry
|
|
*
|
|
* @param string $level Log level (info, warning, error, success)
|
|
* @param string $action Action performed
|
|
* @param string $message Log message
|
|
* @param string|null $user User who performed the action
|
|
* @param array $context Additional context data
|
|
* @return bool
|
|
*/
|
|
public function log(string $level, string $action, string $message, ?string $user = null, array $context = []): bool {
|
|
if (!in_array($level, $this->validLevels)) {
|
|
$level = 'info';
|
|
}
|
|
|
|
$logs = $this->db->get('logs') ?? [];
|
|
|
|
$entry = [
|
|
'id' => uniqid('log_'),
|
|
'timestamp' => date('c'),
|
|
'level' => $level,
|
|
'action' => $action,
|
|
'message' => $message,
|
|
'user' => $user ?? ($_SESSION['user']['username'] ?? 'system'),
|
|
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
|
|
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
|
|
'context' => $context,
|
|
];
|
|
|
|
array_unshift($logs, $entry);
|
|
|
|
// Trim logs to max entries
|
|
if (count($logs) > $this->maxEntries) {
|
|
$logs = array_slice($logs, 0, $this->maxEntries);
|
|
}
|
|
|
|
return $this->db->set('logs', $logs);
|
|
}
|
|
|
|
/**
|
|
* Log info level message
|
|
*
|
|
* @param string $action
|
|
* @param string $message
|
|
* @param array $context
|
|
* @return bool
|
|
*/
|
|
public function info(string $action, string $message, array $context = []): bool {
|
|
return $this->log('info', $action, $message, null, $context);
|
|
}
|
|
|
|
/**
|
|
* Log warning level message
|
|
*
|
|
* @param string $action
|
|
* @param string $message
|
|
* @param array $context
|
|
* @return bool
|
|
*/
|
|
public function warning(string $action, string $message, array $context = []): bool {
|
|
return $this->log('warning', $action, $message, null, $context);
|
|
}
|
|
|
|
/**
|
|
* Log error level message
|
|
*
|
|
* @param string $action
|
|
* @param string $message
|
|
* @param array $context
|
|
* @return bool
|
|
*/
|
|
public function error(string $action, string $message, array $context = []): bool {
|
|
return $this->log('error', $action, $message, null, $context);
|
|
}
|
|
|
|
/**
|
|
* Log success level message
|
|
*
|
|
* @param string $action
|
|
* @param string $message
|
|
* @param array $context
|
|
* @return bool
|
|
*/
|
|
public function success(string $action, string $message, array $context = []): bool {
|
|
return $this->log('success', $action, $message, null, $context);
|
|
}
|
|
|
|
/**
|
|
* Get all logs
|
|
*
|
|
* @param int|null $limit
|
|
* @param int $offset
|
|
* @return array
|
|
*/
|
|
public function getLogs(?int $limit = null, int $offset = 0): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
|
|
if ($limit !== null) {
|
|
return array_slice($logs, $offset, $limit);
|
|
}
|
|
|
|
return $logs;
|
|
}
|
|
|
|
/**
|
|
* Get logs by level
|
|
*
|
|
* @param string $level
|
|
* @param int|null $limit
|
|
* @return array
|
|
*/
|
|
public function getByLevel(string $level, ?int $limit = null): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
$filtered = array_filter($logs, fn($log) => $log['level'] === $level);
|
|
|
|
if ($limit !== null) {
|
|
return array_slice($filtered, 0, $limit);
|
|
}
|
|
|
|
return array_values($filtered);
|
|
}
|
|
|
|
/**
|
|
* Get logs by user
|
|
*
|
|
* @param string $user
|
|
* @param int|null $limit
|
|
* @return array
|
|
*/
|
|
public function getByUser(string $user, ?int $limit = null): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
$filtered = array_filter($logs, fn($log) => $log['user'] === $user);
|
|
|
|
if ($limit !== null) {
|
|
return array_slice($filtered, 0, $limit);
|
|
}
|
|
|
|
return array_values($filtered);
|
|
}
|
|
|
|
/**
|
|
* Get logs by action
|
|
*
|
|
* @param string $action
|
|
* @param int|null $limit
|
|
* @return array
|
|
*/
|
|
public function getByAction(string $action, ?int $limit = null): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
$filtered = array_filter($logs, fn($log) => strpos($log['action'], $action) !== false);
|
|
|
|
if ($limit !== null) {
|
|
return array_slice($filtered, 0, $limit);
|
|
}
|
|
|
|
return array_values($filtered);
|
|
}
|
|
|
|
/**
|
|
* Get logs by date range
|
|
*
|
|
* @param string $startDate
|
|
* @param string $endDate
|
|
* @return array
|
|
*/
|
|
public function getByDateRange(string $startDate, string $endDate): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
$start = strtotime($startDate);
|
|
$end = strtotime($endDate);
|
|
|
|
return array_values(array_filter($logs, function($log) use ($start, $end) {
|
|
$logTime = strtotime($log['timestamp']);
|
|
return $logTime >= $start && $logTime <= $end;
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Search logs
|
|
*
|
|
* @param string $query
|
|
* @param int|null $limit
|
|
* @return array
|
|
*/
|
|
public function search(string $query, ?int $limit = null): array {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
$query = strtolower($query);
|
|
|
|
$filtered = array_filter($logs, function($log) use ($query) {
|
|
return strpos(strtolower($log['message']), $query) !== false ||
|
|
strpos(strtolower($log['action']), $query) !== false ||
|
|
strpos(strtolower($log['user']), $query) !== false;
|
|
});
|
|
|
|
if ($limit !== null) {
|
|
return array_slice($filtered, 0, $limit);
|
|
}
|
|
|
|
return array_values($filtered);
|
|
}
|
|
|
|
/**
|
|
* Get total log count
|
|
*
|
|
* @return int
|
|
*/
|
|
public function count(): int {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
return count($logs);
|
|
}
|
|
|
|
/**
|
|
* Clear all logs
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function clear(): bool {
|
|
return $this->db->set('logs', []);
|
|
}
|
|
|
|
/**
|
|
* Export logs to JSON
|
|
*
|
|
* @return string
|
|
*/
|
|
public function exportJson(): string {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
return json_encode($logs, JSON_PRETTY_PRINT);
|
|
}
|
|
|
|
/**
|
|
* Export logs to CSV
|
|
*
|
|
* @return string
|
|
*/
|
|
public function exportCsv(): string {
|
|
$logs = $this->db->get('logs') ?? [];
|
|
|
|
$output = "ID,Timestamp,Level,Action,Message,User,IP\n";
|
|
|
|
foreach ($logs as $log) {
|
|
$output .= sprintf(
|
|
'"%s","%s","%s","%s","%s","%s","%s"' . "\n",
|
|
$log['id'],
|
|
$log['timestamp'],
|
|
$log['level'],
|
|
str_replace('"', '""', $log['action']),
|
|
str_replace('"', '""', $log['message']),
|
|
$log['user'],
|
|
$log['ip']
|
|
);
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
}
|