fetchAll('SELECT clave, valor FROM lab_config ORDER BY clave');
foreach ($rows as $r) {
$cfg[$r['clave']] = $r['valor'];
}
} catch (Exception $e) {
// BD no disponible: continuar con defaults
}
$empresa = htmlspecialchars($cfg['empresa_nombre'] ?? 'Laboratorio Clínico', ENT_QUOTES, 'UTF-8');
$subtitulo= htmlspecialchars($cfg['empresa_subtitulo'] ?? 'Sistema de Gestión ERP', ENT_QUOTES, 'UTF-8');
$color = preg_match('/^#[0-9a-fA-F]{3,8}$/', $cfg['doc_color'] ?? '') ? $cfg['doc_color'] : '#1565c0';
$logo = $cfg['doc_logo_base64'] ?? '';
// Calcular color derivado más oscuro para el gradiente
function adjustColor(string $hex, int $amount): string {
$hex = ltrim($hex, '#');
$r = max(0, min(255, hexdec(substr($hex, 0, 2)) + $amount));
$g = max(0, min(255, hexdec(substr($hex, 2, 2)) + $amount));
$b = max(0, min(255, hexdec(substr($hex, 4, 2)) + $amount));
return sprintf('#%02x%02x%02x', $r, $g, $b);
}
$colorDark = adjustColor($color, -40);
?>
Iniciar Sesión — = $empresa ?>
= $empresa ?>
= $subtitulo ?>
Análisis Clínicos
Domicilios
Documentos PDF
Reportes
// Con Docker, la instalación siempre está completada
// El archivo .installation_completed se crea automáticamente o no es necesario
// Si ya está logueado, redirigir al panel
if (isUserLoggedIn()) {
header('Location: index.php');
exit;
}
$error = '';
$success = '';
$loginBlocked = false;
$clientIp = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
// Verificar si viene de logout
if (isset($_GET['logged_out']) && $_GET['logged_out'] == '1') {
$success = 'Sesión cerrada correctamente.';
}
// Verificar si la sesión expiró
if (isset($_GET['session_expired']) && $_GET['session_expired'] == '1') {
$error = 'Su sesión ha expirado por inactividad. Por favor, inicie sesión nuevamente.';
}
// Verificar si la IP está bloqueada
if (!checkLoginAttempts($clientIp)) {
$loginBlocked = true;
$error = 'Demasiados intentos de login. Inténtalo en ' . (LOGIN_LOCKOUT_TIME / 60) . ' minutos.';
}
// Procesar login
if ($_POST && !$loginBlocked) {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
// Usar el nuevo sistema de autenticación unificado
$adminUser = authenticateUser($username, $password);
if ($adminUser) {
// Login exitoso
clearLoginAttempts($clientIp);
$_SESSION['admin_logged_in'] = true;
$_SESSION['admin_user'] = $adminUser;
$_SESSION['last_activity'] = time();
$_SESSION['login_ip'] = $clientIp;
$_SESSION['login_time'] = time();
// Redirigir según el rol
$roleSlug = $adminUser['role'] ?? 'admin';
$modules = $adminUser['modules'] ?? [];
// 1. Página de inicio configurada explícitamente para el rol
if (!empty($adminUser['home_page'])) {
$safePath = filter_var($adminUser['home_page'], FILTER_SANITIZE_URL);
// Solo rutas relativas (evitar redirects abiertos)
if (str_starts_with($safePath, '/') && !str_starts_with($safePath, '//')) {
header('Location: ' . $safePath);
exit;
}
}
// 2. Reglas heredadas (compatibilidad hacia atrás)
if ($roleSlug === 'enfermero') {
header('Location: enfermero_portal.php');
} elseif (count($modules) === 1 && $modules[0] === 'lab_formularios') {
header('Location: lab_formularios.php');
} elseif (count($modules) === 2
&& in_array('lab_domicilios', $modules, true)
&& in_array('lab_ordenes', $modules, true)) {
header('Location: lab_domicilios.php');
} else {
header('Location: index.php');
}
exit;
} else {
// Login fallido
recordFailedLogin($clientIp);
$error = 'Usuario o contraseña incorrectos.';
if (!checkLoginAttempts($clientIp)) {
$loginBlocked = true;
$error = 'Demasiados intentos de login. Cuenta bloqueada por ' . (LOGIN_LOCKOUT_TIME / 60) . ' minutos.';
}
}
}
?>
🔐 Login - WhatsApp Bot Manager
WhatsApp Bot Manager
Panel de Administración
Protección Brute Force
Sesiones Seguras
Control de Acceso
Acceso Bloqueado
= htmlspecialchars($error) ?>