File manager - Edit - /home/webapp69.cm.in.th/u69319090036/Shop/verify_otp.php
Back
<?php // verify_otp.php - Email OTP Verification Page require_once 'db_connect.php'; // Redirect if already logged in if (isLoggedIn()) { header("Location: index.php"); exit(); } $token = trim($_GET['token'] ?? ''); $errorMsg = trim($_GET['error'] ?? ''); $successMsg = trim($_GET['success'] ?? ''); $redirect = $_GET['redirect'] ?? 'index.php'; // ── Validate token exists & not expired ────────────────────────────────────── if (empty($token)) { header("Location: login.php?error=" . urlencode("Invalid or missing OTP session.")); exit(); } $stmt = $pdo->prepare("SELECT * FROM otp_tokens WHERE token = ? AND expires_at > NOW()"); $stmt->execute([$token]); $otpRow = $stmt->fetch(); if (!$otpRow) { header("Location: login.php?tab=otp&error=" . urlencode("OTP session expired or invalid. Please request a new code.")); exit(); } // ── Handle OTP submission ───────────────────────────────────────────────────── if ($_SERVER['REQUEST_METHOD'] === 'POST') { $inputOtp = trim($_POST['otp_code'] ?? ''); if (empty($inputOtp) || !ctype_digit($inputOtp) || strlen($inputOtp) !== 6) { $errorMsg = "Please enter the 6-digit code."; } elseif (!password_verify($inputOtp, $otpRow['otp_code'])) { $errorMsg = "Incorrect code. Please try again."; } else { // OTP correct — log the user in $userStmt = $pdo->prepare("SELECT * FROM users WHERE email = ? AND is_banned = 0"); $userStmt->execute([$otpRow['email']]); $user = $userStmt->fetch(); if (!$user) { $errorMsg = "Account not found or has been banned."; } else { // Delete used OTP $pdo->prepare("DELETE FROM otp_tokens WHERE id = ?")->execute([$otpRow['id']]); // Set session $_SESSION['user_id'] = $user['id']; $_SESSION['username'] = $user['username']; $_SESSION['role'] = $user['role']; header("Location: " . $redirect . "?success=" . urlencode("Signed in with Email OTP successfully!")); exit(); } } } renderHeader(__('otp_page_title')); ?> <div class="max-w-md mx-auto my-10 bg-white p-8 sm:p-10 rounded-2xl shadow-xl border border-gray-100/80"> <div class="text-center mb-8"> <div class="w-14 h-14 bg-orange-50 border border-orange-100 text-orange-600 rounded-2xl flex items-center justify-center mx-auto mb-3"> <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg> </div> <h1 class="text-2xl font-extrabold text-gray-900 tracking-tight"><?php echo __('otp_heading'); ?></h1> <p class="mt-1.5 text-xs text-gray-500"> <?php echo __('otp_sent_to'); ?><br> <strong class="text-gray-800"><?php echo sanitize($otpRow['email']); ?></strong> </p> </div> <?php if (!empty($errorMsg)): ?> <div class="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded-xl mb-5 text-sm font-semibold flex items-center gap-2.5"> <svg class="w-4 h-4 text-red-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg> <span><?php echo sanitize($errorMsg); ?></span> </div> <?php endif; ?> <?php if (!empty($successMsg)): ?> <div class="bg-emerald-50 border border-emerald-200 text-emerald-800 px-4 py-3 rounded-xl mb-5 text-sm font-semibold flex items-center gap-2.5"> <svg class="w-4 h-4 text-emerald-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> <span><?php echo sanitize($successMsg); ?></span> </div> <?php endif; ?> <!-- OTP Form --> <form action="verify_otp.php?token=<?php echo urlencode($token); ?>" method="POST" class="space-y-5"> <div> <label for="otp_code" class="block text-xs font-bold uppercase tracking-wider text-gray-500 mb-3 text-center"> <?php echo __('otp_label'); ?> </label> <!-- 6 individual digit inputs --> <div class="flex gap-2 justify-center" id="otp-boxes"> <?php for ($i = 1; $i <= 6; $i++): ?> <input type="text" id="otp-digit-<?php echo $i; ?>" maxlength="1" inputmode="numeric" class="w-12 h-14 text-center text-2xl font-black border-2 border-gray-200 rounded-xl bg-gray-50 focus:outline-none focus:border-orange-500 focus:bg-white transition-all caret-orange-500" autocomplete="off" oninput="otpInput(this, <?php echo $i; ?>)" onkeydown="otpBack(event, <?php echo $i; ?>)"> <?php endfor; ?> </div> <!-- Hidden combined input sent to server --> <input type="hidden" name="otp_code" id="otp_code_hidden"> </div> <!-- Expiry countdown --> <div class="text-center"> <p class="text-xs text-gray-400"><?php echo __('otp_countdown_pre'); ?> <span id="countdown" class="font-bold text-orange-500">10:00</span></p> </div> <button type="submit" id="submit-btn" onclick="combineOtp()" class="w-full py-3 px-4 bg-gradient-to-r from-orange-500 to-rose-500 text-white font-bold rounded-xl shadow hover:shadow-lg transition-all duration-200 hover:-translate-y-0.5 focus:outline-none text-sm disabled:opacity-50 disabled:cursor-not-allowed"> <?php echo __('otp_btn_verify'); ?> </button> </form> <!-- Resend / Back --> <div class="mt-6 flex items-center justify-between text-xs"> <a href="login.php?tab=otp" class="text-gray-400 hover:text-gray-600 transition-colors"> <?php echo __('otp_use_different'); ?> </a> <a href="login.php?tab=otp" class="font-bold text-orange-500 hover:text-orange-600"> <?php echo __('otp_resend'); ?> </a> </div> </div> <script> function otpInput(el, idx) { el.value = el.value.replace(/\D/g, '').slice(-1); if (el.value && idx < 6) { document.getElementById('otp-digit-' + (idx + 1)).focus(); } } function otpBack(e, idx) { if (e.key === 'Backspace') { const el = document.getElementById('otp-digit-' + idx); if (!el.value && idx > 1) { document.getElementById('otp-digit-' + (idx - 1)).focus(); } } } function combineOtp() { let code = ''; for (let i = 1; i <= 6; i++) { code += document.getElementById('otp-digit-' + i).value; } document.getElementById('otp_code_hidden').value = code; } document.getElementById('otp-digit-1').addEventListener('paste', function(e) { e.preventDefault(); const pasted = (e.clipboardData || window.clipboardData).getData('text').replace(/\D/g, '').slice(0, 6); for (let i = 0; i < pasted.length; i++) { const box = document.getElementById('otp-digit-' + (i + 1)); if (box) box.value = pasted[i]; } const last = Math.min(pasted.length, 6); const nextBox = document.getElementById('otp-digit-' + last); if (nextBox) nextBox.focus(); }); (function() { const expireMs = <?php echo OTP_EXPIRE_MIN; ?> * 60 * 1000; const start = Date.now(); const el = document.getElementById('countdown'); const btnText = '<?php echo addslashes(__('otp_btn_expired')); ?>'; if (!el) return; const interval = setInterval(function() { const remaining = expireMs - (Date.now() - start); if (remaining <= 0) { clearInterval(interval); el.textContent = '00:00'; el.classList.remove('text-orange-500'); el.classList.add('text-red-500'); document.getElementById('submit-btn').disabled = true; document.getElementById('submit-btn').textContent = btnText; return; } const m = String(Math.floor(remaining / 60000)).padStart(2, '0'); const s = String(Math.floor((remaining % 60000) / 1000)).padStart(2, '0'); el.textContent = m + ':' + s; if (remaining < 60000) { el.classList.remove('text-orange-500'); el.classList.add('text-red-500'); } }, 1000); })(); document.getElementById('otp-digit-1').focus(); </script> <?php renderFooter(); ?>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.23 |
proxy
|
phpinfo
|
Settings