1. 系统概述
用户登录系统是Web应用的基础功能之一。本教程将指导您创建一个安全可靠的PHP登录系统,包含以下功能:
2. 数据库设计
首先创建用户表存储用户信息:
CREATE TABLE users ( id INT(11) PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, last_login DATETIME NULL );
3. 数据库连接
创建数据库连接文件config.php:
<?php $host = 'localhost'; $dbname = 'your_database'; $username = 'your_username'; $password = 'your_password'; try { $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } catch (PDOException $e) { die("数据库连接失败: " . $e->getMessage()); } ?>
4. 用户注册功能
创建注册页面register.php:
<?php require_once 'config.php'; session_start(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $username = trim($_POST['username']); $email = trim($_POST['email']); $password = $_POST['password']; $confirm_password = $_POST['confirm_password']; // 验证输入 $errors = []; if (empty($username) || strlen($username) < 3) { $errors[] = "用户名至少需要3个字符"; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = "请输入有效的邮箱地址"; } if (strlen($password) prepare("SELECT id FROM users WHERE username = ? OR email = ?"); $stmt->execute([$username, $email]); if ($stmt->rowCount() > 0) { $errors[] = "用户名或邮箱已被注册"; } } // 如果没有错误,创建用户 if (empty($errors)) { $hashed_password = password_hash($password, PASSWORD_DEFAULT); $stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)"); if ($stmt->execute([$username, $email, $hashed_password])) { $_SESSION['success_msg'] = "注册成功,请登录"; header("Location: login.php"); exit(); } else { $errors[] = "注册失败,请稍后重试"; } } } ?> <!DOCTYPE html> <html> <head> <title>用户注册</title> </head> <body> <h2>用户注册</h2> <?php if (!empty($errors)): ?> <div class="errors"> <?php foreach ($errors as $error): ?> <p><?php echo htmlspecialchars($error); ?></p> <?php endforeach; ?> </div> <?php endif; ?> <form method="post" action=""> <div> <label>用户名:</label> <input type="text" name="username" required value="<?php echo isset($username) ? htmlspecialchars($username) : ''; ?>"> </div> <div> <label>邮箱:</label> <input type="email" name="email" required value="<?php echo isset($email) ? htmlspecialchars($email) : ''; ?>"> </div> <div> <label>密码:</label> <input type="password" name="password" required> </div> <div> <label>确认密码:</label> <input type="password" name="confirm_password" required> </div> <div> <button type="submit">注册</button> </div> </form> <p>已有账号? <a href="login.php" rel="external nofollow" >立即登录</a></p> </body> </html>
5. 用户登录功能
创建登录页面login.php:
<?php require_once 'config.php'; session_start(); // 如果用户已登录,重定向到主页 if (isset($_SESSION['user_id'])) { header("Location: index.php"); exit(); } if ($_SERVER['REQUEST_METHOD'] == 'POST') { $username = trim($_POST['username']); $password = $_POST['password']; $remember = isset($_POST['remember']); $errors = []; if (empty($username)) { $errors[] = "请输入用户名"; } if (empty($password)) { $errors[] = "请输入密码"; } if (empty($errors)) { // 查询用户 $stmt = $pdo->prepare("SELECT id, username, password 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']; // 更新最后登录时间 $stmt = $pdo->prepare("UPDATE users SET last_login = NOW() WHERE id = ?"); $stmt->execute([$user['id']]); // 记住登录状态 if ($remember) { $token = bin2hex(random_bytes(32)); $expire = time() + 60 * 60 * 24 * 30; // 30天 setcookie('remember_token', $token, $expire, '/'); // 存储token到数据库 $stmt = $pdo->prepare("UPDATE users SET remember_token = ? WHERE id = ?"); $stmt->execute([$token, $user['id']]); } header("Location: index.php"); exit(); } else { $errors[] = "用户名或密码错误"; } } } ?> <!DOCTYPE html> <html> <head> <title>用户登录</title> </head> <body> <h2>用户登录</h2> <?php if (isset($_SESSION['success_msg'])): ?> <div class="success"> <p><?php echo htmlspecialchars($_SESSION['success_msg']); unset($_SESSION['success_msg']); ?></p> </div> <?php endif; ?> <?php if (!empty($errors)): ?> <div class="errors"> <?php foreach ($errors as $error): ?> <p><?php echo htmlspecialchars($error); ?></p> <?php endforeach; ?> </div> <?php endif; ?> <form method="post" action=""> <div> <label>用户名或邮箱:</label> <input type="text" name="username" required value="<?php echo isset($username) ? htmlspecialchars($username) : ''; ?>"> </div> <div> <label>密码:</label> <input type="password" name="password" required> </div> <div> <label> <input type="checkbox" name="remember"> 记住我 </label> </div> <div> <button type="submit">登录</button> </div> </form> <p>还没有账号? <a href="register.php" rel="external nofollow" >立即注册</a></p> </body> </html>
6. 会话管理与自动登录
创建session.php文件处理会话和自动登录:
<?php require_once 'config.php'; session_start(); // 自动登录功能 function auto_login() { global $pdo; if (isset($_COOKIE['remember_token']) && !isset($_SESSION['user_id'])) { $token = $_COOKIE['remember_token']; $stmt = $pdo->prepare("SELECT id, username FROM users WHERE remember_token = ?"); $stmt->execute([$token]); $user = $stmt->fetch(); if ($user) { $_SESSION['user_id'] = $user['id']; $_SESSION['username'] = $user['username']; } } } // 检查用户是否登录 function is_logged_in() { return isset($_SESSION['user_id']); } // 获取当前用户ID function get_current_user_id() { return $_SESSION['user_id'] ?? null; } // 注销功能 function logout() { global $pdo; if (isset($_SESSION['user_id'])) { // 清除数据库中的remember_token $stmt = $pdo->prepare("UPDATE users SET remember_token = NULL WHERE id = ?"); $stmt->execute([$_SESSION['user_id']]); } // 清除会话 $_SESSION = []; session_destroy(); // 清除记住登录的cookie setcookie('remember_token', '', time() - 3600, '/'); } // 调用自动登录 auto_login(); ?>
7. 主页与用户仪表板
创建主页index.php:
<?php require_once 'session.php'; if (!is_logged_in()) { header("Location: login.php"); exit(); } ?> <!DOCTYPE html> <html> <head> <title>用户主页</title> </head> <body> <h2>欢迎, <?php echo htmlspecialchars($_SESSION['username']); ?>!</h2> <nav> <ul> <li><a href="profile.php" rel="external nofollow" >个人资料</a></li> <li><a href="logout.php" rel="external nofollow" >退出登录</a></li> </ul> </nav> <div> <h3>用户仪表板</h3> <p>这是您的个人主页,您可以在这里管理您的账户信息。</p> </div> </body> </html>
8. 安全增强措施
为了提高系统安全性,我们需要实施以下措施:
8.1 防止SQL注入
始终使用预处理语句:
// 不安全的做法 $sql = "SELECT * FROM users WHERE username = '$username'"; $result = $pdo->query($sql); // 安全的做法 - 使用预处理语句 $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); $stmt->execute([$username]); $user = $stmt->fetch();
8.2 防止XSS攻击
对所有用户输出进行转义:
// 不安全的做法 echo $user_input; // 安全的做法 echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
8.3 密码加密
使用password_hash()和password_verify()函数:
// 创建密码哈希 $hashed_password = password_hash($password, PASSWORD_DEFAULT); // 验证密码 if (password_verify($input_password, $hashed_password)) { // 密码正确 }
8.4 CSRF保护
在表单中添加CSRF令牌:
// 生成CSRF令牌 if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // 在表单中包含令牌 <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> // 验证令牌 if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die("CSRF令牌验证失败"); }
9. 完整系统文件结构
/login-system/ │ ├── config.php # 数据库配置 ├── session.php # 会话管理 ├── register.php # 用户注册 ├── login.php # 用户登录 ├── index.php # 主页 ├── profile.php # 用户资料页面 ├── logout.php # 退出登录 └── .htaccess # Apache配置(可选)
10. 总结
本教程详细介绍了如何使用PHP创建一个完整的用户登录验证系统。我们实现了用户注册、登录、会话管理和安全防护等功能。关键点包括:
- 使用预处理语句防止SQL注入
- 对输出进行转义防止XSS攻击
- 使用password_hash()安全加密密码
- 实现CSRF令牌保护
- 提供”记住我”功能增强用户体验
通过遵循这些最佳实践,您可以创建一个安全可靠的用户认证系统,为您的Web应用提供坚实的基础。记得根据实际需求调整和扩展这些功能,并始终保持对安全问题的关注。