【问题标题】:The mysqli num_rows returns 0 from mysqli OOP stylemysqli num_rows 从 mysqli OOP 样式返回 0
【发布时间】:2017-10-08 02:04:36
【问题描述】:

我正在编写登录脚本并使用mysqli OOP 样式。我编写了echo 脚本来检查它是否获取了数据。结果是登录数据。但是当我想检查num_rows 时,即使我使用$stmt->store_result,它也会返回零。我在这个网站上搜索了很多线程,但它不起作用。 mysqli_num_rows 也不起作用。或者我只是错过了一些数据存储顺序?

这是我的代码。

<?php
require_once "condb.php";

if (!isset($_POST['LOGIN']))
  {header("Location:index.php");}

else
{

  $username=mysqli_real_escape_string($cn,$_POST['username']);
  $password=mysqli_real_escape_string($cn,$_POST['password']);
  $hashed_password=password_hash($password,PASSWORD_DEFAULT);

  $login = $cn->prepare("SELECT name,username,password,status
                       FROM login WHERE username=?");

  $login->bind_param("s", $username);
  $login->execute();
  $login->bind_result($name,$username,$password,$status);
  $login->store_result();
  $login->fetch();
  $count=$login->num_rows();

  echo $name."<br />".
  $username."<br />".
  $password."<br />".
  $status."<br />".$count;

/*Below here is if condition that I'll used when I finished solving this 
problem.*/

/*
if ($count > 0 )
{
   if(password_verify($password, $row['password']) && 
   $row['status']=="Admin")
   {
   echo "ok<br>You are Admin!";
   header("Location:admin/admin.php");
   $login->close();
   }elseif(password_verify($password, $row['password']) && 
    $row['status']=="Editor")
    {
      echo "ok<br>You are Editor!";
      $login->close();
    }elseif(password_verify($password, $row['password']) && 
    $row['status']=="Author")
    {
      echo "ok<br>You are Author!";
      $login->close();
     }
 else
 {
   echo "Username or password incorrect";
   $login->close();
   }
}
*/
}
?>

【问题讨论】:

  • 你忘记了密码
  • 我已经添加了。
  • 这条评论是根据我回答的最新代码。 Sname 是用户的全名,$username 是用户用来登录网站的名称。我得到的所有 4 个变量都不为空。我声称这是真的,因为我从 var_dump();mysqli-&gt;execute(); 看到了结果。

标签: php oop mysqli


【解决方案1】:
  • 如果你正在准备sql语句,不要再使用mysqli_real_escape_string(),因为准备过程已经暗示了转义。因此,通过使用准备好的语句,您在 MySQL 注入方面是安全的。
  • num_rows 不是方法,而是属性:$count = $login-&gt;num_rows;
  • 您应该使用异常处理以便能够捕获最终的错误。
  • 为变量、属性和方法使用具有意图的、可发音的名称。不要害怕提供长的。见Clean, high quality code guide。示例:dbconnection.php 代替 condb.php$connection 代替 $cn$statement 代替 $login

也许这些答案对你也有帮助。

祝你好运!

<?php

require_once 'condb.php';

/*
 * Enable internal report functions. This enables the exception handling, 
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions 
 * (mysqli_sql_exception). They are catched in the try-catch block.
 * 
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings. 
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

if (!isset($_POST['LOGIN'])) {
    header('Location: index.php');
    exit();
} else {
    try {
        $username = $_POST['username'];
        $password = $_POST['password'];

        $sql = 'SELECT 
                name,
                username,
                password,
                status 
            FROM login 
            WHERE username = ?';

        $statement = $connection->prepare($sql);
        $statement->bind_param('s', $username);
        $statement->execute();
        $statement->store_result();

        $count = $statement->num_rows;

        if ($count > 0) {
            $varsBound = $statement->bind_result($resultName, $resultUsername, $resultPassword, $resultStatus);

            $fetched = $statement->fetch();

            // For testing.
            var_dump($resultName);
            var_dump($resultUsername);
            var_dump($resultPassword);
            var_dump($resultStatus);

            if (password_verify($resultPassword, password_hash($password, PASSWORD_DEFAULT))) {
                switch ($resultStatus) {
                    case 'Admin':
                        echo 'You are an Admin!';
                        // header("Location: admin/admin.php");
                        // exit();
                        break;

                    case 'Editor':
                        echo 'You are an Editor!';
                        //...
                        break;

                    case 'Author':
                        echo 'You are an Author!';
                        //...
                        break;

                    default:
                        //...
                        break;
                }
            } else {
                echo 'Invalid password!';
            }
        } else {
            echo 'Invalid user name or no record found for the given user name!';
        }

        $statement->free_result();
        $statement->close();
        $connection->close();
    } catch (mysqli_sql_exception $e) {
        echo 'Error: ' . $e->getCode() . ' - ' . $e->getMessage();
        exit();
    } catch (Exception $e) {
        echo $e->getMessage();
        exit();
    }
}

/*
 * Disable internal report functions.
 * 
 * MYSQLI_REPORT_OFF: Turns reporting off.
 * 
 * See:
 *      http://php.net/manual/en/class.mysqli-driver.php
 *      http://php.net/manual/en/mysqli-driver.report-mode.php
 *      http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver->report_mode = MYSQLI_REPORT_OFF;

【讨论】:

  • 仍有改进的余地。此代码将受益于摆脱 password_hash 和 while。关于 bind_result 的说法也是错误的。更不用说根本不需要 num-rows
  • 不确定你的意思 这段代码将受益于摆脱 password_hash...
  • 我不知道如何摆脱while,你能告诉我/告诉我怎么做吗?我想说,使用num_rows 更好。谢谢。
  • 如果我使用num_rows,如果没有找到记录,我不会绑定任何结果。这是我通常更喜欢的选项。假设我只获取一个 $resUsername,它也可以是 NULL。不使用 num_rows 时,如何检查 NULL 是否仍不代表有效记录?至于你对我的理解:我一向尊重别人的任何意见。这并不意味着我同意所有观点。在这种情况下,我不同意你的观点。但你知道,这都是关于感知的。所以,也许你是对的。可以肯定的是:我总是有理由让我的代码膨胀。
  • 另一个我不同意的观点:我提供了另一个操作顺序 (store_result -> bind_result -> fetch),我知道这是正确的。除非我得到证明,证明订单不算数,否则我的回答是合法的。如果需要,我还提供了两个对提供验证和异常处理的代码的引用。而且,只要@PaoPaoMC 不提供任何反馈,您就无法确定是否引发了错误。再见。
【解决方案2】:

您的问题的答案很简单。如果(假设调用了store_result()),num_rows 返回 0,这意味着您的查询没有找到任何行。这真的很简单。无需寻找其他代码或责怪数据库。没有要获取的行?那么数据库中就没有这样的数据了。因此,要使您的查询返回某些内容,您需要确保$_POST['username'] 包含数据库中存在的值。

此外,我必须告诉你,这个函数/变量是 mysqli(或任何其他数据库 API)中最没用的部分。任何时候你需要它并且它可用时,它可以用你已经拥有的其他东西代替。在您的情况下,您可以检查 fetch() 的结果,这将完美地用于此目的。

话虽如此,我有一种感觉,即使有查询,一切都很好,而您的问题出在您正在使用的变量上。您正在使用一个不存在的 $row 变量,它显然不会返回任何内容。您是否在 PHP 中切换了正确的错误报告,它已经告诉您了。所以无论如何只要记住正确处理错误,你可以参考我的文章,PHP error reporting basics

所以,最后你的代码应该是这样的:

<?php

if (!isset($_POST['LOGIN'])){
    header("Location:index.php");
    exit;
}
require_once "condb.php";

$sql = "SELECT name,username,password,status FROM login WHERE username=?";
$stmt = $cn->prepare($sql);
$stmt->bind_param("s", $_POST['username']);
$stmt->bind_result($name,$username,$password,$status);
$stmt->execute();

if ($login->fetch() and password_verify($_POST['password'], $password) {
    if ($status=="Admin")
    {
        header("Location:admin/admin.php");
        exit();
    }
    echo "ok<br>You are $status!";
} else {
   echo "Username or password incorrect";
}

如您所见,您的代码中还使用了一些其他无用的函数,我也将其删除。你看,如果你让它只做它必须做的事情,PHP 代码可能会紧凑而整洁。

【讨论】:

  • 关于你的第一句话:不是真的。在您的代码中,例如没有store_result()num_rows 将显示0,即使记录的绑定值是有效的数据库值。
【解决方案3】:

我根据您的回答写了一些东西,如下所示。

<?php
error_reporting(E_ALL);
require_once "condb.php";

if (!isset($_POST['LOGIN']))
{header("Location:index.php");}

else
{

  $username=$_POST['username'];
  $receivedpassword=$_POST['password'];
  $hashed_password=password_hash($receivedpassword,PASSWORD_DEFAULT);

  $login = $cn->prepare("SELECT name,username,password,status
                         FROM login 
                         WHERE username=?");

  $login->bind_param("s", $username);
  $login->execute();
  $login->store_result();
  $login->bind_result($name,$getusername,$getpassword,$status);
  $login->fetch();
  $count=$login->num_rows;

  echo $name."<br />".$getusername."<br />".$getpassword."<br />".
  $status."<br />".$count."<br />";
  var_dump($name);echo "<br />";
  var_dump($getusername);echo "<br />";
  var_dump($getpassword);echo "<br />";
  var_dump($status);echo "<br />";
  var_dump($count);echo "<br />";
  // start checking a row

  if($count > 0)
  { // start of username check

    echo 'You are going good of your username.'."<br />";

    if(password_verify($receivedpassword, $getpassword))
    { // start of pw check

      echo 'Your password is going good!'."<br />";

      //start to check permission
      switch ($status)
      {// start of switch
        case 'Admin':
          echo 'You are admin.';
          break;
        case 'Editor':
          echo 'You are editor.';
          break;
        case 'Author':
         echo 'You are author.';
         break;
        case 'User':
          echo 'You are user.';
          break;
        default:
          echo 'NO PERMISSION FOUND.';
          break;
      }// end of switch

    } // end of pw check

    // else from pw verify
    else
    { // check of incorrect password
      echo 'Your password isn\'t going good.';
    } // end of incorrect password check

  } // end of username check

  // else from $count > 0
  else
  {// No username found condition check

    echo 'Your username isn\'t going good.';

  } // end of no username found

}//end of everything

?>

【讨论】:

  • @YourCommonSense 你所说的迷信和错误——顺便说一句:哪些错误? - 我叫经验。我真的希望,你会更灵活,对别人的意见和观点持开放态度。因为我喜欢您的整体建议、解决方案、教程等,所以很高兴再次收到您的来信。
  • 尽量不要在代码中使用太多的 cmets,因为它们可能会造成混淆。尤其是语句末尾的那些。
猜你喜欢
  • 1970-01-01
  • 2011-09-26
  • 2018-01-12
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
相关资源
最近更新 更多