Added full user authentication system: register/login with validation, bcrypt, reCAPTCHA integration, session handling, and new landing page with animated form switcher.
This commit is contained in:
4
db.php
4
db.php
@@ -1,13 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
function getConnection() {
|
function getConnection() {
|
||||||
$host = getenv('DB_HOST') ?: 'localhost';
|
$host = getenv('DB_HOST') ?: 'localhost';
|
||||||
$port = 3308;
|
$port = 3308; // ✅ using custom port
|
||||||
$db = getenv('DB_NAME') ?: 'ai_email';
|
$db = getenv('DB_NAME') ?: 'ai_email';
|
||||||
$user = getenv('DB_USER') ?: 'root';
|
$user = getenv('DB_USER') ?: 'root';
|
||||||
$pass = getenv('DB_PASS') ?: '';
|
$pass = getenv('DB_PASS') ?: '';
|
||||||
$charset = 'utf8mb4';
|
$charset = 'utf8mb4';
|
||||||
|
|
||||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
$dsn = "mysql:host=$host;port=$port;dbname=$db;charset=$charset";
|
||||||
$options = [
|
$options = [
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
|
|||||||
10
home.php
10
home.php
@@ -1,4 +1,12 @@
|
|||||||
<?php include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/header.php');
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: /landing.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/header.php');
|
||||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/db.php');
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/db.php');
|
||||||
$conn = getConnection();?>
|
$conn = getConnection();?>
|
||||||
|
|
||||||
|
|||||||
@@ -151,3 +151,29 @@ button + button {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-box {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #fff;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.auth-box.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.auth-box h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.auth-box .error {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.auth-box input, .auth-box button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
@@ -5,13 +5,23 @@ require_once($_SERVER['DOCUMENT_ROOT'] . '/db.php');
|
|||||||
$errors = [];
|
$errors = [];
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$user = trim($_POST['user'] ?? '');
|
$user = trim($_POST['login_email'] ?? '');
|
||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['login_password'] ?? '';
|
||||||
|
$captcha = $_POST['g-recaptcha-response'] ?? '';
|
||||||
|
|
||||||
if (empty($user) || empty($password)) {
|
if (empty($user) || empty($password)) {
|
||||||
$errors[] = "All fields are required.";
|
$errors[] = "All fields are required.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAPTCHA validation
|
||||||
|
$captcha_secret = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'; // Google's test secret key
|
||||||
|
$captcha_response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$captcha_secret}&response={$captcha}");
|
||||||
|
$captcha_data = json_decode($captcha_response);
|
||||||
|
|
||||||
|
if (!$captcha_data->success) {
|
||||||
|
$errors[] = "CAPTCHA verification failed.";
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($errors)) {
|
if (empty($errors)) {
|
||||||
$conn = getConnection();
|
$conn = getConnection();
|
||||||
$stmt = $conn->prepare("SELECT id, password, uniqueid FROM users WHERE email = :user OR username = :user");
|
$stmt = $conn->prepare("SELECT id, password, uniqueid FROM users WHERE email = :user OR username = :user");
|
||||||
@@ -27,17 +37,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$errors[] = "Invalid credentials.";
|
$errors[] = "Invalid credentials.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_SESSION['login_error'] = implode("<br>", $errors);
|
||||||
|
header("Location: /landing.php");
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Basic form UI -->
|
|
||||||
<h2>Login</h2>
|
|
||||||
<form method="POST">
|
|
||||||
<input name="user" placeholder="Username or Email" required><br>
|
|
||||||
<input name="password" type="password" placeholder="Password" required><br>
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<?php if (!empty($errors)): ?>
|
|
||||||
<ul><?php foreach ($errors as $e) echo "<li>$e</li>"; ?></ul>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|||||||
@@ -7,13 +7,20 @@ $errors = [];
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$username = trim($_POST['username'] ?? '');
|
$username = trim($_POST['username'] ?? '');
|
||||||
$email = trim($_POST['email'] ?? '');
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
$confirm_email = trim($_POST['confirm_email'] ?? '');
|
||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['password'] ?? '';
|
||||||
|
$age = (int) ($_POST['age'] ?? 0);
|
||||||
|
$captcha = $_POST['g-recaptcha-response'] ?? '';
|
||||||
|
|
||||||
// Validate inputs
|
// Basic validation
|
||||||
if (empty($username) || empty($email) || empty($password)) {
|
if (empty($username) || empty($email) || empty($confirm_email) || empty($password) || empty($age)) {
|
||||||
$errors[] = "All fields are required.";
|
$errors[] = "All fields are required.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($email !== $confirm_email) {
|
||||||
|
$errors[] = "Emails do not match.";
|
||||||
|
}
|
||||||
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
$errors[] = "Invalid email format.";
|
$errors[] = "Invalid email format.";
|
||||||
}
|
}
|
||||||
@@ -22,10 +29,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$errors[] = "Password must be at least 6 characters.";
|
$errors[] = "Password must be at least 6 characters.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($age < 16) {
|
||||||
|
$errors[] = "You must be at least 16 years old to register.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAPTCHA validation
|
||||||
|
$captcha_secret = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'; // Google's test secret key
|
||||||
|
$captcha_response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$captcha_secret}&response={$captcha}");
|
||||||
|
$captcha_data = json_decode($captcha_response);
|
||||||
|
|
||||||
|
if (!$captcha_data->success) {
|
||||||
|
$errors[] = "CAPTCHA verification failed.";
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($errors)) {
|
if (empty($errors)) {
|
||||||
$conn = getConnection();
|
$conn = getConnection();
|
||||||
|
|
||||||
// Check if email or username already exists
|
// Check for existing user
|
||||||
$stmt = $conn->prepare("SELECT id FROM users WHERE email = :email OR username = :username");
|
$stmt = $conn->prepare("SELECT id FROM users WHERE email = :email OR username = :username");
|
||||||
$stmt->execute(['email' => $email, 'username' => $username]);
|
$stmt->execute(['email' => $email, 'username' => $username]);
|
||||||
|
|
||||||
@@ -33,7 +53,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$errors[] = "Email or username already in use.";
|
$errors[] = "Email or username already in use.";
|
||||||
} else {
|
} else {
|
||||||
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
|
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
|
||||||
$uniqueId = bin2hex(random_bytes(16)); // session ID
|
$uniqueId = bin2hex(random_bytes(16));
|
||||||
|
|
||||||
$insert = $conn->prepare("INSERT INTO users (username, email, password, uniqueid) VALUES (:username, :email, :password, :uniqueid)");
|
$insert = $conn->prepare("INSERT INTO users (username, email, password, uniqueid) VALUES (:username, :email, :password, :uniqueid)");
|
||||||
$insert->execute([
|
$insert->execute([
|
||||||
@@ -50,18 +70,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_SESSION['register_error'] = implode("<br>", $errors);
|
||||||
|
header("Location: /landing.php");
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Basic form UI -->
|
|
||||||
<h2>Register</h2>
|
|
||||||
<form method="POST">
|
|
||||||
<input name="username" placeholder="Username" required><br>
|
|
||||||
<input name="email" type="email" placeholder="Email" required><br>
|
|
||||||
<input name="password" type="password" placeholder="Password" required><br>
|
|
||||||
<button type="submit">Register</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<?php if (!empty($errors)): ?>
|
|
||||||
<ul><?php foreach ($errors as $e) echo "<li>$e</li>"; ?></ul>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|||||||
101
landing.php
101
landing.php
@@ -1,28 +1,83 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/db.php');
|
||||||
if (isset($_SESSION['user_id'])) {
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/config.php');
|
||||||
// Already logged in, redirect to email generator
|
include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/header.php');
|
||||||
header("Location: /home.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/header.php');
|
|
||||||
?>
|
?>
|
||||||
<body>
|
|
||||||
<div class="container" style="text-align: center;">
|
|
||||||
<h1>Welcome to AI Email Generator</h1>
|
|
||||||
<p style="margin-bottom: 20px;">Craft professional emails in seconds. Please login or register to get started.</p>
|
|
||||||
|
|
||||||
<div style="display: flex; justify-content: center; gap: 20px;">
|
|
||||||
<a href="/inc/php/login.php"><button style="padding: 10px 20px;">Login</button></a>
|
|
||||||
<a href="/inc/php/register.php"><button style="padding: 10px 20px;">Register</button></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 30px;">
|
<link rel="stylesheet" href="/inc/css/style.css">
|
||||||
<button id="darkModeBtn">Toggle Dark Mode</button>
|
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||||
</div>
|
|
||||||
|
<body>
|
||||||
|
<div class="container" id="auth-container">
|
||||||
|
<h1>AI Email Generator</h1>
|
||||||
|
|
||||||
|
<!-- Login Form -->
|
||||||
|
<div id="login-box" class="auth-box">
|
||||||
|
<form action="/inc/php/login.php" method="POST">
|
||||||
|
<h2>Login</h2>
|
||||||
|
|
||||||
|
<?php if (isset($_SESSION['login_error'])): ?>
|
||||||
|
<p class="error"><?= $_SESSION['login_error']; unset($_SESSION['login_error']); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<label for="login_email">Email or Username</label>
|
||||||
|
<input type="text" name="login_email" required>
|
||||||
|
|
||||||
|
<label for="login_password">Password</label>
|
||||||
|
<input type="password" name="login_password" required>
|
||||||
|
|
||||||
|
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
|
||||||
|
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
|
||||||
|
<p>Don't have an account? <a href="#" onclick="showRegister()">Register here</a></p>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/inc/js/theme.js"></script>
|
<!-- Register Form -->
|
||||||
|
<div id="register-box" class="auth-box hidden">
|
||||||
|
<form action="/inc/php/register.php" method="POST">
|
||||||
|
<h2>Register</h2>
|
||||||
|
|
||||||
|
<?php if (isset($_SESSION['register_error'])): ?>
|
||||||
|
<p class="error"><?= $_SESSION['register_error']; unset($_SESSION['register_error']); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" name="username" required>
|
||||||
|
|
||||||
|
<label for="email">Email</label>
|
||||||
|
<input type="email" name="email" required>
|
||||||
|
|
||||||
|
<label for="confirm_email">Confirm Email</label>
|
||||||
|
<input type="email" name="confirm_email" required>
|
||||||
|
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="password" required>
|
||||||
|
|
||||||
|
<label for="age">Age</label>
|
||||||
|
<input type="number" name="age" min="16" required>
|
||||||
|
|
||||||
|
<div class="g-recaptcha" data-sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"></div>
|
||||||
|
|
||||||
|
<button type="submit">Register</button>
|
||||||
|
|
||||||
|
<p>Already have an account? <a href="#" onclick="showLogin()">Login here</a></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showRegister() {
|
||||||
|
document.getElementById("login-box").classList.add("hidden");
|
||||||
|
document.getElementById("register-box").classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLogin() {
|
||||||
|
document.getElementById("register-box").classList.add("hidden");
|
||||||
|
document.getElementById("login-box").classList.remove("hidden");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<?php include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/footer.php'); ?>
|
<?php include($_SERVER['DOCUMENT_ROOT'] . '/inc/php/footer.php'); ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user