72) { $errors['password'] = 'Password cannot exceed 72 characters.'; } if (empty($errors)) { $pdo = getDbConnection(); // Consuming the ticket and updating the password happen in one transaction so a // failure between the two can't strand the user: either both take effect, or the // ticket stays unconsumed and the (still valid) reset link can be used again. $pdo->beginTransaction(); try { $userId = consumePasswordResetTicket($pdo, $token); if ($userId === null) { $pdo->rollBack(); $errors['password'] = 'This reset link has already been used or has expired. Please request a new one.'; } else { $hashedPassword = password_hash($password, PASSWORD_DEFAULT); // Bumping session_version invalidates every existing session for this user // (including a stolen one) the next time enforce_session_version() runs. $stmt = $pdo->prepare('UPDATE users SET password = :password, session_version = session_version + 1 WHERE id = :id'); $stmt->execute(['password' => $hashedPassword, 'id' => $userId]); $pdo->commit(); header('Location: login.php?reset=success'); exit; } } catch (Throwable $e) { $pdo->rollBack(); throw $e; } } } $pageTitle = 'Reset Password'; ?>

Link expired

This password reset link is invalid or has expired. Request a new one below.

Request New Link

Choose a new password

Make it something you'll remember.