Files
controls-web/includes/control-logger.php
2026-02-17 12:44:37 -06:00

172 lines
5.8 KiB
PHP

<?php // phpcs:ignoreFile
declare(strict_types=1);
require_once __DIR__ . '/db.php';
if (!function_exists('control_log_write')) {
/**
* Persist a control write audit entry into the configured log store.
*
* @param array<string, mixed> $entry
*
* @return array{success:bool, driver:?string, error:?string, path:?string}
*/
function control_log_write(array $entry): array
{
static $tableName;
static $fallbackPath;
/** @var array<string, array<int, string>> $columnsCache */
static $columnsCache = [];
$result = [
'success' => false,
'driver' => null,
'error' => null,
'path' => null,
];
$settings = include __DIR__ . '/../config/control-settings.php';
if ($tableName === null) {
$configuredTable = $settings['log_table'] ?? null;
if (!is_string($configuredTable) || trim($configuredTable) === '') {
$result['error'] = 'Control log table name is not configured.';
error_log('Control write log insert failed: ' . $result['error']);
return $result;
}
$tableName = trim($configuredTable);
}
if ($fallbackPath === null) {
$configuredFallback = $settings['log_fallback_path'] ?? '';
if (is_string($configuredFallback) && trim($configuredFallback) !== '') {
$fallbackPath = $configuredFallback;
} else {
$fallbackPath = '';
}
}
try {
$connection = controls_db_connect();
$tableKey = $tableName;
if (!isset($columnsCache[$tableKey])) {
$tableEscaped = $connection->real_escape_string($tableName);
$columnsResult = $connection->query('SHOW COLUMNS FROM `' . $tableEscaped . '`');
if ($columnsResult === false) {
throw new RuntimeException('Unable to determine columns for control write log table.');
}
$columns = [];
while ($column = $columnsResult->fetch_assoc()) {
if (isset($column['Field'])) {
$columns[] = $column['Field'];
}
}
$columnsResult->free();
$columnsCache[$tableKey] = $columns;
}
$availableColumns = $columnsCache[$tableKey] ?? [];
if ($availableColumns === []) {
throw new RuntimeException('No columns available on control write log table.');
}
$insertData = [];
foreach ($entry as $column => $value) {
if (in_array($column, $availableColumns, true)) {
$insertData[$column] = $value;
}
}
if ($insertData === []) {
$result['error'] = 'None of the provided fields matched the log table columns.';
error_log('Control write log insert skipped: ' . $result['error']);
} else {
$fields = [];
$values = [];
foreach ($insertData as $column => $value) {
$fields[] = '`' . $connection->real_escape_string($column) . '`';
if ($value === null) {
$values[] = 'NULL';
continue;
}
if (is_bool($value)) {
$values[] = $value ? "'1'" : "'0'";
continue;
}
$values[] = "'" . $connection->real_escape_string((string) $value) . "'";
}
$tableEscaped = $connection->real_escape_string($tableName);
$sql = sprintf(
'INSERT INTO `%s` (%s) VALUES (%s)',
$tableEscaped,
implode(', ', $fields),
implode(', ', $values)
);
$connection->query($sql);
$result['success'] = true;
$result['driver'] = 'database';
$result['error'] = null;
return $result;
}
} catch (Throwable $exception) {
$result['error'] = $exception->getMessage();
error_log('Control write log insert failed: ' . $exception->getMessage());
}
if ($fallbackPath === '') {
return $result;
}
try {
$directory = dirname($fallbackPath);
if ($directory !== '' && !is_dir($directory)) {
if (!mkdir($directory, 0775, true) && !is_dir($directory)) {
throw new RuntimeException('Unable to create fallback log directory: ' . $directory);
}
}
$record = [
'timestamp' => gmdate('c'),
'entry' => $entry,
'error' => $result['error'],
];
$json = json_encode($record, JSON_THROW_ON_ERROR);
file_put_contents($fallbackPath, $json . PHP_EOL, FILE_APPEND | LOCK_EX);
$result['success'] = true;
$result['driver'] = 'file';
$result['path'] = $fallbackPath;
error_log('Control write log stored in fallback file: ' . $fallbackPath);
} catch (Throwable $fallbackException) {
$result['driver'] = 'none';
$result['path'] = null;
$fallbackMessage = $fallbackException->getMessage();
if ($result['error'] !== null) {
$result['error'] .= '; ' . $fallbackMessage;
} else {
$result['error'] = $fallbackMessage;
}
error_log('Control write log fallback failed: ' . $fallbackMessage);
}
return $result;
}
}