37048-vm/auth_handler.php
2025-12-10 00:53:11 +00:00

232 lines
8.6 KiB
PHP

<?php
require_once 'includes/session_config.php';
session_start();
require_once 'db/config.php';
require_once 'mail/MailService.php';
// Main router for authentication actions
$action = $_GET['action'] ?? '';
switch ($action) {
case 'send_otp':
handle_send_otp();
break;
case 'verify_otp':
handle_verify_otp();
break;
case 'resend_otp':
handle_resend_otp();
break;
case 'google_callback':
handle_google_callback();
break;
default:
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'درخواست نامعتبر است.'];
header('Location: login.php');
exit;
}
function handle_resend_otp() {
header('Content-Type: application/json');
$pdo = db();
if (!isset($_SESSION['otp_identifier'])) {
echo json_encode(['success' => false, 'message' => 'جلسه شما یافت نشد. لطفا دوباره تلاش کنید.']);
exit;
}
$identifier = $_SESSION['otp_identifier'];
$login_method = filter_var($identifier, FILTER_VALIDATE_EMAIL) ? 'email' : 'phone';
// Generate a new, cryptographically secure 6-digit OTP for resend
$otp = random_int(100000, 999999);
$expires = date('Y-m-d H:i:s', time() + (10 * 60)); // 10 minutes expiry
try {
// A new OTP is inserted. The verification logic automatically picks the latest valid one.
$stmt = $pdo->prepare("INSERT INTO otp_codes (identifier, code, expires_at) VALUES (?, ?, ?)");
$stmt->execute([$identifier, $otp, $expires]);
// FOR TESTING: Always show the OTP for debugging purposes
$_SESSION['show_otp_for_debugging'] = $otp;
echo json_encode(['success' => true, 'otp' => $otp, 'message' => 'کد جدید با موفقیت ارسال شد.']);
exit;
} catch (Throwable $t) {
error_log("OTP Resend Error: " . $t->getMessage());
echo json_encode(['success' => false, 'message' => 'خطایی در سیستم هنگام ارسال مجدد کد رخ داد.']);
exit;
}
}
function handle_send_otp() {
$pdo = db();
$identifier = '';
$login_method = '';
// Simplified and corrected logic
if (isset($_POST['email'])) {
// Trim whitespace from the email input
$identifier = trim($_POST['email']);
if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) {
$login_method = 'email';
} else {
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'لطفا یک ایمیل معتبر وارد کنید.'];
header('Location: login.php');
exit;
}
} elseif (isset($_POST['phone'])) {
// Trim whitespace from the phone input
$identifier = trim($_POST['phone']);
if (preg_match('/^09[0-9]{9}$/', $identifier)) {
$login_method = 'phone';
} else {
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'لطفا یک شماره تلفن معتبر (مانند 09123456789) وارد کنید.'];
header('Location: login.php');
exit;
}
} else {
// Neither email nor phone was submitted
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'ایمیل یا شماره تلفن ارسال نشده است.'];
header('Location: login.php');
exit;
}
// Generate a cryptographically secure 6-digit OTP
$otp = random_int(100000, 999999);
$expires = date('Y-m-d H:i:s', time() + (10 * 60)); // 10 minutes expiry
try {
$stmt = $pdo->prepare("INSERT INTO otp_codes (identifier, code, expires_at) VALUES (?, ?, ?)");
$stmt->execute([$identifier, $otp, $expires]);
$_SESSION['otp_identifier'] = $identifier;
// FOR TESTING: Always show the OTP for debugging purposes for both email and phone
$_SESSION['show_otp_for_debugging'] = $otp;
header('Location: verify.php');
exit;
} catch (Throwable $t) {
error_log("OTP Generation Error: " . $t->getMessage());
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'خطایی در سیستم رخ داد. لطفا دوباره تلاش کنید.'];
header('Location: login.php');
exit;
}
}
function handle_verify_otp() {
if (empty($_POST['otp_code']) || empty($_SESSION['otp_identifier'])) {
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'جلسه شما منقضی شده است. لطفا دوباره تلاش کنید.'];
header('Location: login.php');
exit;
}
$pdo = db();
$identifier = $_SESSION['otp_identifier'];
$otp_code = $_POST['otp_code'];
try {
$stmt = $pdo->prepare("SELECT * FROM otp_codes WHERE identifier = ? AND code = ? AND expires_at > NOW() ORDER BY created_at DESC LIMIT 1");
$stmt->execute([$identifier, $otp_code]);
$otp_entry = $stmt->fetch();
if ($otp_entry) {
// OTP is correct, clean up and log the user in
$delete_stmt = $pdo->prepare("DELETE FROM otp_codes WHERE identifier = ?");
$delete_stmt->execute([$identifier]);
unset($_SESSION['otp_identifier']);
unset($_SESSION['show_otp_for_debugging']);
// Determine if login was via email or phone
$is_email = filter_var($identifier, FILTER_VALIDATE_EMAIL);
$column = $is_email ? 'email' : 'phone';
$user_stmt = $pdo->prepare("SELECT * FROM users WHERE $column = ?");
$user_stmt->execute([$identifier]);
$user = $user_stmt->fetch();
if ($user) {
// User exists, log them in
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = trim($user['first_name'] . ' ' . $user['last_name']);
$_SESSION['is_admin'] = $user['is_admin'];
} else {
// User does not exist, create a new one
$insert_column = $is_email ? 'email' : 'phone';
$insert_stmt = $pdo->prepare("INSERT INTO users ($insert_column, created_at) VALUES (?, NOW())");
$insert_stmt->execute([$identifier]);
$newUserId = $pdo->lastInsertId();
$_SESSION['user_id'] = $newUserId;
$_SESSION['user_name'] = $identifier; // Placeholder name
$_SESSION['is_admin'] = 0;
}
header('Location: profile.php');
exit;
} else {
// Invalid or expired OTP
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'کد تایید نامعتبر یا منقضی شده است.'];
header('Location: verify.php');
exit;
}
} catch (Throwable $t) {
// Reverted to production error handling
error_log("OTP Verification Error: " . $t->getMessage());
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'خطایی در پایگاه داده رخ داد. لطفا دوباره تلاش کنید.'];
header('Location: verify.php');
exit;
}
}
function handle_google_callback() {
if (!isset($_SESSION['google_user_info'])) {
header('Location: login.php?error=google_auth_failed');
exit();
}
$google_user = $_SESSION['google_user_info'];
$email = $google_user['email'];
$fullName = $google_user['name'];
$nameParts = explode(' ', $fullName, 2);
$firstName = $nameParts[0];
$lastName = isset($nameParts[1]) ? $nameParts[1] : '';
// Clear the temporary session data
unset($_SESSION['google_user_info']);
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = trim($user['first_name'] . ' ' . $user['last_name']);
$_SESSION['is_admin'] = $user['is_admin'];
} else {
$insertStmt = $pdo->prepare("INSERT INTO users (first_name, last_name, email, password, is_admin, created_at) VALUES (?, ?, ?, NULL, 0, NOW())");
$insertStmt->execute([$firstName, $lastName, $email]);
$newUserId = $pdo->lastInsertId();
$_SESSION['user_id'] = $newUserId;
$_SESSION['user_name'] = $fullName;
$_SESSION['is_admin'] = 0;
}
header('Location: profile.php');
exit();
} catch (Throwable $t) {
error_log('Database error during Google auth processing: ' . $t->getMessage());
header('Location: login.php?error=db_error');
exit();
}
}
?>