PHP 基础教程
PHP 高级教程
PHP & MySQL DATABASE
PHP 示例
PHP 参考手册

PHP MySQL 登录系统

在本教程中,您将学习如何使用 PHP 和 MySQL 构建登录系统。

实现用户认证机制

用户身份验证在现代 Web 应用程序中非常常见。 它是一种安全机制,用于限制未经授权访问站点上仅限会员的区域和工具。

在本教程中,我们将使用 PHP 和 MySQL 创建一个简单的注册和登录系统。 本教程由两部分组成:第一部分我们将创建一个用户注册表单,第二部分我们将创建一个登录表单,以及一个欢迎页面和一个注销脚本。

构建注册系统

在本节中,我们将构建一个注册系统,允许用户通过填写网络表单来创建新帐户。 但是,首先我们需要创建一个包含所有用户数据的表。

第 1 步:创建数据库表

执行以下 SQL 查询以在 MySQL 数据库中创建 users 表。

示例

Download
CREATE TABLE users (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

有关语法的详细信息,请查看 SQL CREATE TABLE 语句 的教程 用于在 MySQL 数据库系统中创建表。

第 2 步:创建配置文件

创建表后,我们需要创建一个 PHP 脚本来连接 MySQL 数据库服务器。 让我们创建一个名为"config.php"的文件并将以下代码放入其中。

示例

Procedural Object Oriented PDO
Download
<?php
/* 数据库凭据。 假设您正在运行 MySQL
具有默认设置的服务器(用户 'root' 没有密码) */
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'demo');
 
/* 尝试连接 MySQL 数据库 */
$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
 
// 检查连接
if($link === false){
    die("ERROR: Could not connect. " . mysqli_connect_error());
}
?>
<?php
/* 数据库凭据。 假设您正在运行 MySQL
具有默认设置的服务器(用户 'root' 没有密码) */
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'demo');
 
/* 尝试连接 MySQL 数据库 */
$mysqli = new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
 
// 检查连接
if($mysqli === false){
    die("ERROR: Could not connect. " . $mysqli->connect_error);
}
?>
<?php
/* 数据库凭据。 假设您正在运行 MySQL
具有默认设置的服务器(用户 'root' 没有密码) */
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'demo');
 
/* 尝试连接 MySQL 数据库 */
try{
    $pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD);
    // 设置 PDO 错误模式为异常
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
    die("ERROR: Could not connect. " . $e->getMessage());
}
?>

如果您使用下载按钮下载了面向对象或 PDO 代码示例,请在测试代码之前从文件名中删除文本"-oo-format"或"-pdo-format"。

注意: 在测试此代码之前,请根据您的 MySQL 服务器设置替换凭据,例如,将数据库名称"demo"替换为您自己的数据库名称,将用户名"root"替换为您自己的数据库用户名, 如果有,请指定数据库密码。

第 3 步:创建注册表

让我们创建另一个 PHP 文件"register.php"并将以下示例代码放入其中。 此示例代码将创建一个允许用户注册自己的 Web 表单。

如果用户尝试在未输入任何值的情况下提交表单,或者如果用户输入的用户名已被其他用户使用,则此脚本也会生成错误。

示例

Procedural Object Oriented PDO
Download
<?php
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = $confirm_password = "";
$username_err = $password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证用户名
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter a username.";
    } elseif(!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))){
        $username_err = "Username can only contain letters, numbers, and underscores.";
    } else{
        // 准备一个选择语句
        $sql = "SELECT id FROM users WHERE username = ?";
        
        if($stmt = mysqli_prepare($link, $sql)){
            // 将变量作为参数绑定到准备好的语句
            mysqli_stmt_bind_param($stmt, "s", $param_username);
            
            // 设置参数
            $param_username = trim($_POST["username"]);
            
            // 尝试执行准备好的语句
            if(mysqli_stmt_execute($stmt)){
                /* 存储结果 */
                mysqli_stmt_store_result($stmt);
                
                if(mysqli_stmt_num_rows($stmt) == 1){
                    $username_err = "This username is already taken.";
                } else{
                    $username = trim($_POST["username"]);
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            mysqli_stmt_close($stmt);
        }
    }
    
    // 验证密码
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter a password.";     
    } elseif(strlen(trim($_POST["password"])) < 6){
        $password_err = "Password must have atleast 6 characters.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm password.";     
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($password_err) && ($password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
    
    // 在插入数据库之前检查输入错误
    if(empty($username_err) && empty($password_err) && empty($confirm_password_err)){
        
        // 准备一个插入语句
        $sql = "INSERT INTO users (username, password) VALUES (?, ?)";
         
        if($stmt = mysqli_prepare($link, $sql)){
            // 将变量作为参数绑定到准备好的语句
            mysqli_stmt_bind_param($stmt, "ss", $param_username, $param_password);
            
            // 设置参数
            $param_username = $username;
            $param_password = password_hash($password, PASSWORD_DEFAULT); // Creates a password hash
            
            // 尝试执行准备好的语句
            if(mysqli_stmt_execute($stmt)){
                // 重定向到登录页面
                header("location: login.php");
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            mysqli_stmt_close($stmt);
        }
    }
    
    // 关闭连接
    mysqli_close($link);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sign Up</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Sign Up</h2>
        <p>Please fill this form to create an account.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $password; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $confirm_password; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <input type="reset" class="btn btn-secondary ml-2" value="Reset">
            </div>
            <p>Already have an account? <a href="login.php">Login here</a>.</p>
        </form>
    </div>    
</body>
</html>
<?php
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = $confirm_password = "";
$username_err = $password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证用户名
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter a username.";
    } elseif(!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))){
        $username_err = "Username can only contain letters, numbers, and underscores.";
    } else{
        // 准备一个选择语句
        $sql = "SELECT id FROM users WHERE username = ?";
        
        if($stmt = $mysqli->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bind_param("s", $param_username);
            
            // 设置参数
            $param_username = trim($_POST["username"]);
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 存储结果
                $stmt->store_result();
                
                if($stmt->num_rows == 1){
                    $username_err = "This username is already taken.";
                } else{
                    $username = trim($_POST["username"]);
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            $stmt->close();
        }
    }
    
    // 验证密码
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter a password.";     
    } elseif(strlen(trim($_POST["password"])) < 6){
        $password_err = "Password must have atleast 6 characters.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm password.";     
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($password_err) && ($password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
    
    // 在插入数据库之前检查输入错误
    if(empty($username_err) && empty($password_err) && empty($confirm_password_err)){
        
        // 准备一个插入语句
        $sql = "INSERT INTO users (username, password) VALUES (?, ?)";
         
        if($stmt = $mysqli->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bind_param("ss", $param_username, $param_password);
            
            // 设置参数
            $param_username = $username;
            $param_password = password_hash($password, PASSWORD_DEFAULT); // Creates a password hash
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 重定向到登录页面
                header("location: login.php");
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            $stmt->close();
        }
    }
    
    // 关闭连接
    $mysqli->close();
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sign Up</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Sign Up</h2>
        <p>Please fill this form to create an account.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $password; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $confirm_password; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <input type="reset" class="btn btn-secondary ml-2" value="Reset">
            </div>
            <p>Already have an account? <a href="login.php">Login here</a>.</p>
        </form>
    </div>    
</body>
</html>
<?php
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = $confirm_password = "";
$username_err = $password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证用户名
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter a username.";
    } elseif(!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))){
        $username_err = "Username can only contain letters, numbers, and underscores.";
    } else{
        // 准备一个选择语句
        $sql = "SELECT id FROM users WHERE username = :username";
        
        if($stmt = $pdo->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
            
            // 设置参数
            $param_username = trim($_POST["username"]);
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                if($stmt->rowCount() == 1){
                    $username_err = "This username is already taken.";
                } else{
                    $username = trim($_POST["username"]);
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            unset($stmt);
        }
    }
    
    // 验证密码
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter a password.";     
    } elseif(strlen(trim($_POST["password"])) < 6){
        $password_err = "Password must have atleast 6 characters.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm password.";     
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($password_err) && ($password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
    
    // 在插入数据库之前检查输入错误
    if(empty($username_err) && empty($password_err) && empty($confirm_password_err)){
        
        // 准备一个插入语句
        $sql = "INSERT INTO users (username, password) VALUES (:username, :password)";
         
        if($stmt = $pdo->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
            $stmt->bindParam(":password", $param_password, PDO::PARAM_STR);
            
            // 设置参数
            $param_username = $username;
            $param_password = password_hash($password, PASSWORD_DEFAULT); // Creates a password hash
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 重定向到登录页面
                header("location: login.php");
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            unset($stmt);
        }
    }
    
    // 关闭连接
    unset($pdo);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sign Up</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Sign Up</h2>
        <p>Please fill this form to create an account.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $password; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $confirm_password; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <input type="reset" class="btn btn-secondary ml-2" value="Reset">
            </div>
            <p>Already have an account? <a href="login.php">Login here</a>.</p>
        </form>
    </div>    
</body>
</html>

— 上述示例的输出(即注册表单)将如下所示:

PHP MySQL Sign Up Form

在上面的示例中,我们使用了 PHP 的内置 password_hash() 函数从用户输入的密码字符串创建密码哈希(line no-78)。 此函数使用强大的单向散列算法创建密码散列。 它还会在对密码进行哈希处理时自动生成并应用随机盐; 这基本上意味着即使两个用户拥有相同的密码,他们的密码哈希值也会不同。

在登录时,我们将使用 PHP password_verify() 函数使用存储在数据库中的密码哈希来验证给定密码,如下一个示例所示。

我们使用 Bootstrap 框架快速而美观地制作 表单布局。 请查看 Bootstrap 教程 部分以了解有关此框架的更多信息。

提示: 密码加盐是一种广泛用于通过随机化密码哈希来保护密码的技术,这样如果两个用户拥有相同的密码,他们将不会拥有相同的密码哈希。 这是通过在散列之前向密码附加或附加一个称为盐的随机字符串来完成的。


构建登录系统

在本节中,我们将创建一个登录表单,用户可以在其中输入他们的用户名和密码。 当用户提交表单时,这些输入将根据存储在数据库中的凭据进行验证,如果用户名和密码匹配,则用户被授权并被授予访问站点的权限,否则登录尝试将被拒绝。

第 1 步:创建登录表单

让我们创建一个名为"login.php"的文件并将以下代码放入其中。

示例

Procedural Object Oriented PDO
Download
<?php
// 初始化session会话
session_start();
 
// 检查用户是否已经登录,如果是则将他重定向到欢迎页面
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
    header("location: welcome.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = "";
$username_err = $password_err = $login_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 检查用户名是否为空
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter username.";
    } else{
        $username = trim($_POST["username"]);
    }
    
    // 检查密码是否为空
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter your password.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证凭据
    if(empty($username_err) && empty($password_err)){
        // 准备一个选择语句
        $sql = "SELECT id, username, password FROM users WHERE username = ?";
        
        if($stmt = mysqli_prepare($link, $sql)){
            // 将变量作为参数绑定到准备好的语句
            mysqli_stmt_bind_param($stmt, "s", $param_username);
            
            // 设置参数
            $param_username = $username;
            
            // 尝试执行准备好的语句
            if(mysqli_stmt_execute($stmt)){
                // 存储结果
                mysqli_stmt_store_result($stmt);
                
                // 检查用户名是否存在,如果存在则验证密码
                if(mysqli_stmt_num_rows($stmt) == 1){                    
                    // 绑定结果变量
                    mysqli_stmt_bind_result($stmt, $id, $username, $hashed_password);
                    if(mysqli_stmt_fetch($stmt)){
                        if(password_verify($password, $hashed_password)){
                            // 密码正确,所以开始一个新的会话
                            session_start();
                            
                            // 将数据存储在会话变量中
                            $_SESSION["loggedin"] = true;
                            $_SESSION["id"] = $id;
                            $_SESSION["username"] = $username;                            
                            
                            // 将用户重定向到欢迎页面
                            header("location: welcome.php");
                        } else{
                            // 密码无效,显示一般错误信息
                            $login_err = "Invalid username or password.";
                        }
                    }
                } else{
                    // 用户名不存在,显示一般错误信息
                    $login_err = "Invalid username or password.";
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            mysqli_stmt_close($stmt);
        }
    }
    
    // 关闭连接
    mysqli_close($link);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Login</h2>
        <p>Please fill in your credentials to login.</p>

        <?php 
        if(!empty($login_err)){
            echo '<div class="alert alert-danger">' . $login_err . '</div>';
        }        
        ?>

        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Login">
            </div>
            <p>Don't have an account? <a href="register.asp">Sign up now</a>.</p>
        </form>
    </div>
</body>
</html>
<?php
// 初始化session会话
session_start();
 
// 检查用户是否已经登录,如果是则将他重定向到欢迎页面
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
    header("location: welcome.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = "";
$username_err = $password_err = $login_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 检查用户名是否为空
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter username.";
    } else{
        $username = trim($_POST["username"]);
    }
    
    // 检查密码是否为空
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter your password.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证凭据
    if(empty($username_err) && empty($password_err)){
        // 准备一个选择语句
        $sql = "SELECT id, username, password FROM users WHERE username = ?";
        
        if($stmt = $mysqli->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bind_param("s", $param_username);
            
            // 设置参数
            $param_username = $username;
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 存储结果
                $stmt->store_result();
                
                // 检查用户名是否存在,如果存在则验证密码
                if($stmt->num_rows == 1){                    
                    // 绑定结果变量
                    $stmt->bind_result($id, $username, $hashed_password);
                    if($stmt->fetch()){
                        if(password_verify($password, $hashed_password)){
                            // 密码正确,所以开始一个新的会话
                            session_start();
                            
                            // 将数据存储在会话变量中
                            $_SESSION["loggedin"] = true;
                            $_SESSION["id"] = $id;
                            $_SESSION["username"] = $username;                            
                            
                            // 将用户重定向到欢迎页面
                            header("location: welcome.php");
                        } else{
                            // 密码无效,显示一般错误信息
                            $login_err = "Invalid username or password.";
                        }
                    }
                } else{
                    // 用户名不存在,显示一般错误信息
                    $login_err = "Invalid username or password.";
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            $stmt->close();
        }
    }
    
    // 关闭连接
    $mysqli->close();
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Login</h2>
        <p>Please fill in your credentials to login.</p>

        <?php 
        if(!empty($login_err)){
            echo '<div class="alert alert-danger">' . $login_err . '</div>';
        }        
        ?>

        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Login">
            </div>
            <p>Don't have an account? <a href="register.asp">Sign up now</a>.</p>
        </form>
    </div>
</body>
</html>
<?php
// 初始化session会话
session_start();
 
// 检查用户是否已经登录,如果是则将他重定向到欢迎页面
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
    header("location: welcome.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$username = $password = "";
$username_err = $password_err = $login_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 检查用户名是否为空
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter username.";
    } else{
        $username = trim($_POST["username"]);
    }
    
    // 检查密码是否为空
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter your password.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // 验证凭据
    if(empty($username_err) && empty($password_err)){
        // 准备一个选择语句
        $sql = "SELECT id, username, password FROM users WHERE username = :username";
        
        if($stmt = $pdo->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
            
            // 设置参数
            $param_username = trim($_POST["username"]);
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 检查用户名是否存在,如果存在则验证密码
                if($stmt->rowCount() == 1){
                    if($row = $stmt->fetch()){
                        $id = $row["id"];
                        $username = $row["username"];
                        $hashed_password = $row["password"];
                        if(password_verify($password, $hashed_password)){
                            // 密码正确,所以开始一个新的会话
                            session_start();
                            
                            // 将数据存储在会话变量中
                            $_SESSION["loggedin"] = true;
                            $_SESSION["id"] = $id;
                            $_SESSION["username"] = $username;                            
                            
                            // 将用户重定向到欢迎页面
                            header("location: welcome.php");
                        } else{
                            // 密码无效,显示一般错误信息
                            $login_err = "Invalid username or password.";
                        }
                    }
                } else{
                    // 用户名不存在,显示一般错误信息
                    $login_err = "Invalid username or password.";
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            unset($stmt);
        }
    }
    
    // 关闭连接
    unset($pdo);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Login</h2>
        <p>Please fill in your credentials to login.</p>

        <?php 
        if(!empty($login_err)){
            echo '<div class="alert alert-danger">' . $login_err . '</div>';
        }        
        ?>

        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
                <span class="invalid-feedback"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Login">
            </div>
            <p>Don't have an account? <a href="register.asp">Sign up now</a>.</p>
        </form>
    </div>
</body>
</html>

— 上述示例的输出(即登录表单)将如下所示:

PHP MySQL Login Form

第 2 步:创建欢迎页面

这是我们的"welcome.php"文件的代码,用户在成功登录后被重定向。

示例

Download
<?php
// 初始化session会话
session_start();
 
// 检查用户是否登录,如果没有则重定向到登录页面
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
    header("location: login.php");
    exit;
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Welcome</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; text-align: center; }
    </style>
</head>
<body>
    <h1 class="my-5">Hi, <b><?php echo htmlspecialchars($_SESSION["username"]); ?></b>. Welcome to our site.</h1>
    <p>
        <a href="reset-password.php" class="btn btn-warning">Reset Your Password</a>
        <a href="logout.php" class="btn btn-danger ml-3">Sign Out of Your Account</a>
    </p>
</body>
</html>

如果数据来自外部来源,例如匿名用户填写的表格,则存在可能包含用于发起跨站脚本 (XSS) 攻击的恶意脚本的风险。 因此,您必须使用 PHP htmlspecialchars() 函数对这些数据进行转义,然后再将其显示在浏览器中,以便它包含的任何 HTML 标记变得无害。

例如,在转义特殊字符后,字符串 <script>alert("XSS")</script> 变为 &lt;script&gt;alert("XSS")&lt;/script&gt;,浏览器不执行该字符串。

第 3 步:创建注销脚本

现在,让我们创建一个"logout.php"文件。 当用户单击注销或注销链接时,此文件中的脚本会破坏会话并将用户重定向回登录页面。

示例

Download
<?php
// 初始化session会话
session_start();
 
// 取消设置所有会话变量
$_SESSION = array();
 
// 销毁会话。
session_destroy();
 
// 重定向到登录页面
header("location: login.php");
exit;
?>

添加密码重置功能

最后,在本节中,我们将密码重置实用程序添加到我们的登录系统。 使用此功能登录的用户可以立即重置他们自己的帐户密码。

让我们创建一个名为"reset-password.php"的文件并将以下代码放入其中。

示例

Procedural Object Oriented PDO
Download
<?php
// 初始化session会话
session_start();
 
// 检查用户是否登录,否则跳转到登录页面
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
    header("location: login.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$new_password = $confirm_password = "";
$new_password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证新密码
    if(empty(trim($_POST["new_password"]))){
        $new_password_err = "Please enter the new password.";     
    } elseif(strlen(trim($_POST["new_password"])) < 6){
        $new_password_err = "Password must have atleast 6 characters.";
    } else{
        $new_password = trim($_POST["new_password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm the password.";
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($new_password_err) && ($new_password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
        
    // 更新数据库前检查输入错误
    if(empty($new_password_err) && empty($confirm_password_err)){
        // 准备更新语句
        $sql = "UPDATE users SET password = ? WHERE id = ?";
        
        if($stmt = mysqli_prepare($link, $sql)){
            // 将变量作为参数绑定到准备好的语句
            mysqli_stmt_bind_param($stmt, "si", $param_password, $param_id);
            
            // 设置参数
            $param_password = password_hash($new_password, PASSWORD_DEFAULT);
            $param_id = $_SESSION["id"];
            
            // 尝试执行准备好的语句
            if(mysqli_stmt_execute($stmt)){
                // 密码更新成功。 销毁会话,并重定向到登录页面
                session_destroy();
                header("location: login.php");
                exit();
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            mysqli_stmt_close($stmt);
        }
    }
    
    // 关闭连接
    mysqli_close($link);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Reset Password</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Reset Password</h2>
        <p>Please fill out this form to reset your password.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> 
            <div class="form-group">
                <label>New Password</label>
                <input type="password" name="new_password" class="form-control <?php echo (!empty($new_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $new_password; ?>">
                <span class="invalid-feedback"><?php echo $new_password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <a class="btn btn-link ml-2" href="welcome.php">Cancel</a>
            </div>
        </form>
    </div>    
</body>
</html>
<?php
// 初始化session会话
session_start();
 
// 检查用户是否登录,否则跳转到登录页面
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
    header("location: login.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$new_password = $confirm_password = "";
$new_password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证新密码
    if(empty(trim($_POST["new_password"]))){
        $new_password_err = "Please enter the new password.";     
    } elseif(strlen(trim($_POST["new_password"])) < 6){
        $new_password_err = "Password must have atleast 6 characters.";
    } else{
        $new_password = trim($_POST["new_password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm the password.";
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($new_password_err) && ($new_password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
        
    // 更新数据库前检查输入错误
    if(empty($new_password_err) && empty($confirm_password_err)){
        // 准备更新语句
        $sql = "UPDATE users SET password = ? WHERE id = ?";
        
        if($stmt = $mysqli->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bind_param("si", $param_password, $param_id);
            
            // 设置参数
            $param_password = password_hash($new_password, PASSWORD_DEFAULT);
            $param_id = $_SESSION["id"];
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 密码更新成功。 销毁会话,并重定向到登录页面
                session_destroy();
                header("location: login.php");
                exit();
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            $stmt->close();
        }
    }
    
    // 关闭连接
    $mysqli->close();
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Reset Password</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Reset Password</h2>
        <p>Please fill out this form to reset your password.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> 
            <div class="form-group">
                <label>New Password</label>
                <input type="password" name="new_password" class="form-control <?php echo (!empty($new_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $new_password; ?>">
                <span class="invalid-feedback"><?php echo $new_password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <a class="btn btn-link ml-2" href="welcome.php">Cancel</a>
            </div>
        </form>
    </div>    
</body>
</html>
<?php
// 初始化session会话
session_start();
 
// 检查用户是否登录,否则跳转到登录页面
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
    header("location: login.php");
    exit;
}
 
// 包含配置文件
require_once "config.asp";
 
// 定义变量并用空值初始化
$new_password = $confirm_password = "";
$new_password_err = $confirm_password_err = "";
 
// 提交表单时处理表单数据
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // 验证新密码
    if(empty(trim($_POST["new_password"]))){
        $new_password_err = "Please enter the new password.";     
    } elseif(strlen(trim($_POST["new_password"])) < 6){
        $new_password_err = "Password must have atleast 6 characters.";
    } else{
        $new_password = trim($_POST["new_password"]);
    }
    
    // 验证确认密码
    if(empty(trim($_POST["confirm_password"]))){
        $confirm_password_err = "Please confirm the password.";
    } else{
        $confirm_password = trim($_POST["confirm_password"]);
        if(empty($new_password_err) && ($new_password != $confirm_password)){
            $confirm_password_err = "Password did not match.";
        }
    }
        
    // 更新数据库前检查输入错误
    if(empty($new_password_err) && empty($confirm_password_err)){
        // 准备更新语句
        $sql = "UPDATE users SET password = :password WHERE id = :id";
        
        if($stmt = $pdo->prepare($sql)){
            // 将变量作为参数绑定到准备好的语句
            $stmt->bindParam(":password", $param_password, PDO::PARAM_STR);
            $stmt->bindParam(":id", $param_id, PDO::PARAM_INT);
            
            // 设置参数
            $param_password = password_hash($new_password, PASSWORD_DEFAULT);
            $param_id = $_SESSION["id"];
            
            // 尝试执行准备好的语句
            if($stmt->execute()){
                // 密码更新成功。 销毁会话,并重定向到登录页面
                session_destroy();
                header("location: login.php");
                exit();
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }

            // 关闭语句
            unset($stmt);
        }
    }
    
    // 关闭连接
    unset($pdo);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Reset Password</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        body{ font: 14px sans-serif; }
        .wrapper{ width: 360px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Reset Password</h2>
        <p>Please fill out this form to reset your password.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> 
            <div class="form-group">
                <label>New Password</label>
                <input type="password" name="new_password" class="form-control <?php echo (!empty($new_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $new_password; ?>">
                <span class="invalid-feedback"><?php echo $new_password_err; ?></span>
            </div>
            <div class="form-group">
                <label>Confirm Password</label>
                <input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>">
                <span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit">
                <a class="btn btn-link ml-2" href="welcome.php">Cancel</a>
            </div>
        </form>
    </div>    
</body>
</html>
Advertisements