Files
gravity/จัดการข้อมูล Line KSH-STAFF/admin/login.php
T
2026-09-16 23:20:08 +07:00

182 lines
9.8 KiB
PHP

<?php
session_start();
require_once '../includes/db.php';
require_once '../includes/GoogleAuthenticator.php';
$ga = new PHPGangsta_GoogleAuthenticator();
$step = 1;
$error = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_POST['login_step_1'])) {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$stmt = $pdo->prepare("SELECT * FROM admin_users WHERE username = ?");
$stmt->execute([$username]);
$admin = $stmt->fetch();
if ($admin && password_verify($password, $admin['password_hash'])) {
// Step 1 Success
$_SESSION['temp_admin_id'] = $admin['id'];
$_SESSION['temp_admin_username'] = $admin['username'];
$_SESSION['temp_admin_role'] = $admin['role'];
$_SESSION['temp_admin_secret'] = $admin['google2fa_secret'];
if (empty($admin['google2fa_secret'])) {
// Not setup 2FA yet, go to setup
$_SESSION['admin_logged_in'] = true;
$_SESSION['admin_id'] = $admin['id'];
$_SESSION['admin_username'] = $admin['username'];
$_SESSION['admin_role'] = $admin['role'];
unset($_SESSION['temp_admin_id'], $_SESSION['temp_admin_username'], $_SESSION['temp_admin_role'], $_SESSION['temp_admin_secret']);
header("Location: setup_2fa.php");
exit;
} else {
$step = 2; // Move to 2FA step
}
} else {
$error = "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง";
}
} elseif (isset($_POST['login_step_2'])) {
$code = $_POST['code2fa'] ?? '';
$secret = $_SESSION['temp_admin_secret'];
if ($ga->verifyCode($secret, $code, 2)) {
// Success
$_SESSION['admin_logged_in'] = true;
$_SESSION['admin_id'] = $_SESSION['temp_admin_id'];
$_SESSION['admin_username'] = $_SESSION['temp_admin_username'];
$_SESSION['admin_role'] = $_SESSION['temp_admin_role'];
unset($_SESSION['temp_admin_id'], $_SESSION['temp_admin_username'], $_SESSION['temp_admin_role'], $_SESSION['temp_admin_secret']);
header("Location: index.php");
exit;
} else {
$error = "รหัส Google Authenticator ไม่ถูกต้อง";
$step = 2; // Stay at step 2
}
}
}
?>
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Login - KSH-STAFF</title>
<link rel="icon" type="image/png" href="../assets/img/logo.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Sarabun', 'sans-serif'],
},
animation: {
shine: 'shine 3s ease-in-out infinite'
},
keyframes: {
shine: {
'0%': { left: '-150%' },
'20%': { left: '150%' },
'100%': { left: '150%' }
}
}
}
}
}
</script>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center font-sans antialiased">
<div class="bg-white rounded-xl shadow-lg p-8 w-full max-w-md border border-gray-100">
<div class="text-center mb-6">
<div class="relative inline-block overflow-hidden rounded-full w-24 h-24 mx-auto mb-4 shadow-md bg-white p-1">
<img src="../assets/img/logo.png" alt="Logo" class="w-full h-full object-cover rounded-full relative z-10">
<div class="absolute inset-0 z-20 w-1/2 h-full bg-gradient-to-r from-transparent via-white/60 to-transparent -skew-x-12 animate-shine mix-blend-overlay"></div>
</div>
<h2 class="text-blue-600 text-2xl font-bold">Admin Login</h2>
</div>
<?php if (!empty($error)): ?>
<div class="text-red-500 text-center text-sm mb-4 font-medium bg-red-50 py-2 rounded-lg"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<?php if ($step === 1): ?>
<form method="post" class="space-y-4">
<div>
<label class="block text-gray-700 text-sm font-medium mb-1">Username (หรือ CID)</label>
<input type="text" name="username" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition" required autofocus>
</div>
<div>
<label class="block text-gray-700 text-sm font-medium mb-1">Password</label>
<input type="password" name="password" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition" required>
</div>
<button type="submit" name="login_step_1" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-4 rounded-lg transition duration-200 shadow-md hover:shadow-lg mt-2">เข้าสู่ระบบ</button>
</form>
<?php else: ?>
<form method="post" id="otp-form" class="space-y-6">
<div class="text-center text-gray-600 text-sm leading-relaxed">
กรุณาเปิดแอปพลิเคชัน <strong class="text-gray-800">Google Authenticator</strong><br>และนำรหัส 6 หลักมากรอก
</div>
<div class="flex justify-center gap-2">
<input type="text" maxlength="1" oninput="moveToNext(this, 'otp2')" id="otp1" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition" autofocus>
<input type="text" maxlength="1" oninput="moveToNext(this, 'otp3')" onkeydown="moveToPrev(event, this, 'otp1')" id="otp2" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition">
<input type="text" maxlength="1" oninput="moveToNext(this, 'otp4')" onkeydown="moveToPrev(event, this, 'otp2')" id="otp3" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition">
<input type="text" maxlength="1" oninput="moveToNext(this, 'otp5')" onkeydown="moveToPrev(event, this, 'otp3')" id="otp4" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition">
<input type="text" maxlength="1" oninput="moveToNext(this, 'otp6')" onkeydown="moveToPrev(event, this, 'otp4')" id="otp5" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition">
<input type="text" maxlength="1" oninput="submitOtp()" onkeydown="moveToPrev(event, this, 'otp5')" id="otp6" class="w-12 h-14 text-center text-2xl font-bold border-2 border-gray-300 rounded-lg focus:border-blue-500 focus:ring-4 focus:ring-blue-500/20 outline-none transition">
</div>
<input type="hidden" name="code2fa" id="code2fa" required>
<button type="submit" name="login_step_2" id="submit-btn" class="hidden">ยืนยันตัวตน</button>
<div class="text-center mt-6">
<a href="login.php" class="text-sm text-gray-500 hover:text-gray-800 hover:underline transition">ยกเลิก / กลับไปหน้าแรก</a>
</div>
</form>
<script>
function moveToNext(current, nextFieldId) {
if (current.value.length === 1) {
if (nextFieldId) document.getElementById(nextFieldId).focus();
}
}
function moveToPrev(e, current, prevFieldId) {
if (e.key === 'Backspace' && current.value === '') {
if (prevFieldId) document.getElementById(prevFieldId).focus();
}
}
function submitOtp() {
let code = '';
for (let i = 1; i <= 6; i++) {
code += document.getElementById('otp' + i).value;
}
document.getElementById('code2fa').value = code;
if (code.length === 6) {
document.getElementById('submit-btn').click();
}
}
// Handle pasting 6 digits at once
document.getElementById('otp1').addEventListener('paste', function(e) {
let paste = (e.clipboardData || window.clipboardData).getData('text');
if (paste.length === 6 && /^\d+$/.test(paste)) {
for (let i = 0; i < 6; i++) {
document.getElementById('otp' + (i+1)).value = paste[i];
}
submitOtp();
e.preventDefault();
}
});
</script>
<?php endif; ?>
</div>
</body>
</html>