使用mysqli_stmt_num_rows()验证用户凭证的无效判断排查
mysqli_stmt_num_rows()匹配行检查方式汇总 我需要在登录脚本中通过mysqli_stmt_num_rows()检查数据库是否存在匹配的用户凭证(至少1条匹配行,否则提示未注册),编写了21种判断方式,现根据测试结果(使用正确凭证时mysqli_stmt_num_rows()返回1,标记为FAILS的即为无效方式),整理出无效的检查方式如下:
无效检查方式编号
1、2、3、4、8、11、12、13、15、16、17、18、19、20
各无效方式的错误解析
编号1
if(!$num_rows = mysqli_stmt_num_rows($stmt)) //FAILS { die('Incorrect User Credentials!'); }
错误原因:运算符优先级问题,!优先级高于=,实际先执行!mysqli_stmt_num_rows($stmt),再将结果赋值给$num_rows。当返回1时,!1为false,条件不成立不会触发die,但逻辑完全颠倒——我们需要的是行数为0时触发提示,此写法判断逻辑错误。
编号2
if(!$num_rows==mysqli_stmt_num_rows($stmt)) //FAILS { die('Incorrect User Credentials!'); }
错误原因:$num_rows未初始化,默认值为null,!null结果为true,而PHP中true == 1为true,条件成立会错误触发die提示,逻辑完全错误。
编号3
if($num_rows!=mysqli_stmt_num_rows($stmt)) //FAILS { die('Incorrect User Credentials!'); }
错误原因:$num_rows未初始化为null,null != 1为true,条件成立错误触发die提示,属于无意义的比较。
编号4
if($num_rows!==mysqli_stmt_num_rows($stmt)) //FAILS { die('Incorrect User Credentials!'); }
错误原因:$num_rows未初始化为null,null !== 1为true,条件成立错误触发die提示,属于无意义的比较。
编号8
if($num_rows = mysqli_stmt_num_rows($stmt)=0)//FAILS { die('Incorrect User Credentials!'); }
错误原因:连续赋值操作非法,试图将0赋值给mysqli_stmt_num_rows($stmt)的返回值(函数返回值为右值,无法被赋值),最终$num_rows被赋值为0,条件成立错误触发die提示。
编号11
if(!mysqli_stmt_num_rows($stmt)) //FAILS { die('Incorrect User Credentials!'); }
错误原因:上下文代码未调用mysqli_stmt_store_result($stmt),导致mysqli_stmt_num_rows无法正确获取结果行数(实际返回0),此时!0为true会错误触发die;同时逻辑上该写法是行数为0时触发提示,但结果集未存储导致判断失效。
编号12
if(mysqli_stmt_num_rows($stmt)=FALSE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:使用赋值运算符=而非比较运算符,将FALSE赋值给函数返回值(非法操作),条件结果为FALSE,不会触发die,逻辑完全错误。
编号13
if(mysqli_stmt_num_rows($stmt)==FALSE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:PHP中1 == FALSE为false,条件不成立不会触发die;但上下文未存储结果集导致num_rows返回0,此时0 == FALSE为true会错误触发die,且松散比较易引发隐式类型转换问题。
编号15
if(!mysqli_stmt_num_rows($stmt)=TRUE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:运算符优先级问题,先执行mysqli_stmt_num_rows($stmt)=TRUE(非法赋值),再取反,条件结果为!TRUE即false,不会触发die,逻辑完全错误。
编号16
if(!mysqli_stmt_num_rows($stmt)==TRUE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:!mysqli_stmt_num_rows($stmt)即!1为false,false == TRUE为false,条件不成立不会触发die,且判断逻辑颠倒。
编号17
if(mysqli_stmt_num_rows($stmt)!=TRUE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:PHP松散比较下1 != TRUE为false,条件不成立不会触发die;逻辑错误——应判断行数是否小于1,而非和布尔值true比较。
编号18
if(mysqli_stmt_num_rows($stmt)!==TRUE) //FAILS { die('Incorrect User Credentials!'); }
错误原因:1 !== TRUE为true(整数和布尔值类型不同),条件成立错误触发die提示,错误地用严格比较判断行数有效性。
编号19
if(mysqli_stmt_num_rows($stmt)=NULL) //FAILS { die('Incorrect User Credentials!'); }
错误原因:使用赋值运算符=而非比较运算符,将NULL赋值给函数返回值(非法操作),条件结果为NULL,视为false不会触发die,逻辑完全错误。
编号20
if(mysqli_stmt_num_rows($stmt)==NULL) //FAILS { die('Incorrect User Credentials!'); }
错误原因:1 == NULL为false,条件不成立不会触发die;当无匹配行且未存储结果集时num_rows返回0,0 == NULL也为false,无法正确触发提示,逻辑错误。
上下文测试代码
$domain = trim($_POST['domain']); $domain_email = trim($_POST['domain_email']); $password_hashed = hash('sha256',trim($_POST['password'])); //Query DB. //Check if User already registered or not. mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); $conn = mysqli_connect("localhost","root","","buzz"); //mysqli_connect("server","user","password","db"); $stmt = mysqli_stmt_init($conn); //$sql = "SELECT id FROM domains WHERE password = ? AND (domain = ? OR domain_email = ?)"; $sql = "SELECT id FROM domains WHERE (domain = ? OR domain_email = ?) AND password = ?"; if(!mysqli_stmt_prepare($stmt,$sql)) { echo __LINE__; echo '<br>';//DELETE echo 'Mysqli Error: ' .mysqli_stmt_error(); //DEV MODE. echo '<br>'; echo 'Mysqli Error No: ' .mysqli_stmt_errno(); //DEV MODE. echo '<br>'; die('Login a Failure!'); } else { echo __LINE__; echo '<br>';//DELETE mysqli_stmt_bind_param($stmt,"sss",$domain,$domain_email,$password_hashed); mysqli_stmt_execute($stmt); mysqli_stmt_bind_result($stmt,$id); if(!mysqli_stmt_fetch($stmt)) //This triggers if credentials are wrong. { echo __LINE__; echo '<br>';//DELETE mysqli_stmt_close($stmt); mysqli_close($conn); die('Password fetching failed!'); } else { echo __LINE__; echo '<br>';//DELETE //if(!$num_rows = mysqli_stmt_num_rows($stmt)) //FAILS //if(!$num_rows==mysqli_stmt_num_rows($stmt)) //FAILS //if($num_rows!=mysqli_stmt_num_rows($stmt)) //FAILS //if($num_rows!==mysqli_stmt_num_rows($stmt)) //FAILS //if($num_rows = mysqli_stmt_num_rows($stmt)!=1) //WORKS //if($num_rows = mysqli_stmt_num_rows($stmt)!==1) //WORKS //if($num_rows = mysqli_stmt_num_rows($stmt)<1) //WORKS //if($num_rows = mysqli_stmt_num_rows($stmt)=0)//FAILS //if($num_rows = mysqli_stmt_num_rows($stmt)==0)//WORKS //if($num_rows = mysqli_stmt_num_rows($stmt)===0)//WORKS //if(!mysqli_stmt_num_rows($stmt)) //FAILS //if(mysqli_stmt_num_rows($stmt)=FALSE) //FAILS //if(mysqli_stmt_num_rows($stmt)==FALSE) //FAILS //if(mysqli_stmt_num_rows($stmt)===FALSE) //WORKS //if(!mysqli_stmt_num_rows($stmt)=TRUE) //FAILS //if(!mysqli_stmt_num_rows($stmt)==TRUE) //FAILS //if(mysqli_stmt_num_rows($stmt)!=TRUE) //FAILS //if(mysqli_stmt_num_rows($stmt)!==TRUE) //FAILS //if(mysqli_stmt_num_rows($stmt)=NULL) //FAILS //if(mysqli_stmt_num_rows($stmt)==NULL) //FAILS //if(mysqli_stmt_num_rows($stmt)===NULL) //WORKS { die('Incorrect User Credentials!'); } mysqli_stmt_close($stmt); mysqli_close($conn); echo __LINE__; echo '<br>';//DELETE echo 'password: ' .$password; echo '<br>'; echo 'hashed password: ' .$hashed_password; echo '<br>'; header('location: home_Template.php'); exit; }
内容的提问来源于stack exchange,提问作者Urgent Questioner

