Files
AudioCore/core/services/Audit.php

106 lines
3.4 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Core\Services;
use PDO;
use Throwable;
class Audit
{
public static function ensureTable(): void
{
$db = Database::get();
if (!($db instanceof PDO)) {
return;
}
try {
$db->exec("
CREATE TABLE IF NOT EXISTS ac_audit_logs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
actor_id INT UNSIGNED NULL,
actor_name VARCHAR(120) NULL,
actor_role VARCHAR(40) NULL,
action VARCHAR(120) NOT NULL,
context_json MEDIUMTEXT NULL,
ip_address VARCHAR(45) NULL,
user_agent VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
} catch (Throwable $e) {
return;
}
}
public static function log(string $action, array $context = []): void
{
$db = Database::get();
if (!($db instanceof PDO)) {
return;
}
self::ensureTable();
try {
$stmt = $db->prepare("
INSERT INTO ac_audit_logs
(actor_id, actor_name, actor_role, action, context_json, ip_address, user_agent)
VALUES
(:actor_id, :actor_name, :actor_role, :action, :context_json, :ip_address, :user_agent)
");
$stmt->execute([
':actor_id' => Auth::id() > 0 ? Auth::id() : null,
':actor_name' => Auth::name() !== '' ? Auth::name() : null,
':actor_role' => Auth::role() !== '' ? Auth::role() : null,
':action' => $action,
':context_json' => $context ? json_encode($context, JSON_UNESCAPED_SLASHES) : null,
':ip_address' => self::ip(),
':user_agent' => mb_substr((string)($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255),
]);
} catch (Throwable $e) {
return;
}
}
public static function latest(int $limit = 100): array
{
$db = Database::get();
if (!($db instanceof PDO)) {
return [];
}
self::ensureTable();
$limit = max(1, min(500, $limit));
try {
$stmt = $db->prepare("
SELECT id, actor_name, actor_role, action, context_json, ip_address, created_at
FROM ac_audit_logs
ORDER BY id DESC
LIMIT :limit
");
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
} catch (Throwable $e) {
return [];
}
}
private static function ip(): ?string
{
$candidates = [
(string)($_SERVER['HTTP_CF_CONNECTING_IP'] ?? ''),
(string)($_SERVER['HTTP_X_FORWARDED_FOR'] ?? ''),
(string)($_SERVER['REMOTE_ADDR'] ?? ''),
];
foreach ($candidates as $candidate) {
if ($candidate === '') {
continue;
}
$first = trim(explode(',', $candidate)[0] ?? '');
if ($first !== '' && filter_var($first, FILTER_VALIDATE_IP)) {
return $first;
}
}
return null;
}
}