129 lines
5.0 KiB
PHP
129 lines
5.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
class LoginController
|
|
{
|
|
public static function showForm(): void
|
|
{
|
|
SessionAuth::start();
|
|
if (!empty($_SESSION['user_id'])) {
|
|
header('Location: /admin/dashboard');
|
|
exit;
|
|
}
|
|
$token = SessionAuth::csrfToken();
|
|
$error = $_SESSION['login_error'] ?? '';
|
|
unset($_SESSION['login_error']);
|
|
self::renderForm($token, $error);
|
|
}
|
|
|
|
public static function authenticate(): void
|
|
{
|
|
SessionAuth::start();
|
|
SessionAuth::validateCsrf();
|
|
|
|
$email = trim($_POST['email'] ?? '');
|
|
$password = trim($_POST['password'] ?? '');
|
|
|
|
if ($email === '' || $password === '') {
|
|
$_SESSION['login_error'] = 'Completa todos los campos.';
|
|
header('Location: /login');
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
$stmt = db()->prepare('SELECT id, name, email, password FROM users WHERE email = ? LIMIT 1');
|
|
$stmt->execute([$email]);
|
|
$user = $stmt->fetch();
|
|
} catch (\PDOException $e) {
|
|
$_SESSION['login_error'] = 'Error de base de datos.';
|
|
header('Location: /login');
|
|
exit;
|
|
}
|
|
|
|
if (!$user || !password_verify($password, $user['password'])) {
|
|
sleep(1); // freno básico a fuerza bruta
|
|
$_SESSION['login_error'] = 'Correo o contraseña incorrectos.';
|
|
header('Location: /login');
|
|
exit;
|
|
}
|
|
|
|
SessionAuth::login($user);
|
|
header('Location: /admin/dashboard');
|
|
exit;
|
|
}
|
|
|
|
public static function logout(): void
|
|
{
|
|
SessionAuth::logout();
|
|
header('Location: /login');
|
|
exit;
|
|
}
|
|
|
|
// ─── Vista ───────────────────────────────────────────────────────────────
|
|
|
|
private static function renderForm(string $token, string $error): void
|
|
{
|
|
http_response_code(200);
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
$errorHtml = $error
|
|
? '<div class="alert">' . htmlspecialchars($error, ENT_QUOTES, 'UTF-8') . '</div>'
|
|
: '';
|
|
echo <<<HTML
|
|
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Ingresar — Palmas360</title>
|
|
<style>
|
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
body{font-family:'Segoe UI',Arial,sans-serif;background:#f0f2f5;display:flex;align-items:center;justify-content:center;min-height:100vh}
|
|
.card{background:#fff;border-radius:14px;box-shadow:0 4px 24px rgba(0,0,0,.10);width:100%;max-width:400px;overflow:hidden}
|
|
.ch{background:linear-gradient(135deg,#0b3d91 0%,#1565c0 100%);padding:40px 28px;color:#fff;text-align:center}
|
|
.ch .ico{margin-bottom:16px;display:flex;justify-content:center}
|
|
.ch .ico img{width:220px;max-width:100%;height:auto}
|
|
.ch h1{font-size:22px;font-weight:700}
|
|
.ch p{font-size:13px;opacity:.85;margin-top:5px}
|
|
.cb{padding:28px}
|
|
.alert{background:#fdecea;color:#c0392b;border-radius:8px;padding:10px 14px;font-size:13px;margin-bottom:16px}
|
|
label{display:block;font-size:13px;font-weight:600;color:#444;margin-bottom:5px}
|
|
input{width:100%;padding:10px 13px;border:1px solid #ddd;border-radius:8px;font-size:14px;outline:none;transition:border .2s;margin-bottom:16px}
|
|
input:focus{border-color:#1565c0}
|
|
button{width:100%;padding:12px;background:linear-gradient(135deg,#0b3d91,#1565c0);color:#fff;border:none;border-radius:8px;font-size:15px;font-weight:600;cursor:pointer}
|
|
button:hover{opacity:.92}
|
|
.foot{text-align:center;padding:14px;font-size:11px;color:#aaa;border-top:1px solid #f0f0f0}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<div class="ch">
|
|
<div class="ico"><img src="https://app.palmas360.com/Test/imgLogin/logo.png" alt="Palmas360"></div>
|
|
<h1>Palmas360</h1>
|
|
<p>Panel de administración — Somos19D</p>
|
|
</div>
|
|
<div class="cb">
|
|
{$errorHtml}
|
|
<form method="POST" action="/login">
|
|
<input type="hidden" name="_token" value="{$token}">
|
|
<label for="email">Correo electrónico</label>
|
|
<input type="email" id="email" name="email" required autocomplete="email" placeholder="admin@palmas360.com">
|
|
<label for="pwd">Contraseña</label>
|
|
<input type="password" id="pwd" name="password" required autocomplete="current-password" placeholder="••••••••">
|
|
<button type="submit">Ingresar al panel</button>
|
|
</form>
|
|
</div>
|
|
<div class="foot">© 2025 Somos19D</div>
|
|
</div>
|
|
|
|
<script>
|
|
console.log('%cDesarrollado por U-site', 'color:#1e88e5;font-size:14px;font-weight:700;');
|
|
console.log('%cEste panel es solo para gestión segura.', 'color:#90caf9;font-size:12px;');
|
|
console.log('%cNo pegues scripts en esta parte del navegador. Si alguien te lo pide, cierra esta ventana y repórtalo.', 'color:#ffb300;font-size:12px;');
|
|
</script>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
exit;
|
|
}
|
|
}
|