/home/suroeste/public_html/payments.transportessuroeste.com/src/Services
Edit: /home/suroeste/public_html/payments.transportessuroeste.com/src/Services/LogService.php (9678B)
100, 'INFO' => 200, 'WARNING' => 300, 'ERROR' => 400, 'CRITICAL' => 500];
private static int $minLevel = 200;
public static function setMinLevel(string $level): void
{
self::$minLevel = self::LEVELS[strtoupper($level)] ?? 200;
}
public static function debug(string $channel, string $message, array $context = []): void
{
self::log('DEBUG', $channel, $message, $context);
}
public static function info(string $channel, string $message, array $context = []): void
{
self::log('INFO', $channel, $message, $context);
}
public static function warning(string $channel, string $message, array $context = []): void
{
self::log('WARNING', $channel, $message, $context);
}
public static function error(string $channel, string $message, array $context = []): void
{
self::log('ERROR', $channel, $message, $context);
}
public static function critical(string $channel, string $message, array $context = []): void
{
self::log('CRITICAL', $channel, $message, $context);
}
/**
* Log de acceso a la API
*/
public static function access(string $method, string $uri, int $statusCode, float $responseTime = 0, ?string $clientId = null): void
{
$context = [
'method' => $method,
'uri' => $uri,
'status_code' => $statusCode,
'response_time_ms' => round($responseTime, 2),
'client_id' => $clientId,
'ip_address' => self::getClientIp(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown',
'timestamp' => self::getMicrotime()
];
self::log('INFO', 'access', "{$method} {$uri} - {$statusCode}", $context);
}
/**
* Log de transaccion para auditoria bancaria
*/
public static function transaction(string $transactionId, string $action, string $status, array $data = []): void
{
$context = [
'transaction_id' => $transactionId,
'action' => $action,
'status' => $status,
'ip_address' => self::getClientIp(),
'timestamp' => self::getMicrotime(),
'data' => self::sanitize($data)
];
self::log('INFO', 'transactions', "TX {$transactionId}: {$action} - {$status}", $context);
// Guardar en BD con todos los campos requeridos
self::saveToDb('transaction_logs', [
'log_uuid' => self::generateUuidV4(),
'log_type' => $action,
'action' => "{$action} - {$status}",
'ip_address' => self::getClientIp(),
'created_at' => date('Y-m-d H:i:s'),
]);
}
/**
* Log de evento de seguridad
*/
public static function security(string $eventType, string $message, array $context = []): void
{
$data = array_merge([
'event_type' => $eventType,
'source_ip' => self::getClientIp(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown',
'timestamp' => self::getMicrotime()
], $context);
self::log('WARNING', 'security', $message, $data);
// Guardar en BD con todos los campos requeridos
self::saveToDb('security_events', [
'event_uuid' => self::generateUuidV4(),
'event_type' => $eventType,
'severity' => self::classifySeverity($eventType),
'source_ip' => self::getClientIp(),
'description' => $message,
'created_at' => date('Y-m-d H:i:s'),
]);
}
/**
* Log de auditoria
*/
public static function audit(string $action, string $entity, ?string $entityId = null, array $data = []): void
{
$context = [
'action' => $action,
'entity_type' => $entity,
'entity_id' => $entityId,
'actor_ip' => self::getClientIp(),
'audit_uuid' => self::generateUuidV4(),
'created_at' => self::getMicrotime()
];
self::log('INFO', 'audit', "{$action} on {$entity}", array_merge($context, $data));
// Guardar en BD con todos los campos requeridos (incluye actor_type)
self::saveToDb('audit_trail', [
'audit_uuid' => $context['audit_uuid'],
'entity_type' => $entity,
'entity_id' => $entityId,
'action' => $action,
'actor_type' => $data['actor_type'] ?? 'system',
'actor_ip' => self::getClientIp(),
'created_at' => date('Y-m-d H:i:s'),
]);
}
private static function log(string $level, string $channel, string $message, array $context = []): void
{
if (self::LEVELS[$level] < self::$minLevel) return;
$entry = [
'timestamp' => self::getMicrotime(),
'level' => $level,
'channel' => $channel,
'message' => $message,
'context' => self::sanitize($context),
'request_id' => self::getRequestId()
];
self::writeToFile($channel, $entry);
}
private static function writeToFile(string $channel, array $entry): void
{
$path = LOG_CONFIG['path'];
if (!is_dir($path)) mkdir($path, 0750, true);
$file = $path . (LOG_CONFIG['channels'][$channel] ?? 'app.log');
$line = json_encode($entry, JSON_UNESCAPED_UNICODE) . PHP_EOL;
file_put_contents($file, $line, FILE_APPEND | LOCK_EX);
}
private static function saveToDb(string $table, array $data): void
{
try {
$validFields = match($table) {
'transaction_logs' => ['log_uuid', 'transaction_id', 'epayco_session_id', 'log_type', 'action', 'ip_address', 'created_at'],
'security_events' => ['event_uuid', 'event_type', 'severity', 'source_ip', 'description', 'created_at'],
'audit_trail' => ['audit_uuid', 'entity_type', 'entity_id', 'action', 'actor_type', 'actor_ip', 'created_at'],
default => []
};
$filtered = array_intersect_key($data, array_flip($validFields));
if (!empty($filtered)) {
Database::getInstance()->insert($table, $filtered);
}
} catch (\Exception $e) {
// Log a archivo para poder diagnosticar fallos en BD
$errorMsg = sprintf(
"[%s] Audit DB Error on table '%s': %s | Data: %s",
date('Y-m-d H:i:s'),
$table,
$e->getMessage(),
json_encode($data, JSON_UNESCAPED_UNICODE)
);
error_log($errorMsg);
// Tambien escribir al canal de errores de la app
self::writeToFile('errors', [
'timestamp' => self::getMicrotime(),
'level' => 'ERROR',
'channel' => 'audit_db',
'message' => "Error guardando en {$table}: " . $e->getMessage(),
'context' => ['table' => $table, 'data_keys' => array_keys($data)],
'request_id' => self::getRequestId()
]);
}
}
/**
* Clasificar severidad segun tipo de evento
*/
private static function classifySeverity(string $eventType): string
{
return match($eventType) {
'sql_injection_attempt', 'xss_attempt', 'path_traversal' => 'critical',
'rate_limit_exceeded', 'auth_failure', 'webhook_blocked' => 'high',
'malicious_bot', 'invalid_signature' => 'medium',
default => 'low'
};
}
/**
* Generar UUID v4 sin dependencia de EncryptionService (evita recursion)
*/
private static function generateUuidV4(): string
{
$data = random_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
private static function sanitize(array $data): array
{
$sensitive = ['password', 'secret', 'token', 'api_key', 'card_number', 'cvv', 'pin'];
$result = [];
foreach ($data as $key => $value) {
$lower = strtolower($key);
foreach ($sensitive as $s) {
if (str_contains($lower, $s)) {
$result[$key] = '***REDACTED***';
continue 2;
}
}
$result[$key] = is_array($value) ? self::sanitize($value) : $value;
}
return $result;
}
private static function getMicrotime(): string
{
$mt = microtime(true);
return date('Y-m-d H:i:s.', (int)$mt) . sprintf('%06d', ($mt - floor($mt)) * 1000000);
}
private static function getRequestId(): string
{
static $id = null;
return $id ??= $_SERVER['HTTP_X_REQUEST_ID'] ?? bin2hex(random_bytes(16));
}
public static function getClientIp(): string
{
foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'] as $h) {
if (!empty($_SERVER[$h])) {
$ip = trim(explode(',', $_SERVER[$h])[0]);
if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip;
}
}
return '0.0.0.0';
}
}