PHP面向对象mysqli预处理语句登录校验失效问题求助
编辑说明:版主标记为“已有答案”的问题并未解答本疑问,Chris Haas给出了有效解答。
运行代码时持续返回用户名或密码无效提示,核心逻辑存在多处疏漏,原始代码如下:
<?php $configs = include('../hidden/config.php'); echo 'Hello from jslogin.php'; if(isset($_POST)){ /* Login values from user */ $username = $_POST['username']; $password = password_hash($_POST['password'], PASSWORD_DEFAULT); /* Define DB variables */ $db_host = $configs['db_host']; $db_user = $configs['db_user']; $db_password = $configs['db_password']; $db_name = $configs['db_name']; /* Connect to DB */ $dbc = new mysqli($db_host, $db_user, $db_password, $db_name) or die('Error connecting to Database.'); /* Prepare and bind the statements */ $stmt = $dbc->prepare("SELECT first_name FROM user_reg where username=? AND password=?"); $stmt->bind_param("ss", $username, $password); /* Execute prepared statements and interpolate parameterized values*/ $stmt->execute(); /* Get result and number of rows returned */ $result = $stmt->get_result(); $count = $result->num_rows; /* Check to see if statement returned 1 row and pass/fail accordingly and grab firstname*/ if($count == 1){ $firstname = $result; alert("$firstname Successfully Logged In."); }else { echo 'You need to enter a valid username and/or password!!!'; } }
问题根源
- 核心密码校验逻辑错误:
password_hash()每次执行会自动生成随机盐,相同明文密码多次哈希得到的结果完全不同。登录阶段直接对用户输入的密码做哈希,再和数据库注册时存储的哈希值做SQL等值匹配,永远无法匹配成功。 - 入口判断无效:
isset($_POST)恒返回真,即使没有POST请求提交也会进入登录逻辑,应该判断具体的用户名、密码提交字段是否存在。 - 函数调用错误:PHP无内置
alert()函数,该函数是前端JavaScript方法,直接在PHP中调用会触发未定义函数报错。 - 结果读取错误:登录成功分支直接把mysqli结果对象赋值给
$firstname变量,没有调用fetch方法从结果集中取出实际字段值,拿不到用户姓名。 - 错误处理不合理:数据库连接使用
or die()写法会屏蔽mysqli的详细错误信息,不利于排查问题。
修正后可运行代码
<?php $configs = include('../hidden/config.php'); echo 'Hello from jslogin.php'; // 仅在用户名、密码字段都提交时进入登录逻辑 if(isset($_POST['username'], $_POST['password'])){ /* 接收用户提交参数 */ $username = trim($_POST['username']); $password = $_POST['password']; // 登录阶段不要直接哈希用户输入的明文密码 /* 读取数据库配置 */ $db_host = $configs['db_host']; $db_user = $configs['db_user']; $db_password = $configs['db_password']; $db_name = $configs['db_name']; /* 连接数据库,开启异常模式方便排错 */ mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $dbc = new mysqli($db_host, $db_user, $db_password, $db_name); $dbc->set_charset('utf8mb4'); /* 仅根据用户名查询对应记录,不要在SQL中做密码匹配 */ $stmt = $dbc->prepare("SELECT first_name, password FROM user_reg where username=?"); $stmt->bind_param("s", $username); $stmt->execute(); $result = $stmt->get_result(); $user = $result->fetch_assoc(); // 先校验用户是否存在,再用password_verify验证密码哈希 if($user && password_verify($password, $user['password'])){ $firstname = $user['first_name']; // 输出JS弹窗需要拼接完整的script标签 echo "<script>alert('{$firstname} Successfully Logged In.');</script>"; }else { echo 'You need to enter a valid username and/or password!!!'; } }
关键实现说明
- 注册用户时,必须使用
password_hash($用户输入的明文密码, PASSWORD_DEFAULT)生成哈希值后存入数据库,禁止存储明文密码。 - 登录阶段禁止在SQL语句中做密码等值匹配,先通过用户名查出对应存储的哈希值,再传入
password_verify()做校验。 - 预处理语句已经可以防范SQL注入风险,不需要额外对用户输入做转义处理。
内容的提问来源于stack exchange,提问作者user2654953
相关产品推荐
相关产品推荐

