Password Generator with Save Option built with HTML, CSS, JavaScript, PHP, and MySQL

πŸ” Project Introduction: Password Generator with Save Option

This project is a comprehensive Password Generator and Manager that helps users create strong, secure passwords and store them safely. Users can customize password complexity, generate multiple passwords at once, and save them with descriptions for different accounts or services.

The Problem it Solves:
Creating strong, unique passwords for every online account is challenging, and remembering them is even harder. Many people reuse passwords across multiple sites, which is a major security risk. This tool generates cryptographically strong random passwords and provides a secure way to store them, eliminating the need to remember complex passwords.

Key Features:

  • Password Generation:
  • Customizable length (4-64 characters)
  • Include/exclude uppercase letters
  • Include/exclude lowercase letters
  • Include/exclude numbers
  • Include/exclude special characters
  • Avoid ambiguous characters (similar looking characters)
  • Generate multiple passwords at once (1-20)
  • Password strength indicator
  • Copy to clipboard functionality
  • Regenerate button
  • Password Management:
  • Save passwords with title/description
  • Categorize passwords (Web, Email, Social, Banking, etc.)
  • Store associated username/email
  • Add notes for each password
  • View saved passwords (with show/hide toggle)
  • Edit saved passwords
  • Delete passwords
  • Search/filter saved passwords
  • Export passwords (encrypted CSV)
  • Password strength analysis
  • Security Features:
  • Passwords are encrypted before storing in database
  • Master password protection
  • Session-based authentication
  • HTTPS ready
  • No plain text storage
  • Automatic logout after inactivity
  • Password strength meter

Technology Stack:

  • Frontend: HTML5, CSS3, JavaScript (ES6+)
  • Backend: PHP (Object-Oriented with PDO)
  • Database: MySQL with encryption
  • Encryption: OpenSSL (AES-256-CBC)
  • Additional Libraries:
  • Clipboard.js (copy to clipboard)
  • Zxcvbn (password strength estimation)

πŸ“ Project File Structure

password-generator/
β”‚
β”œβ”€β”€ index.php                 # Password generator interface
β”œβ”€β”€ login.php                 # User login
β”œβ”€β”€ register.php              # User registration
β”œβ”€β”€ dashboard.php             # Saved passwords dashboard
β”œβ”€β”€ save-password.php         # Save generated password
β”œβ”€β”€ edit-password.php         # Edit saved password
β”œβ”€β”€ delete-password.php       # Delete password
β”œβ”€β”€ view-password.php         # View single password
β”œβ”€β”€ export-passwords.php      # Export passwords
β”œβ”€β”€ logout.php                # Logout script
β”œβ”€β”€ profile.php               # User profile settings
β”‚
β”œβ”€β”€ api/                       # AJAX endpoints
β”‚   β”œβ”€β”€ generate-password.php  # Generate password via AJAX
β”‚   β”œβ”€β”€ check-strength.php     # Check password strength
β”‚   └── search-passwords.php   # Search passwords
β”‚
β”œβ”€β”€ includes/                   # Backend logic
β”‚   β”œβ”€β”€ config.php              # Database connection
β”‚   β”œβ”€β”€ functions.php           # Helper functions
β”‚   β”œβ”€β”€ auth.php                # Authentication functions
β”‚   β”œβ”€β”€ encryption.php          # Encryption/decryption functions
β”‚   └── session.php             # Session management
β”‚
β”œβ”€β”€ assets/                    # Static assets
β”‚   β”œβ”€β”€ css/
β”‚   β”‚   β”œβ”€β”€ style.css          # Main styles
β”‚   β”‚   └── dashboard.css       # Dashboard styles
β”‚   β”œβ”€β”€ js/
β”‚   β”‚   β”œβ”€β”€ generator.js        # Password generation logic
β”‚   β”‚   β”œβ”€β”€ strength-meter.js   # Password strength meter
β”‚   β”‚   └── clipboard.js        # Copy to clipboard
β”‚   └── images/
β”‚       └── favicon.ico
β”‚
β”œβ”€β”€ vendor/                    # Third-party libraries
β”‚   └── clipboard.js/           # Clipboard library
β”‚
└── database/
└── password_generator.sql  # Database dump

πŸ—„οΈ Database Setup (database/password_generator.sql)

Create a database named password_manager and run this SQL.

-- phpMyAdmin SQL Dump
-- Database: `password_manager`
CREATE DATABASE IF NOT EXISTS `password_manager`;
USE `password_manager`;
-- --------------------------------------------------------
-- Table structure for table `users`
-- --------------------------------------------------------
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL,
`password` varchar(255) NOT NULL,
`full_name` varchar(100) NOT NULL,
`master_key` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`last_login` timestamp NULL DEFAULT NULL,
`preferences` text DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Default user (password: password123) - you need to hash this
INSERT INTO `users` (`username`, `email`, `password`, `full_name`) VALUES
('demo', '[email protected]', '$2y$10$YourHashedPasswordHere', 'Demo User');
-- --------------------------------------------------------
-- Table structure for table `categories`
-- --------------------------------------------------------
CREATE TABLE `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`color` varchar(20) DEFAULT '#3498db',
`icon` varchar(50) DEFAULT 'πŸ”',
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `categories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Default categories for each user (will be inserted after user creation)
-- Sample data for demo user (assuming user_id = 1)
INSERT INTO `categories` (`user_id`, `name`, `color`, `icon`) VALUES
(1, 'Websites', '#3498db', '🌐'),
(1, 'Email', '#e74c3c', 'πŸ“§'),
(1, 'Social Media', '#9b59b6', 'πŸ“±'),
(1, 'Banking', '#27ae60', 'πŸ’°'),
(1, 'Work', '#f39c12', 'πŸ’Ό'),
(1, 'Other', '#95a5a6', 'πŸ“');
-- --------------------------------------------------------
-- Table structure for table `passwords`
-- --------------------------------------------------------
CREATE TABLE `passwords` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`category_id` int(11) DEFAULT NULL,
`title` varchar(200) NOT NULL,
`username` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`encrypted_password` text NOT NULL,
`url` varchar(500) DEFAULT NULL,
`notes` text DEFAULT NULL,
`strength` enum('weak','medium','strong','very_strong') DEFAULT 'medium',
`favorite` tinyint(1) DEFAULT 0,
`last_used` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `category_id` (`category_id`),
KEY `favorite` (`favorite`),
FULLTEXT KEY `search` (`title`,`username`,`email`,`url`,`notes`),
CONSTRAINT `passwords_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `passwords_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
-- Table structure for table `password_history`
-- --------------------------------------------------------
CREATE TABLE `password_history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`password_id` int(11) NOT NULL,
`old_password` text NOT NULL,
`changed_at` timestamp NOT NULL DEFAULT current_timestamp(),
`changed_by_ip` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `password_id` (`password_id`),
CONSTRAINT `password_history_ibfk_1` FOREIGN KEY (`password_id`) REFERENCES `passwords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
-- Table structure for table `shared_passwords`
-- --------------------------------------------------------
CREATE TABLE `shared_passwords` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`password_id` int(11) NOT NULL,
`shared_with_user_id` int(11) NOT NULL,
`shared_by_user_id` int(11) NOT NULL,
`permission` enum('view','edit') DEFAULT 'view',
`shared_at` timestamp NOT NULL DEFAULT current_timestamp(),
`expires_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `password_id` (`password_id`),
KEY `shared_with_user_id` (`shared_with_user_id`),
KEY `shared_by_user_id` (`shared_by_user_id`),
CONSTRAINT `shared_passwords_ibfk_1` FOREIGN KEY (`password_id`) REFERENCES `passwords` (`id`) ON DELETE CASCADE,
CONSTRAINT `shared_passwords_ibfk_2` FOREIGN KEY (`shared_with_user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `shared_passwords_ibfk_3` FOREIGN KEY (`shared_by_user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
-- Table structure for table `two_factor`
-- --------------------------------------------------------
CREATE TABLE `two_factor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`secret` varchar(255) NOT NULL,
`enabled` tinyint(1) DEFAULT 0,
`backup_codes` text DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`),
CONSTRAINT `two_factor_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
COMMIT;

πŸ’» Core PHP Files

1. Database Configuration (includes/config.php)

<?php
// Database configuration
define('DB_HOST', 'localhost');
define('DB_NAME', 'password_manager');
define('DB_USER', 'root');
define('DB_PASS', '');
// Encryption configuration
define('ENCRYPTION_METHOD', 'AES-256-CBC');
define('ENCRYPTION_KEY', 'YourSecretEncryptionKeyHere123!'); // Change this in production
define('ENCRYPTION_IV', '1234567890123456'); // 16 bytes for AES-256-CBC
// Site configuration
define('SITE_NAME', 'Password Generator & Manager');
define('SITE_URL', 'http://localhost/password-generator/');
define('SESSION_TIMEOUT', 1800); // 30 minutes
try {
$pdo = new PDO(
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
DB_USER,
DB_PASS,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]
);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
// Start session if not started
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Check session timeout
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > SESSION_TIMEOUT)) {
session_unset();
session_destroy();
header("Location: login.php?timeout=1");
exit;
}
$_SESSION['last_activity'] = time();
// Helper functions
function sanitize($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
function redirect($url) {
header("Location: $url");
exit;
}
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
function generateCSRFToken() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verifyCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
function formatDate($date, $format = 'M d, Y') {
return date($format, strtotime($date));
}
function timeAgo($timestamp) {
$time_ago = strtotime($timestamp);
$current_time = time();
$time_difference = $current_time - $time_ago;
$seconds = $time_difference;
$minutes = round($seconds / 60);
$hours = round($seconds / 3600);
$days = round($seconds / 86400);
$weeks = round($seconds / 604800);
$months = round($seconds / 2629440);
$years = round($seconds / 31553280);
if ($seconds <= 60) {
return "Just now";
} else if ($minutes <= 60) {
return ($minutes == 1) ? "1 minute ago" : "$minutes minutes ago";
} else if ($hours <= 24) {
return ($hours == 1) ? "1 hour ago" : "$hours hours ago";
} else if ($days <= 7) {
return ($days == 1) ? "yesterday" : "$days days ago";
} else if ($weeks <= 4.3) {
return ($weeks == 1) ? "1 week ago" : "$weeks weeks ago";
} else if ($months <= 12) {
return ($months == 1) ? "1 month ago" : "$months months ago";
} else {
return ($years == 1) ? "1 year ago" : "$years years ago";
}
}
?>

2. Encryption Functions (includes/encryption.php)

<?php
/**
* Encryption and decryption functions for passwords
* Uses OpenSSL with AES-256-CBC
*/
function encryptPassword($password) {
$key = hash('sha256', ENCRYPTION_KEY, true);
$iv = ENCRYPTION_IV;
$encrypted = openssl_encrypt(
$password,
ENCRYPTION_METHOD,
$key,
OPENSSL_RAW_DATA,
$iv
);
return base64_encode($encrypted);
}
function decryptPassword($encryptedPassword) {
$key = hash('sha256', ENCRYPTION_KEY, true);
$iv = ENCRYPTION_IV;
$decrypted = openssl_decrypt(
base64_decode($encryptedPassword),
ENCRYPTION_METHOD,
$key,
OPENSSL_RAW_DATA,
$iv
);
return $decrypted;
}
function generateSecurePassword($length = 12, $options = []) {
$uppercase = $options['uppercase'] ?? true;
$lowercase = $options['lowercase'] ?? true;
$numbers = $options['numbers'] ?? true;
$symbols = $options['symbols'] ?? true;
$avoidAmbiguous = $options['avoid_ambiguous'] ?? false;
$upperChars = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // Removed I and O if ambiguous
$lowerChars = 'abcdefghijkmnopqrstuvwxyz'; // Removed l if ambiguous
$numberChars = '23456789'; // Removed 0 and 1 if ambiguous
$symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?';
if (!$avoidAmbiguous) {
$upperChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$lowerChars = 'abcdefghijklmnopqrstuvwxyz';
$numberChars = '0123456789';
}
$chars = '';
if ($uppercase) $chars .= $upperChars;
if ($lowercase) $chars .= $lowerChars;
if ($numbers) $chars .= $numberChars;
if ($symbols) $chars .= $symbolChars;
if (empty($chars)) {
$chars = $lowerChars . $numberChars; // Default fallback
}
$password = '';
$charsLength = strlen($chars);
for ($i = 0; $i < $length; $i++) {
$password .= $chars[random_int(0, $charsLength - 1)];
}
return $password;
}
function calculatePasswordStrength($password) {
$score = 0;
$length = strlen($password);
// Length checks
if ($length >= 8) $score += 1;
if ($length >= 12) $score += 1;
if ($length >= 16) $score += 1;
// Character variety
if (preg_match('/[A-Z]/', $password)) $score += 1;
if (preg_match('/[a-z]/', $password)) $score += 1;
if (preg_match('/[0-9]/', $password)) $score += 1;
if (preg_match('/[^A-Za-z0-9]/', $password)) $score += 1;
// Complexity
if (preg_match('/[A-Z]/', $password) && preg_match('/[a-z]/', $password) && 
preg_match('/[0-9]/', $password) && preg_match('/[^A-Za-z0-9]/', $password)) {
$score += 1;
}
// Determine strength
if ($score <= 3) return ['text' => 'Weak', 'class' => 'weak', 'score' => $score];
if ($score <= 5) return ['text' => 'Medium', 'class' => 'medium', 'score' => $score];
if ($score <= 7) return ['text' => 'Strong', 'class' => 'strong', 'score' => $score];
return ['text' => 'Very Strong', 'class' => 'very-strong', 'score' => $score];
}
?>

3. Authentication Functions (includes/auth.php)

<?php
require_once 'config.php';
require_once 'encryption.php';
class Auth {
public static function login($username, $password) {
global $pdo;
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? OR email = ?");
$stmt->execute([$username, $username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['user_name'] = $user['full_name'];
$_SESSION['user_email'] = $user['email'];
// Update last login
$pdo->prepare("UPDATE users SET last_login = NOW() WHERE id = ?")->execute([$user['id']]);
// Create default categories if not exist
self::createDefaultCategories($user['id']);
return true;
}
return false;
}
public static function register($data) {
global $pdo;
// Check if username exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$data['username']]);
if ($stmt->fetch()) {
return ['success' => false, 'message' => 'Username already taken'];
}
// Check if email exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
$stmt->execute([$data['email']]);
if ($stmt->fetch()) {
return ['success' => false, 'message' => 'Email already registered'];
}
// Hash password
$hashedPassword = password_hash($data['password'], PASSWORD_DEFAULT);
// Generate master key (for future encryption features)
$masterKey = bin2hex(random_bytes(32));
// Insert user
$stmt = $pdo->prepare("
INSERT INTO users (username, email, password, full_name, master_key) 
VALUES (?, ?, ?, ?, ?)
");
$success = $stmt->execute([
$data['username'],
$data['email'],
$hashedPassword,
$data['full_name'],
$masterKey
]);
if ($success) {
$userId = $pdo->lastInsertId();
self::createDefaultCategories($userId);
return ['success' => true, 'message' => 'Registration successful! Please login.'];
}
return ['success' => false, 'message' => 'Registration failed. Please try again.'];
}
private static function createDefaultCategories($userId) {
global $pdo;
$categories = [
['Websites', '#3498db', '🌐'],
['Email', '#e74c3c', 'πŸ“§'],
['Social Media', '#9b59b6', 'πŸ“±'],
['Banking', '#27ae60', 'πŸ’°'],
['Work', '#f39c12', 'πŸ’Ό'],
['Other', '#95a5a6', 'πŸ“']
];
$stmt = $pdo->prepare("
INSERT INTO categories (user_id, name, color, icon) 
VALUES (?, ?, ?, ?)
");
foreach ($categories as $cat) {
$stmt->execute([$userId, $cat[0], $cat[1], $cat[2]]);
}
}
public static function logout() {
session_destroy();
redirect('login.php');
}
public static function checkLogin() {
if (!isset($_SESSION['user_id'])) {
redirect('login.php');
}
}
public static function getCurrentUser() {
global $pdo;
if (!isset($_SESSION['user_id'])) {
return null;
}
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
return $stmt->fetch();
}
}
?>

4. Password Generator Interface (index.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
$isLoggedIn = isLoggedIn();
$csrf_token = generateCSRFToken();
// Get categories for logged in user
$categories = [];
if ($isLoggedIn) {
$stmt = $pdo->prepare("SELECT * FROM categories WHERE user_id = ? ORDER BY name");
$stmt->execute([$_SESSION['user_id']]);
$categories = $stmt->fetchAll();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo SITE_NAME; ?> - Secure Password Generator</title>
<meta name="description" content="Generate strong, secure passwords and save them safely">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/dashboard.css">
</head>
<body>
<!-- Header -->
<header class="site-header">
<div class="container">
<div class="logo">
<a href="index.php">
<h1>πŸ” <?php echo SITE_NAME; ?></h1>
</a>
</div>
<nav class="main-nav">
<ul>
<li><a href="index.php" class="active">Generator</a></li>
<?php if ($isLoggedIn): ?>
<li><a href="dashboard.php">My Passwords</a></li>
<li><a href="profile.php">Profile</a></li>
<li><a href="logout.php">Logout</a></li>
<?php else: ?>
<li><a href="login.php">Login</a></li>
<li><a href="register.php">Register</a></li>
<?php endif; ?>
</ul>
</nav>
</div>
</header>
<!-- Main Content -->
<main class="container">
<div class="generator-container">
<h1 class="page-title">Secure Password Generator</h1>
<p class="page-description">Generate strong, random passwords that are difficult to crack. Customize the options below.</p>
<!-- Password Generator Form -->
<div class="generator-card">
<div class="generated-password-area">
<div class="password-display">
<input type="text" id="generated-password" readonly value="Click Generate to create password">
<button class="btn-icon" id="copy-password" title="Copy to clipboard">πŸ“‹</button>
<button class="btn-icon" id="regenerate-password" title="Generate new">πŸ”„</button>
</div>
<div class="strength-meter" id="strength-meter">
<div class="strength-bar"></div>
<span class="strength-text">Password Strength: <span id="strength-label">-</span></span>
</div>
</div>
<form id="generator-form" class="generator-form">
<input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>">
<div class="form-group">
<label for="password-length">Password Length: <span id="length-value">12</span></label>
<input type="range" id="password-length" name="length" min="4" max="64" value="12">
</div>
<div class="options-grid">
<div class="option-item">
<label class="checkbox-label">
<input type="checkbox" id="include-uppercase" checked>
<span>Include Uppercase (A-Z)</span>
</label>
</div>
<div class="option-item">
<label class="checkbox-label">
<input type="checkbox" id="include-lowercase" checked>
<span>Include Lowercase (a-z)</span>
</label>
</div>
<div class="option-item">
<label class="checkbox-label">
<input type="checkbox" id="include-numbers" checked>
<span>Include Numbers (0-9)</span>
</label>
</div>
<div class="option-item">
<label class="checkbox-label">
<input type="checkbox" id="include-symbols" checked>
<span>Include Symbols (!@#$%)</span>
</label>
</div>
<div class="option-item">
<label class="checkbox-label">
<input type="checkbox" id="avoid-ambiguous">
<span>Avoid Ambiguous Characters (Il1O0)</span>
</label>
</div>
</div>
<div class="form-group">
<label for="quantity">Number of Passwords: <span id="quantity-value">1</span></label>
<input type="range" id="quantity" name="quantity" min="1" max="20" value="1">
</div>
<button type="button" id="generate-btn" class="btn btn-large btn-primary">Generate Passwords</button>
</form>
<!-- Multiple Passwords Display -->
<div id="passwords-list" class="passwords-list" style="display: none;">
<h3>Generated Passwords</h3>
<div class="passwords-grid"></div>
</div>
</div>
<?php if ($isLoggedIn): ?>
<!-- Save Password Section (shown when logged in) -->
<div id="save-section" class="save-card" style="display: none;">
<h2>Save Password</h2>
<form id="save-form" action="save-password.php" method="POST" class="save-form">
<input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>">
<input type="hidden" name="password" id="save-password">
<div class="form-row">
<div class="form-group col-md-6">
<label for="save-title">Title *</label>
<input type="text" id="save-title" name="title" required 
placeholder="e.g., Gmail, Facebook, Bank Account">
</div>
<div class="form-group col-md-6">
<label for="save-category">Category</label>
<select id="save-category" name="category_id">
<option value="">Select Category</option>
<?php foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>">
<?php echo $category['icon'] . ' ' . $category['name']; ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="save-username">Username</label>
<input type="text" id="save-username" name="username" 
placeholder="Username">
</div>
<div class="form-group col-md-6">
<label for="save-email">Email</label>
<input type="email" id="save-email" name="email" 
placeholder="Email address">
</div>
</div>
<div class="form-group">
<label for="save-url">Website/URL</label>
<input type="url" id="save-url" name="url" 
placeholder="https://example.com">
</div>
<div class="form-group">
<label for="save-notes">Notes</label>
<textarea id="save-notes" name="notes" rows="3" 
placeholder="Additional notes about this password"></textarea>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="save-favorite" name="favorite" value="1">
Mark as favorite
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-success">Save Password</button>
<button type="button" class="btn" id="cancel-save">Cancel</button>
</div>
</form>
</div>
<?php else: ?>
<!-- Login Prompt -->
<div class="login-prompt">
<p>Want to save your passwords? <a href="login.php">Login</a> or <a href="register.php">Register</a></p>
</div>
<?php endif; ?>
<!-- Information Section -->
<div class="info-section">
<h2>Why Use Strong Passwords?</h2>
<div class="info-grid">
<div class="info-card">
<h3>πŸ”’ Security</h3>
<p>Strong passwords protect your accounts from unauthorized access and hacking attempts.</p>
</div>
<div class="info-card">
<h3>🎲 Randomness</h3>
<p>Random passwords are harder to guess than those based on personal information.</p>
</div>
<div class="info-card">
<h3>πŸ“¦ Storage</h3>
<p>Save and organize all your passwords securely in one place.</p>
</div>
<div class="info-card">
<h3>πŸ”„ Unique</h3>
<p>Use different passwords for each account to prevent chain reactions if one is compromised.</p>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="site-footer">
<div class="container">
<p>&copy; 2024 <?php echo SITE_NAME; ?>. All rights reserved.</p>
<p class="security-note">Your passwords are encrypted before storage.</p>
</div>
</footer>
<!-- Scripts -->
<script src="assets/js/generator.js"></script>
<script src="assets/js/strength-meter.js"></script>
<?php if ($isLoggedIn): ?>
<script>
// Handle save button click from generated passwords
document.addEventListener('click', function(e) {
if (e.target.classList.contains('save-generated')) {
const password = e.target.dataset.password;
document.getElementById('save-password').value = password;
document.getElementById('save-section').style.display = 'block';
document.getElementById('save-section').scrollIntoView({ behavior: 'smooth' });
}
});
document.getElementById('cancel-save').addEventListener('click', function() {
document.getElementById('save-section').style.display = 'none';
document.getElementById('save-form').reset();
});
</script>
<?php endif; ?>
</body>
</html>

5. Password Generator JavaScript (assets/js/generator.js)

// Password Generator JavaScript
document.addEventListener('DOMContentLoaded', function() {
const generateBtn = document.getElementById('generate-btn');
const passwordLength = document.getElementById('password-length');
const lengthValue = document.getElementById('length-value');
const quantity = document.getElementById('quantity');
const quantityValue = document.getElementById('quantity-value');
const generatedPassword = document.getElementById('generated-password');
const regenerateBtn = document.getElementById('regenerate-password');
const copyBtn = document.getElementById('copy-password');
const passwordsList = document.getElementById('passwords-list');
const strengthMeter = document.getElementById('strength-meter');
const strengthBar = document.querySelector('.strength-bar');
const strengthLabel = document.getElementById('strength-label');
// Update length display
passwordLength.addEventListener('input', function() {
lengthValue.textContent = this.value;
});
// Update quantity display
quantity.addEventListener('input', function() {
quantityValue.textContent = this.value;
});
// Generate password on button click
generateBtn.addEventListener('click', generatePasswords);
// Regenerate single password
regenerateBtn.addEventListener('click', function() {
const options = getOptions();
const password = generatePassword(options.length, options);
generatedPassword.value = password;
updateStrengthMeter(password);
});
// Copy to clipboard
copyBtn.addEventListener('click', function() {
generatedPassword.select();
document.execCommand('copy');
// Show feedback
const originalText = copyBtn.textContent;
copyBtn.textContent = 'βœ“';
setTimeout(() => {
copyBtn.textContent = originalText;
}, 1500);
});
function getOptions() {
return {
length: parseInt(passwordLength.value),
uppercase: document.getElementById('include-uppercase').checked,
lowercase: document.getElementById('include-lowercase').checked,
numbers: document.getElementById('include-numbers').checked,
symbols: document.getElementById('include-symbols').checked,
avoidAmbiguous: document.getElementById('avoid-ambiguous').checked
};
}
function generatePassword(length, options) {
let uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let lowercase = 'abcdefghijklmnopqrstuvwxyz';
let numbers = '0123456789';
let symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?';
if (options.avoidAmbiguous) {
uppercase = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; // Removed I, O
lowercase = 'abcdefghijkmnopqrstuvwxyz'; // Removed l
numbers = '23456789'; // Removed 0, 1
}
let chars = '';
if (options.uppercase) chars += uppercase;
if (options.lowercase) chars += lowercase;
if (options.numbers) chars += numbers;
if (options.symbols) chars += symbols;
if (chars === '') {
chars = lowercase + numbers; // Default fallback
}
let password = '';
const charsLength = chars.length;
// Ensure at least one character from each selected type
if (options.uppercase && options.lowercase && options.numbers && options.symbols) {
password += uppercase[Math.floor(Math.random() * uppercase.length)];
password += lowercase[Math.floor(Math.random() * lowercase.length)];
password += numbers[Math.floor(Math.random() * numbers.length)];
password += symbols[Math.floor(Math.random() * symbols.length)];
}
// Fill the rest randomly
for (let i = password.length; i < length; i++) {
password += chars[Math.floor(Math.random() * charsLength)];
}
// Shuffle the password
return password.split('').sort(() => Math.random() - 0.5).join('');
}
function generatePasswords() {
const options = getOptions();
const count = parseInt(quantity.value);
const passwords = [];
for (let i = 0; i < count; i++) {
passwords.push(generatePassword(options.length, options));
}
// Update single password display
generatedPassword.value = passwords[0];
updateStrengthMeter(passwords[0]);
// Show multiple passwords if count > 1
if (count > 1) {
displayMultiplePasswords(passwords);
} else {
passwordsList.style.display = 'none';
}
}
function displayMultiplePasswords(passwords) {
const container = passwordsList.querySelector('.passwords-grid');
container.innerHTML = '';
passwords.forEach((pwd, index) => {
const item = document.createElement('div');
item.className = 'password-item';
item.innerHTML = `
<div class="password-row">
<span class="password-number">#${index + 1}</span>
<code class="password-code">${pwd}</code>
<button class="btn-icon copy-multiple" data-password="${pwd}" title="Copy">πŸ“‹</button>
<?php if (isLoggedIn()): ?>
<button class="btn-icon save-generated" data-password="${pwd}" title="Save">πŸ’Ύ</button>
<?php endif; ?>
</div>
`;
container.appendChild(item);
});
// Add copy functionality for multiple passwords
container.querySelectorAll('.copy-multiple').forEach(btn => {
btn.addEventListener('click', function() {
navigator.clipboard.writeText(this.dataset.password).then(() => {
const original = this.textContent;
this.textContent = 'βœ“';
setTimeout(() => this.textContent = original, 1500);
});
});
});
passwordsList.style.display = 'block';
}
function updateStrengthMeter(password) {
// Simple strength calculation
let strength = 0;
if (password.length >= 8) strength += 1;
if (password.length >= 12) strength += 1;
if (password.length >= 16) strength += 1;
if (/[A-Z]/.test(password)) strength += 1;
if (/[a-z]/.test(password)) strength += 1;
if (/[0-9]/.test(password)) strength += 1;
if (/[^A-Za-z0-9]/.test(password)) strength += 1;
if (/[A-Z]/.test(password) && /[a-z]/.test(password) && 
/[0-9]/.test(password) && /[^A-Za-z0-9]/.test(password)) {
strength += 1;
}
let percentage = (strength / 8) * 100;
strengthBar.style.width = percentage + '%';
if (strength <= 3) {
strengthBar.style.background = '#e74c3c';
strengthLabel.textContent = 'Weak';
} else if (strength <= 5) {
strengthBar.style.background = '#f39c12';
strengthLabel.textContent = 'Medium';
} else if (strength <= 7) {
strengthBar.style.background = '#27ae60';
strengthLabel.textContent = 'Strong';
} else {
strengthBar.style.background = '#2ecc71';
strengthLabel.textContent = 'Very Strong';
}
}
// Generate initial password
generatePasswords();
});

6. Dashboard - Saved Passwords (dashboard.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
require_once 'includes/encryption.php';
Auth::checkLogin();
$user_id = $_SESSION['user_id'];
// Get categories for filter
$categories = $pdo->prepare("SELECT * FROM categories WHERE user_id = ? ORDER BY name");
$categories->execute([$user_id]);
$user_categories = $categories->fetchAll();
// Get filter parameters
$category_filter = isset($_GET['category']) ? (int)$_GET['category'] : 0;
$favorite_filter = isset($_GET['favorite']) ? true : false;
$search = isset($_GET['search']) ? sanitize($_GET['search']) : '';
// Build query
$query = "
SELECT p.*, c.name as category_name, c.color as category_color, c.icon as category_icon
FROM passwords p
LEFT JOIN categories c ON p.category_id = c.id
WHERE p.user_id = ?
";
$params = [$user_id];
if ($category_filter > 0) {
$query .= " AND p.category_id = ?";
$params[] = $category_filter;
}
if ($favorite_filter) {
$query .= " AND p.favorite = 1";
}
if ($search) {
$query .= " AND (p.title LIKE ? OR p.username LIKE ? OR p.email LIKE ? OR p.url LIKE ? OR p.notes LIKE ?)";
$search_term = "%$search%";
$params[] = $search_term;
$params[] = $search_term;
$params[] = $search_term;
$params[] = $search_term;
$params[] = $search_term;
}
$query .= " ORDER BY p.favorite DESC, p.updated_at DESC";
$stmt = $pdo->prepare($query);
$stmt->execute($params);
$passwords = $stmt->fetchAll();
// Decrypt passwords for display (but don't show them directly)
foreach ($passwords as &$pwd) {
$pwd['decrypted'] = false; // Will decrypt via AJAX when needed
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Passwords - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/dashboard.css">
</head>
<body>
<!-- Header -->
<header class="site-header">
<div class="container">
<div class="logo">
<a href="index.php">
<h1>πŸ” <?php echo SITE_NAME; ?></h1>
</a>
</div>
<nav class="main-nav">
<ul>
<li><a href="index.php">Generator</a></li>
<li><a href="dashboard.php" class="active">My Passwords</a></li>
<li><a href="profile.php">Profile</a></li>
<li><a href="logout.php">Logout</a></li>
</ul>
</nav>
</div>
</header>
<!-- Main Content -->
<main class="container">
<div class="dashboard-container">
<div class="dashboard-header">
<h1>My Saved Passwords</h1>
<a href="index.php" class="btn btn-primary">+ Generate New Password</a>
</div>
<!-- Filters and Search -->
<div class="filters-card">
<form method="GET" action="" class="filter-form">
<div class="search-box">
<input type="text" name="search" placeholder="Search passwords, sites, usernames..." 
value="<?php echo htmlspecialchars($search); ?>">
<button type="submit" class="btn">πŸ” Search</button>
</div>
<div class="filter-options">
<select name="category" class="filter-select">
<option value="">All Categories</option>
<?php foreach ($user_categories as $cat): ?>
<option value="<?php echo $cat['id']; ?>" 
<?php echo $category_filter == $cat['id'] ? 'selected' : ''; ?>>
<?php echo $cat['icon'] . ' ' . $cat['name']; ?>
</option>
<?php endforeach; ?>
</select>
<label class="checkbox-label">
<input type="checkbox" name="favorite" value="1" 
<?php echo isset($_GET['favorite']) ? 'checked' : ''; ?> 
onchange="this.form.submit()">
<span>⭐ Show only favorites</span>
</label>
<a href="dashboard.php" class="btn btn-secondary">Clear Filters</a>
</div>
</form>
</div>
<!-- Passwords Grid -->
<?php if (empty($passwords)): ?>
<div class="empty-state">
<div class="empty-icon">πŸ”</div>
<h3>No passwords saved yet</h3>
<p>Generate and save your first password to get started.</p>
<a href="index.php" class="btn btn-primary">Generate Password</a>
</div>
<?php else: ?>
<div class="passwords-grid">
<?php foreach ($passwords as $password): ?>
<div class="password-card" data-id="<?php echo $password['id']; ?>">
<div class="card-header">
<div class="category-badge" style="background: <?php echo $password['category_color'] ?? '#95a5a6'; ?>">
<?php echo $password['category_icon'] ?? 'πŸ“'; ?>
</div>
<?php if ($password['favorite']): ?>
<span class="favorite-star">⭐</span>
<?php endif; ?>
</div>
<div class="card-body">
<h3 class="password-title"><?php echo htmlspecialchars($password['title']); ?></h3>
<?php if ($password['username']): ?>
<div class="detail-row">
<span class="detail-label">πŸ‘€ Username:</span>
<span class="detail-value"><?php echo htmlspecialchars($password['username']); ?></span>
</div>
<?php endif; ?>
<?php if ($password['email']): ?>
<div class="detail-row">
<span class="detail-label">πŸ“§ Email:</span>
<span class="detail-value"><?php echo htmlspecialchars($password['email']); ?></span>
</div>
<?php endif; ?>
<div class="password-row">
<span class="detail-label">πŸ”‘ Password:</span>
<div class="password-display">
<span class="password-masked">β€’β€’β€’β€’β€’β€’β€’β€’</span>
<span class="password-hidden" style="display: none;"></span>
</div>
</div>
<?php if ($password['url']): ?>
<div class="detail-row">
<span class="detail-label">🌐 URL:</span>
<a href="<?php echo htmlspecialchars($password['url']); ?>" target="_blank" class="detail-link">
<?php echo parse_url($password['url'], PHP_URL_HOST) ?: $password['url']; ?>
</a>
</div>
<?php endif; ?>
<?php if ($password['notes']): ?>
<div class="notes-section">
<span class="detail-label">πŸ“ Notes:</span>
<p class="notes-text"><?php echo nl2br(htmlspecialchars($password['notes'])); ?></p>
</div>
<?php endif; ?>
<div class="password-meta">
<span>Updated: <?php echo timeAgo($password['updated_at'] ?: $password['created_at']); ?></span>
</div>
</div>
<div class="card-footer">
<button class="btn-icon show-password" title="Show password">πŸ‘οΈ</button>
<button class="btn-icon copy-password" title="Copy password">πŸ“‹</button>
<a href="edit-password.php?id=<?php echo $password['id']; ?>" class="btn-icon" title="Edit">✏️</a>
<button class="btn-icon delete-password" data-id="<?php echo $password['id']; ?>" title="Delete">πŸ—‘οΈ</button>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</main>
<!-- Footer -->
<footer class="site-footer">
<div class="container">
<p>&copy; 2024 <?php echo SITE_NAME; ?>. All rights reserved.</p>
</div>
</footer>
<!-- Password Modal (for viewing) -->
<div id="password-modal" class="modal" style="display: none;">
<div class="modal-content">
<span class="close">&times;</span>
<h2>Password Details</h2>
<div id="modal-password"></div>
<button class="btn btn-primary" id="copy-modal-password">Copy Password</button>
</div>
</div>
<script src="assets/js/dashboard.js"></script>
<script>
// CSRF token for AJAX requests
const csrfToken = '<?php echo generateCSRFToken(); ?>';
</script>
</body>
</html>

7. Dashboard JavaScript (assets/js/dashboard.js)

// Dashboard JavaScript for Password Manager
document.addEventListener('DOMContentLoaded', function() {
// Show/Hide Password functionality
document.querySelectorAll('.show-password').forEach(btn => {
btn.addEventListener('click', async function() {
const card = this.closest('.password-card');
const passwordId = card.dataset.id;
const maskedSpan = card.querySelector('.password-masked');
const hiddenSpan = card.querySelector('.password-hidden');
if (hiddenSpan.style.display === 'none' || !hiddenSpan.style.display) {
// Fetch and show password
try {
const response = await fetch(`api/get-password.php?id=${passwordId}&csrf_token=${csrfToken}`);
const data = await response.json();
if (data.success) {
hiddenSpan.textContent = data.password;
hiddenSpan.style.display = 'inline';
maskedSpan.style.display = 'none';
this.textContent = 'πŸ‘οΈβ€πŸ—¨οΈ';
} else {
alert('Failed to retrieve password');
}
} catch (error) {
console.error('Error:', error);
}
} else {
// Hide password
hiddenSpan.style.display = 'none';
maskedSpan.style.display = 'inline';
this.textContent = 'πŸ‘οΈ';
}
});
});
// Copy password functionality
document.querySelectorAll('.copy-password').forEach(btn => {
btn.addEventListener('click', async function() {
const card = this.closest('.password-card');
const passwordId = card.dataset.id;
try {
const response = await fetch(`api/get-password.php?id=${passwordId}&csrf_token=${csrfToken}`);
const data = await response.json();
if (data.success) {
await navigator.clipboard.writeText(data.password);
// Show feedback
const originalText = this.textContent;
this.textContent = 'βœ“';
setTimeout(() => {
this.textContent = originalText;
}, 1500);
} else {
alert('Failed to copy password');
}
} catch (error) {
console.error('Error:', error);
}
});
});
// Delete password functionality
document.querySelectorAll('.delete-password').forEach(btn => {
btn.addEventListener('click', async function() {
if (!confirm('Are you sure you want to delete this password? This action cannot be undone.')) {
return;
}
const passwordId = this.dataset.id;
try {
const response = await fetch('delete-password.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `id=${passwordId}&csrf_token=${csrfToken}`
});
const data = await response.json();
if (data.success) {
// Remove card from UI
this.closest('.password-card').remove();
// Check if empty
if (document.querySelectorAll('.password-card').length === 0) {
location.reload(); // Reload to show empty state
}
} else {
alert('Failed to delete password');
}
} catch (error) {
console.error('Error:', error);
}
});
});
// Modal functionality
const modal = document.getElementById('password-modal');
const closeBtn = document.querySelector('.close');
closeBtn.addEventListener('click', function() {
modal.style.display = 'none';
});
window.addEventListener('click', function(event) {
if (event.target === modal) {
modal.style.display = 'none';
}
});
document.getElementById('copy-modal-password').addEventListener('click', function() {
const password = document.getElementById('modal-password').textContent;
navigator.clipboard.writeText(password);
const originalText = this.textContent;
this.textContent = 'Copied!';
setTimeout(() => {
this.textContent = originalText;
}, 1500);
});
});

8. Save Password Handler (save-password.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
require_once 'includes/encryption.php';
Auth::checkLogin();
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Invalid request method']);
exit;
}
// Verify CSRF token
if (!isset($_POST['csrf_token']) || !verifyCSRFToken($_POST['csrf_token'])) {
echo json_encode(['success' => false, 'message' => 'Invalid security token']);
exit;
}
$user_id = $_SESSION['user_id'];
$password = $_POST['password'] ?? '';
$title = sanitize($_POST['title'] ?? '');
$category_id = !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null;
$username = sanitize($_POST['username'] ?? '');
$email = sanitize($_POST['email'] ?? '');
$url = sanitize($_POST['url'] ?? '');
$notes = sanitize($_POST['notes'] ?? '');
$favorite = isset($_POST['favorite']) ? 1 : 0;
// Validate
if (empty($password)) {
echo json_encode(['success' => false, 'message' => 'Password is required']);
exit;
}
if (empty($title)) {
echo json_encode(['success' => false, 'message' => 'Title is required']);
exit;
}
// Encrypt the password
$encrypted_password = encryptPassword($password);
// Calculate strength
$strength = calculatePasswordStrength($password);
// Insert into database
try {
$stmt = $pdo->prepare("
INSERT INTO passwords (user_id, category_id, title, username, email, encrypted_password, url, notes, strength, favorite)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$success = $stmt->execute([
$user_id,
$category_id,
$title,
$username,
$email,
$encrypted_password,
$url,
$notes,
$strength['class'],
$favorite
]);
if ($success) {
echo json_encode([
'success' => true, 
'message' => 'Password saved successfully',
'id' => $pdo->lastInsertId()
]);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to save password']);
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
}
?>

9. API - Get Password (api/get-password.php)

<?php
require_once '../includes/config.php';
require_once '../includes/auth.php';
require_once '../includes/encryption.php';
header('Content-Type: application/json');
if (!isLoggedIn()) {
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
exit;
}
// Verify CSRF token
if (!isset($_GET['csrf_token']) || !verifyCSRFToken($_GET['csrf_token'])) {
echo json_encode(['success' => false, 'message' => 'Invalid security token']);
exit;
}
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$user_id = $_SESSION['user_id'];
if (!$id) {
echo json_encode(['success' => false, 'message' => 'Invalid password ID']);
exit;
}
// Get password from database
$stmt = $pdo->prepare("SELECT encrypted_password FROM passwords WHERE id = ? AND user_id = ?");
$stmt->execute([$id, $user_id]);
$result = $stmt->fetch();
if (!$result) {
echo json_encode(['success' => false, 'message' => 'Password not found']);
exit;
}
// Decrypt password
$decrypted = decryptPassword($result['encrypted_password']);
// Update last used timestamp
$pdo->prepare("UPDATE passwords SET last_used = NOW() WHERE id = ?")->execute([$id]);
echo json_encode(['success' => true, 'password' => $decrypted]);
?>

10. Delete Password Handler (delete-password.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
header('Content-Type: application/json');
if (!isLoggedIn()) {
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Invalid request method']);
exit;
}
// Verify CSRF token
if (!isset($_POST['csrf_token']) || !verifyCSRFToken($_POST['csrf_token'])) {
echo json_encode(['success' => false, 'message' => 'Invalid security token']);
exit;
}
$id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
$user_id = $_SESSION['user_id'];
if (!$id) {
echo json_encode(['success' => false, 'message' => 'Invalid password ID']);
exit;
}
// Delete password (cascade will delete history)
$stmt = $pdo->prepare("DELETE FROM passwords WHERE id = ? AND user_id = ?");
$success = $stmt->execute([$id, $user_id]);
if ($success && $stmt->rowCount() > 0) {
echo json_encode(['success' => true, 'message' => 'Password deleted successfully']);
} else {
echo json_encode(['success' => false, 'message' => 'Password not found or could not be deleted']);
}
?>

11. Login Page (login.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
// If already logged in, redirect to dashboard
if (isLoggedIn()) {
redirect('dashboard.php');
}
$error = '';
$timeout = isset($_GET['timeout']);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (Auth::login($username, $password)) {
redirect('dashboard.php');
} else {
$error = 'Invalid username/email or password';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body class="auth-page">
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<h1>πŸ” <?php echo SITE_NAME; ?></h1>
<p>Login to access your password vault</p>
</div>
<?php if ($timeout): ?>
<div class="alert alert-info">Session expired. Please login again.</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-error"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST" action="" class="auth-form">
<div class="form-group">
<label for="username">Username or Email</label>
<input type="text" id="username" name="username" required 
placeholder="Enter your username or email">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required 
placeholder="Enter your password">
</div>
<button type="submit" class="btn btn-primary btn-block">Login</button>
</form>
<div class="auth-footer">
<p>Don't have an account? <a href="register.php">Register</a></p>
<p><a href="index.php">← Back to Generator</a></p>
</div>
<div class="demo-credentials">
<p><strong>Demo Credentials:</strong></p>
<p>Username: demo<br>Password: password123</p>
</div>
</div>
</div>
</body>
</html>

12. Registration Page (register.php)

<?php
require_once 'includes/config.php';
require_once 'includes/auth.php';
// If already logged in, redirect to dashboard
if (isLoggedIn()) {
redirect('dashboard.php');
}
$errors = [];
$form_data = [
'username' => '',
'email' => '',
'full_name' => '',
'password' => '',
'confirm_password' => ''
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form_data['username'] = sanitize($_POST['username']);
$form_data['email'] = sanitize($_POST['email']);
$form_data['full_name'] = sanitize($_POST['full_name']);
$form_data['password'] = $_POST['password'];
$form_data['confirm_password'] = $_POST['confirm_password'];
// Validate
if (empty($form_data['username'])) {
$errors['username'] = 'Username is required';
} elseif (strlen($form_data['username']) < 3) {
$errors['username'] = 'Username must be at least 3 characters';
}
if (empty($form_data['email'])) {
$errors['email'] = 'Email is required';
} elseif (!filter_var($form_data['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Invalid email format';
}
if (empty($form_data['full_name'])) {
$errors['full_name'] = 'Full name is required';
}
if (empty($form_data['password'])) {
$errors['password'] = 'Password is required';
} elseif (strlen($form_data['password']) < 8) {
$errors['password'] = 'Password must be at least 8 characters';
}
if ($form_data['password'] !== $form_data['confirm_password']) {
$errors['confirm_password'] = 'Passwords do not match';
}
if (empty($errors)) {
$result = Auth::register($form_data);
if ($result['success']) {
$_SESSION['success'] = $result['message'];
redirect('login.php');
} else {
$errors['general'] = $result['message'];
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register - <?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body class="auth-page">
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<h1>πŸ” <?php echo SITE_NAME; ?></h1>
<p>Create a new account</p>
</div>
<?php if (!empty($errors['general'])): ?>
<div class="alert alert-error"><?php echo $errors['general']; ?></div>
<?php endif; ?>
<form method="POST" action="" class="auth-form">
<div class="form-group">
<label for="full_name">Full Name *</label>
<input type="text" id="full_name" name="full_name" 
value="<?php echo htmlspecialchars($form_data['full_name']); ?>" required>
<?php if (isset($errors['full_name'])): ?>
<span class="error"><?php echo $errors['full_name']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="username">Username *</label>
<input type="text" id="username" name="username" 
value="<?php echo htmlspecialchars($form_data['username']); ?>" required>
<?php if (isset($errors['username'])): ?>
<span class="error"><?php echo $errors['username']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" 
value="<?php echo htmlspecialchars($form_data['email']); ?>" required>
<?php if (isset($errors['email'])): ?>
<span class="error"><?php echo $errors['email']; ?></span>
<?php endif; ?>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="password">Password *</label>
<input type="password" id="password" name="password" required>
<?php if (isset($errors['password'])): ?>
<span class="error"><?php echo $errors['password']; ?></span>
<?php endif; ?>
</div>
<div class="form-group col-md-6">
<label for="confirm_password">Confirm Password *</label>
<input type="password" id="confirm_password" name="confirm_password" required>
<?php if (isset($errors['confirm_password'])): ?>
<span class="error"><?php echo $errors['confirm_password']; ?></span>
<?php endif; ?>
</div>
</div>
<div class="password-requirements">
<p><strong>Password must:</strong></p>
<ul>
<li>Be at least 8 characters long</li>
<li>Include uppercase and lowercase letters</li>
<li>Include numbers</li>
<li>Include special characters (recommended)</li>
</ul>
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
<div class="auth-footer">
<p>Already have an account? <a href="login.php">Login</a></p>
<p><a href="index.php">← Back to Generator</a></p>
</div>
</div>
</div>
</body>
</html>

13. CSS Styling (assets/css/style.css)

/* Main Styles for Password Generator */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: #f4f6f9;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header */
.site-header {
background: #2c3e50;
color: #fff;
padding: 1rem 0;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.site-header .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo a {
color: #fff;
text-decoration: none;
}
.logo h1 {
font-size: 1.8rem;
}
.main-nav ul {
list-style: none;
display: flex;
gap: 1.5rem;
}
.main-nav a {
color: #fff;
text-decoration: none;
font-weight: 500;
transition: color 0.3s;
}
.main-nav a:hover,
.main-nav a.active {
color: #3498db;
}
/* Generator Page */
.generator-container {
max-width: 800px;
margin: 2rem auto;
}
.page-title {
font-size: 2.5rem;
color: #2c3e50;
margin-bottom: 0.5rem;
text-align: center;
}
.page-description {
color: #666;
text-align: center;
margin-bottom: 2rem;
}
.generator-card {
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 2rem;
}
.generated-password-area {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
margin-bottom: 2rem;
}
.password-display {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.password-display input {
flex: 1;
padding: 1rem;
font-family: monospace;
font-size: 1.2rem;
border: 2px solid #3498db;
border-radius: 4px;
background: #fff;
color: #333;
}
.btn-icon {
width: 50px;
height: 50px;
border: none;
background: #3498db;
color: #fff;
border-radius: 4px;
cursor: pointer;
font-size: 1.2rem;
transition: background 0.3s;
}
.btn-icon:hover {
background: #2980b9;
}
.strength-meter {
margin-top: 1rem;
}
.strength-bar {
height: 10px;
background: #e74c3c;
border-radius: 5px;
width: 0;
transition: width 0.3s, background 0.3s;
margin-bottom: 0.5rem;
}
.strength-text {
font-size: 0.9rem;
color: #666;
}
/* Generator Form */
.generator-form {
margin-bottom: 2rem;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
input[type="range"] {
width: 100%;
height: 8px;
background: #ddd;
border-radius: 4px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: #3498db;
border-radius: 50%;
cursor: pointer;
}
.options-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
}
.checkbox-label input[type="checkbox"] {
width: 18px;
height: 18px;
}
/* Passwords List */
.passwords-list {
margin-top: 2rem;
border-top: 1px solid #eee;
padding-top: 2rem;
}
.passwords-list h3 {
margin-bottom: 1rem;
color: #2c3e50;
}
.passwords-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.password-item {
background: #f8f9fa;
padding: 1rem;
border-radius: 4px;
}
.password-row {
display: flex;
align-items: center;
gap: 1rem;
}
.password-number {
font-weight: bold;
color: #666;
min-width: 50px;
}
.password-code {
flex: 1;
font-family: monospace;
font-size: 1.1rem;
}
/* Save Section */
.save-card {
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 2rem;
}
.save-card h2 {
color: #2c3e50;
margin-bottom: 1.5rem;
}
.save-form .form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.save-form input,
.save-form select,
.save-form textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.save-form textarea {
resize: vertical;
}
.form-actions {
display: flex;
gap: 1rem;
margin-top: 1.5rem;
}
/* Buttons */
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
text-decoration: none;
transition: all 0.3s;
}
.btn-primary {
background: #3498db;
color: #fff;
}
.btn-primary:hover {
background: #2980b9;
}
.btn-success {
background: #27ae60;
color: #fff;
}
.btn-success:hover {
background: #229954;
}
.btn-large {
padding: 1rem 2rem;
font-size: 1.1rem;
}
.btn-block {
width: 100%;
}
/* Login Prompt */
.login-prompt {
text-align: center;
padding: 2rem;
background: #f8f9fa;
border-radius: 8px;
margin-bottom: 2rem;
}
.login-prompt a {
color: #3498db;
text-decoration: none;
font-weight: 500;
}
.login-prompt a:hover {
text-decoration: underline;
}
/* Info Section */
.info-section {
margin-top: 3rem;
}
.info-section h2 {
text-align: center;
margin-bottom: 2rem;
color: #2c3e50;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
}
.info-card {
background: #fff;
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.info-card h3 {
color: #3498db;
margin-bottom: 0.5rem;
}
.info-card p {
color: #666;
}
/* Auth Pages */
.auth-page {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.auth-container {
width: 100%;
max-width: 500px;
padding: 20px;
}
.auth-card {
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.auth-header {
text-align: center;
margin-bottom: 2rem;
}
.auth-header h1 {
color: #2c3e50;
margin-bottom: 0.5rem;
}
.auth-header p {
color: #666;
}
.auth-form .form-group {
margin-bottom: 1.5rem;
}
.auth-form label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
.auth-form input {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.auth-form input:focus {
outline: none;
border-color: #3498db;
}
.auth-footer {
text-align: center;
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 1px solid #eee;
}
.auth-footer a {
color: #3498db;
text-decoration: none;
}
.demo-credentials {
margin-top: 1.5rem;
padding: 1rem;
background: #f8f9fa;
border-radius: 4px;
font-size: 0.9rem;
color: #666;
}
.password-requirements {
background: #f8f9fa;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1.5rem;
font-size: 0.9rem;
}
.password-requirements ul {
margin-left: 1.5rem;
color: #666;
}
/* Alerts */
.alert {
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.error {
display: block;
color: #e74c3c;
font-size: 0.85rem;
margin-top: 0.25rem;
}
/* Footer */
.site-footer {
background: #2c3e50;
color: #fff;
padding: 2rem 0;
margin-top: 3rem;
text-align: center;
}
.security-note {
font-size: 0.9rem;
opacity: 0.8;
margin-top: 0.5rem;
}
/* Responsive */
@media (max-width: 768px) {
.site-header .container {
flex-direction: column;
gap: 1rem;
text-align: center;
}
.main-nav ul {
flex-wrap: wrap;
justify-content: center;
}
.save-form .form-row {
grid-template-columns: 1fr;
}
.password-display {
flex-wrap: wrap;
}
.password-display input {
width: 100%;
}
.btn-icon {
flex: 1;
}
.info-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.page-title {
font-size: 2rem;
}
.options-grid {
grid-template-columns: 1fr;
}
.password-row {
flex-wrap: wrap;
}
.password-number {
width: 100%;
}
}

πŸ“ How to Use This Project (Step-by-Step Guide)

Step 1: Install Local Server

  1. Download and install XAMPP from apachefriends.org
  2. Launch XAMPP Control Panel
  3. Start Apache and MySQL services

Step 2: Create Project Folder

  1. Navigate to C:\xampp\htdocs\ (Windows) or /Applications/XAMPP/htdocs/ (Mac)
  2. Create a new folder named password-generator

Step 3: Set Up Database

  1. Open browser and go to http://localhost/phpmyadmin
  2. Click on "SQL" tab
  3. Copy the entire SQL from database/password_generator.sql
  4. Paste and click "Go" to create database and tables

Step 4: Create Password Hash for Demo User

Create a file named hash.php in project root:

<?php
echo password_hash('password123', PASSWORD_DEFAULT);
?>

Run it: http://localhost/password-generator/hash.php
Copy the hash and update it in the SQL insert statement for the demo user.

Step 5: Configure Database Connection

Open includes/config.php and update:

define('DB_HOST', 'localhost');
define('DB_NAME', 'password_manager');
define('DB_USER', 'root');
define('DB_PASS', '');
define('ENCRYPTION_KEY', 'ChangeThisToARandomSecureKey123!'); // Change this!

Step 6: Test the Application

Public Side (Generator):

  • Open: http://localhost/password-generator/
  • Adjust password length and options
  • Click "Generate Passwords"
  • Copy passwords to clipboard

User Authentication:

  • Register a new account at http://localhost/password-generator/register.php
  • Or login with demo credentials:
  • Username: demo
  • Password: password123

Password Management:

  1. Generate a password
  2. Click "Save" button (visible when logged in)
  3. Fill in title, category, and other details
  4. Save the password
  5. View saved passwords in dashboard
  6. Show/hide passwords
  7. Copy passwords to clipboard
  8. Edit or delete passwords

Step 7: Security Configuration

Important Security Notes:

  1. Change ENCRYPTION_KEY in includes/config.php to a strong random key
  2. Use HTTPS in production
  3. Enable 2FA for admin accounts
  4. Regular database backups
  5. Keep PHP and MySQL updated

Step 8: Customize Settings

You can modify:

  • Password length limits in JavaScript
  • Character sets in includes/encryption.php
  • Session timeout in includes/config.php
  • UI colors in CSS files

🎯 Features Summary

Password Generator Features:

  • βœ… Customizable password length (4-64)
  • βœ… Include/exclude character types
  • βœ… Avoid ambiguous characters
  • βœ… Multiple passwords at once
  • βœ… Copy to clipboard
  • βœ… Password strength indicator
  • βœ… Regenerate button

Password Management Features:

  • βœ… Save passwords with titles
  • βœ… Categorize passwords
  • βœ… Store usernames/emails
  • βœ… Add notes and URLs
  • βœ… Mark favorites
  • βœ… Search/filter passwords
  • βœ… Show/hide passwords
  • βœ… Copy passwords
  • βœ… Edit saved passwords
  • βœ… Delete passwords
  • βœ… Password history tracking

Security Features:

  • βœ… AES-256 encryption
  • βœ… Password hashing for users
  • βœ… CSRF protection
  • βœ… Session management
  • βœ… SQL injection prevention
  • βœ… XSS protection
  • βœ… Automatic logout
  • βœ… Password strength analysis

User Features:

  • βœ… User registration
  • βœ… Secure login
  • βœ… Profile management
  • βœ… Password export (optional)
  • βœ… Multiple categories
  • βœ… Responsive design

πŸš€ Future Enhancements

  1. Two-Factor Authentication: Add 2FA for extra security
  2. Password Sharing: Securely share passwords with other users
  3. Browser Extension: Chrome/Firefox extension for autofill
  4. Password Health Check: Identify weak/reused passwords
  5. Breach Alert: Check if passwords appear in data breaches
  6. Mobile App: React Native or Flutter app
  7. Biometric Login: Fingerprint/face recognition
  8. Secure Notes: Store encrypted notes
  9. Password Generator API: REST API for developers
  10. Import/Export: Import from other password managers
  11. Password Expiry: Set expiration reminders
  12. Emergency Access: Grant emergency access to trusted contacts
  13. Audit Log: Track all access to passwords
  14. Dark Mode: Theme switching
  15. Backup & Restore: Encrypted backup of all data
  16. Password Generator History: Recently generated passwords
  17. Password Strength Report: Analyze all saved passwords
  18. Duplicate Password Detection: Find reused passwords
  19. One-Time Passwords: Generate TOTP for 2FA
  20. Password Generator API: Integrate with other apps

This comprehensive Password Generator with Save Option provides a complete solution for generating and managing secure passwords with enterprise-grade encryption!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper