49 lines
1.4 KiB
PHP
49 lines
1.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
final class AuditLog
|
|
{
|
|
/**
|
|
* @param array<string,mixed> $fields
|
|
*/
|
|
public static function append(string $path, array $fields): void
|
|
{
|
|
self::safeAppend($path, $fields);
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $fields
|
|
*/
|
|
public static function safeAppend(string $path, array $fields): void
|
|
{
|
|
$dir = dirname($path);
|
|
if (!is_dir($dir)) {
|
|
@mkdir($dir, 0700, true);
|
|
}
|
|
$fields = self::redact($fields);
|
|
$fields['timestamp'] = gmdate('c');
|
|
$line = json_encode($fields, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
if (is_string($line)) {
|
|
@file_put_contents($path, $line . "\n", FILE_APPEND | LOCK_EX);
|
|
@chmod($path, 0600);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $fields
|
|
* @return array<string,mixed>
|
|
*/
|
|
private static function redact(array $fields): array
|
|
{
|
|
foreach ($fields as $key => $value) {
|
|
$lower = strtolower((string)$key);
|
|
if (str_contains($lower, 'url') || str_contains($lower, 'key') || str_contains($lower, 'password') || str_contains($lower, 'secret')) {
|
|
$fields[$key] = '[redacted]';
|
|
} elseif (is_string($value)) {
|
|
$fields[$key] = preg_replace('/key=[A-Za-z0-9._-]+/', 'key=[redacted]', $value) ?? $value;
|
|
}
|
|
}
|
|
return $fields;
|
|
}
|
|
}
|