A. Cedano said in a comment that I don't particularly like
num_rows
to know if there are rows in a result, sometimes it's not sure, and there are other better ways to know... but this is beside the point now, or maybe it is?
There is a question and an answer HERE but in PDO
I have two examples where I use
num_rows
based on the security that A. Cedano mentions and that there are other ways to know.
How can I display result rows safely using object oriented mysqli
What are the other better ways to find out?
examples
In the following code I use a num_rows;
to check if record exists or not to insert or update.
$result = $con->prepare("SELECT attempts FROM failed_attempt WHERE ip=? AND datetime BETWEEN DATE_SUB( NOW() , INTERVAL 1 DAY ) AND NOW()");
$result->bind_param("s",$addres);
$result->execute();
$result->store_result();
//Variable para saber si existe registro o no para insert o update.
$check_result = $result->num_rows;
if ($result->num_rows===1) {
//Obtenemos datos para comparar intentos y para resetear intentos por su ultimo fecha.
$result->bind_result($failed_login_attempt);
$result->fetch();
$result->close();
} else {
$result->close();
$failed_login_attempt=0;
}
In the code below I fetch the entered user, and also use anum_rows;
if(count($_POST)>0 && $captcha == true) {
$username = $_POST["username"] ?: '';
$password = $_POST["password"] ?: '';
//Buscar usuario ingresado - INICIO
$sql = $con->prepare("SELECT id_user,username,password,logindatetime, CASE WHEN logindatetime BETWEEN DATE_SUB( NOW() , INTERVAL 2 MINUTE ) AND NOW() THEN '1' ELSE '0' END as logueado FROM users where username=? AND active=? LIMIT 1");
$sql->bind_param("si",$username,$active);
$active=1;
$sql->execute();
$sql->store_result();
if ($sql->num_rows===1) {
$sql->bind_result($id_userBD,$usernameBD,$passwordDB,$logindatetime,$activeBD);
if ($sql->fetch()){
if (password_verify($password, $passwordDB)) {
$check_password = true;
} else {
$check_password = false;
}
} $sql->close();
} else {
$sql->close();
$check_password = false;
}
If you are looking for an alternative, to avoid
num_rows
, you could usefetch()
.An alternative example:
Second example:
Now, if you look closely at your statement at the end it puts
LIMIT 1
, that is, the number of records to return, in your case it can only be0
or1
.If you only need a specified number of rows from a result set, use a clause
LIMIT
in the query instead of searching the entire result set and discarding the extra data.The clause makes it
LIMIT
easy to code multiple pages of results or pagination withSQL
, and is very useful on large tables. Returning a large number of records can have a performance impact.Conclusion, in principle it should not give you problems
if ($result->num_rows===1) {
since you use 1 record as a limit in your sentence.Manual Limit Query Optimization
Logic:
If it were logical, in your statement
users
that you do not useLIMIT 1
, which I personally would add, in your statement you would buy where youusername
(FROM users where username=?
), if youBase de datos
are created correctly, said field should beunique
, that is, unique, there cannot be more than two , in principle younum_rows
should not fail either, since your comparison must check a single field and it will hardly find two equal records, the same email account, it should beunique
.Indeed, the comment:
is of my authorship.
Perhaps there is a confusion with the term safe used in my comment, which in that context, means that
num_rows
it doesn't always report the number of actual rows in a result set. That is, it is not certain that the value returned bynum_rows
is exactly the total number of rows. Now I understand that I should have used the term is not exact instead of not sure .My statement in that case does not refer to the vulnerability of the code, which does not depend on the use of
num_rows
, but on the way the query is sent to the database.Why
num_rows
is it not safe, that is, why is it not accurate?The three points I support are stated in the PHP Manual itself :
If we check the source code we will see that it is like this:
It doesn't work when used together with
LIMIT
andSQL_CALC_FOUND_ROWS
.What alternatives are there for
num_rows
?Alternative 1
If all you need is to know how many rows there are, the best way is to do this query:
Alternative 2
If, apart from knowing the number of rows, you need the information of the columns, you can do the normal query:
Then, you store the results in an associative array and count the rows applying
count
to the obtained array.test code
Let's see a test code with part of the statement.
Reading the
var_dump
and the results, we will see thatnum_rows
it is not always exact.VER DEMO
Result:
Let's take a closer look at buffered and unbuffered queries :
This implies or explains the doubt if the result is exact or not :
So in your case you are on the safe side , that is exact , since you use the stored result by default .
If you choose not to have results stored , it would be of no use to you
num_rows
!Now let's see the performance :
An example, if you have a table with many rows
(rows)
then what you donum_rows
is pass all those rows taken from the query (buffer) once again to the memory ofPHP
, if you useCOUNT()
in your query you pass only 1 result toPHP
.Benchmark buffered and unbuffered queries with and without
COUNT()
:Test environment:
Test code (simplified):
test_mysqli_with_buffer :
test_mysqli_without_buffer :
test_mysqli_count_with_buffer :
test_mysqli_count_without_buffer :
And the winner is....
Sources: