mysqli bind_result()/ only returning nul - php

I am having a fair bit of trouble with the mysqli's bind_result() and fetch() functions.
I have tried a few things including echoing the result of:
$sql->prepare()
$sql->bind_param()
$sql->execute()
$sql->bind_result()
and they were all returning true the only function that is returning false is $sql->fetch()
the mysqli connection info is as follows:
<?php
$mysqli = new mysqli('localhost','false','data','battlestar');
if (mysqli_connect_errno()) {
$siteOffline = 1;
$smarty->assign("Fail", "Site is offline");
}
?>
and the mysqli prepared statment that I am having trouble with is here:
$UID = "";
$userLevel = "";
if(isset($_POST['hidden'])){
$username = $_POST['username'];
$password = crypt($_POST['password']);
if($username != "" || $password != ""){
if($sql = $mysqli->prepare("SELECT UID, userLevel FROM users WHERE username=? AND password=?")){
$sql->bind_param('ss', $username, $password);
$result = $sql->execute();
$res = $sql->bind_result($UID, $userLevel);
$sql->fetch();
var_dump($sql->error_list);
echo $UID . ' ' . $userLevel;
var_dump($sql);
if($result == NULL){
$smarty->assign("error", "Username or password invalid, please try again");
}
else{
$smarty->assign("confirmation", "Logged in Sucessfully");
$_SESSION['UID'] = $UID;
$_SESSION['username'] = $username;
$_SESSION['loggedIn'] = 1;
$_SESSION['userLevel'] = $userLevel;
}
}
}
else{
$smarty->assign("error", "You must enter a username and password");
}
}
$smarty->assign("content", $smarty->fetch("login.tpl"));
require_once("footer.php");
?>
I am using php 5.4 and mysql 5.5
so my problem is that the fields that I select in the query and bind_result() only return NULL and I have been through the documentation of bind_result() over and over yet I can't seem to find a solution.
sorry if this is fairly obvious or has already been asked I did look at like 5 other posts but none of them were completely relational.
if any more data is needed please tell me what you need.

After reading whole your question through, the answer is clear - your query returned no results.
That's the very and the only reason for your variables to contain null.

If $sql->fetch() returns false, it means that error(s) occurred. If it returns null, it means "no more rows". Review the error by issuing var_dump($sql->error);.
Also, if you want to retrieve the data from fetch(), you should:
$sql->bind_result($UID, $userLevel);
while($sql->fetch()) {
printf ("%d (%s)\n", $UID, $userLevel);
}
Reference: mysqli_stmt::fetch on php.net

Related

Login system, converting mysqli to pdo error [duplicate]

This question already has answers here:
Can I mix MySQL APIs in PHP?
(4 answers)
PDO Return All Rows [duplicate]
(1 answer)
Closed 3 years ago.
I am trying to convert some MySQLi code to PDO for a Unity project. I am making a login system and I have already changed some of the MYSQLi into PDO, however I am getting an error on line 33:
Fatal Error: Call to undefined method PDOStatement::fetch_assoc()
I tried to find PDO's version of fetch_assoc and found this:
fetch(PDO::FETCH_ASSOC);
So I changed the line to
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
And now my Unity DBcontroller which has a "Debug.Log(www.downloadHandler.text" isn't returning anything and the login message isn't appearing... Could you wizards please advise me on where to go next? I guess I should say the script worked fine when I was using MySQLi, but I needed to convert it to PDO for this project. Here is the code below:
<?php
$servername = "***";
$username = "***";
$password = "***";
$dbname = "***";
//variables submitted by user
$loginUser = $_POST["loginUser"];
$loginPass = $_POST["loginPass"];
// Create Connection
$conn = new PDO("mysql:host=***;dbname=***",
"***",
"***",
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
//Check Connection
if(!$conn){
die("Connection failed.");
}
$sql = "SELECT password FROM users WHERE username = '" . $loginUser . "'";
$result = $conn->query($sql);
if ($result->fetchAll() > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
if($row["password"] == $loginPass){
echo "Login Success. Welcome ", $loginUser, "!";
}
else{
echo "Wrong Credentials.";
}
}
} else {
echo "Username does not exist.";
}
$conn = null;
?>
When you call fetchAll you fetch all the result rows from the query, so there is no data left when you call fetch. Since you only expect one row to be returned, you can just call fetch once instead:
if ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if($row["password"] == $loginPass){
echo "Login Success. Welcome ", $loginUser, "!";
}
else{
echo "Wrong Credentials.";
}
}
else {
echo "Username does not exist.";
}
Notes:
You are wide open to SQL injection and should use a prepared statement
You should not store passwords in plain text, instead use PHP's password_hash and password_verify to store and verify them
It is generally considered bad practice to distinguish between incorrect password and an invalid username. Use the same error message for both.
You should use something like this code to avoid these issues:
$sql = "SELECT password FROM users WHERE username = :username";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':username', $loginUser);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if(password_verify($loginPass, $row["password"])) {
echo "Login Success. Welcome ", $loginUser, "!";
}
else{
echo "Wrong Credentials.";
}
}
else {
echo "Wrong Credentials.";
}

Using Use prepared statements and parameterized queries in PHP and MySQLi [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 4 years ago.
I am learning how to use prepared statements in my simple login system to make it more secure.
I have followed a few different tutorials to get it working but cant get it to work. When i enter the username and password wrong it gives me the error. When i enter the username and password correct i still get the error.
What am i doing wrong?
I am new to this so apologies for any obvious errors.
I have also looked into hashing my password as it is being stored as plain text in the database at the moment but that will be my next step after i get this working.
Here is my code:
<?php
error_reporting(E_ALL); ini_set('display_errors', 1);
session_start(); // Starting Session
$error=''; // Variable To Store Error Message
if($SERVER['REQUESTMETHOD'] == 'POST') {
if (empty($POST['username']) || empty($POST['password'])) {
$error = "Enter Username and Password";
}
else
{
// Define $username and $password
$username = $_POST['username'];
$password = $_POST['password'];
//connect to database
include('dbconx.php');
}
$stmt = $con->prepare("SELECT * from admin where password=? AND username=?");
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$stmt->bind_result($id, $username, $password);
$stmt->store_result();
if($stmt->num_rows == 1) //To check if the row exists
{
$_SESSION['login_user'] = $username; // Initializing Session
header("location: confirm.php"); // Redirecting To Other Page
}
else {
$error = "Username or Password is incorrect";
}
mysqli_close($con); // Closing Connection
}
?>
You have your bound parameter arguments backwards. Your query binds password then username but your bind_param() uses $username then $password.
I've never been a fan of using the number of rows returned to determine existence. Instead, you can simply use fetch(). It will return a boolean value indicating whether or not there was a result.
For example
$stmt = $con->prepare('SELECT id from admin where password = ? AND username = ?');
$stmt->bind_param('ss', $password, $username); // note the order
$stmt->execute();
$stmt->bind_result($id);
if ($stmt->fetch()) {
$_SESSION['login_user'] = $username;
$_SESSION['login_user_id'] = $id; // probably important
header("Location: confirm.php");
exit; // always exit after a "Location" header
} else {
$error = "Username or Password is incorrect";
}
mysqli_stmt::store_result should be called before mysqli_stmt::bind_result, also you would need to call mysqli_stmt::seek_data and mysqli_stmt::fetch to get the result.
Example :
<?php
$db = new Mysqli(...);
$inputUsername = $_POST['username'] ?? '';
$inputPassword = $_POST['password'] ?? '';
$statment = $db->prepare('SELECT `id`,`username`,`password` FROM `admin` WHERE `username` = ?');
$statment->bind_param('s',$inputUsername);
$statment->execute();
$statment->store_result();
$statment->bind_result($id,$username,$password);
if($statment->num_rows) {
$statment->data_seek(0);
$statment->fetch();
/**
* this is not secure
* #see http://php.net/manual/en/function.password-hash.php
*/
if($inputPassword === $password) {
echo sprintf('Welcome, %s!',$username);
} else {
echo 'Incorrect password!';
}
} else {
echo sprintf('No such user with the given username (%s)',$inputUsername);
}
$statment->close();
$db->close();
Removed bind_result and store_result for get_result and fetch_assoc. It makes getting db records more flexible and stable.
Also added exit(); after redirection so no other codes will be executed after redirect command.
Typo in:
if (empty($POST['username']) || empty($POST['password']))
^ $POST should be $_POST instead.
$error is not being checked properly if empty or not. And still goes through mysqli functions block even if there is an error. Fixed that by creating an appropriate if statement that encloses the mysqli funtions block.
Also added proper indentation to the code for readability.
New Code:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
session_start(); // Starting Session
$error=''; // Variable To Store Error Message
$_POST['username'] = isset( $_POST['username'] ) ? $_POST['username'] : '';
$_POST['password'] = isset( $_POST['password'] ) ? $_POST['password'] : '';
if($_SERVER['REQUEST_METHOD'] == 'POST') {
if (empty($_POST['username']) || empty($_POST['password'])) {
$error = "Enter Username and Password";
}
else{
// Define $username and $password
$username = $_POST['username'];
$password = $_POST['password'];
//connect to database
include('dbconx.php');
}
if( $error == "" ) {
$stmt = $con->prepare("SELECT * from students where username=? AND password=?");
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows == 1) {
$row = $result->fetch_assoc();
$_SESSION['login_user'] = $row['username']; // Initializing Session
header("location: confirm.php");exit(); // Redirecting To Other Page
}
else {
$error = "Username or Password is incorrect";
}
mysqli_close($con); // Closing Connection
}
echo $error;
}
?>

why is $stmt -> num_rows returning 0 when login exists?

Making a login form and this is my first time using prepared statements. My issue is the num_rows keeps returning 0, despite entering the correct email and password that matches the email and password of my table. I tested that the connection works and the SQL statement works also, its just the num_rows is always 0.
PHP(without php tags and connection code):
$email = $_POST['email'];
$password = md5($_POST['password']);
if(!($stmt = $con->prepare("SELECT `email`, `password` FROM users WHERE `email` = ? AND `password` = ?")))
{
echo "Prepare failed: (" . $con->errno . ")" . $con->error;
}
else
{
echo " Query read \n";
$stmt->bind_param('ss', $email, $password);
$stmt->execute();
$stmt->store_result();
$num_of_rows = $stmt->num_rows;
$stmt->bind_result($email, $password);
echo $num_of_rows;
if($num_of_rows == 1) //To check if the row exists
{
echo "Exists";
if($stmt->fetch()) //fetching the contents of the row
{
echo "Exists";
$_SESSION['loggedin'] = true;
$_SESSION['message'] = "logged in";
$_SESSION['email'] = $email;
echo "Success!";
exit();
}
}
else
{
echo "Error";
}
}
Hopefully I've just forgotten something, but either way I am stumped.
Thanks in advance!
The value returned by num_rows may not be a valid count of rows returned until all of the rows are retrieved. That's the case for a mysqli_result. The documentation makes it appear that the num_rows function of a mysqli_stmt should be available immediately after a store_result.
Seems like the most reasonable explanation for the behavior is that the query did not return a row.
Documentation:
http://php.net/manual/en/mysqli-result.num-rows.php
http://php.net/manual/en/mysqli-stmt.num-rows.php
Why do we need to use num_rows at all? That just seems like a lot of unneeded clutter. We could just do the fetch. If it returns TRUE, we know there was at least one row returned. If it's FALSE, then zero rows were returned. No need to muck with num_rows.
If we are going to use store_result, its a good pattern to follow that with a free_result once we're done with the resultset
Also, do not use MD5 for password hash. And there's no need to return the password hash from the database, we can omit that from the SELECT list.
https://security.stackexchange.com/questions/19906/is-md5-considered-insecure
as mentioned ditch out, my_num_rows, and store_result, below works for me.
$email = $_POST['email'];
$password = $_POST['password'];
$arr = array();
$stmt = $db->prepare("SELECT email, password FROM users where email = :email
and password = :password");
$stmt->bindParam(":email", $password);
$stmt->bindParam(":password", $password);
$stmt->execute();
$arr = $stmt->fetchAll();
if(!$arr) exit('No rows');
print_r($arr);
$stmt = null;
You also want to fetch the results, like this:
$stmt->bind_param('ss', $email, $password);
$stmt->execute();
$stmt->store_result();
$stmt->fetch();
$num_of_rows = $stmt->num_rows;
$stmt->bind_result($email, $password);
echo $num_of_rows;

Why wont this check to see if a user exists?

I'm performing a query to check if a user exists before adding it to the database. If that result comes back then die and echo 'username already exists' but if it comes back empty then add the new user to the database.
For some reason it just adds a new user to the database anyway.
//If post was
if (isset($_POST['submit'])) {
// Check if username is blank
if (!isset($_POST['username']) || empty($_POST['username'])) {
echo "Username was blank<br />";
die();
} else {
$username = mysqli_real_escape_string($connection, $_POST['username']);
}
// Check if password is blank
if (!isset($_POST['password']) || empty($_POST['password'])) {
echo "Password was blank<br />";
die();
} else {
$password = mysqli_real_escape_string($connection, $_POST['password']);
$password2 = md5($password);
//echo $password;
}
// Check if email is blank
if (!isset($_POST['email']) || empty($_POST['email'])) {
echo "Email was blank<br />";
die();
} else {
$email = mysqli_real_escape_string($connection, $_POST['email']);
//$password = md5($password);
//echo $password;
}
//Check to see if username alread exsists
$query_check = "SELECT * FROM users WHERE user = '$username' LIMIT 1";
$result_check = mysqli_query($connection, $query_check);
if(count(mysqli_fetch_array($result_check)) === 1) {
echo "Username exists.";
die();
} else {
$query = "INSERT INTO users (user, pass, email) VALUES ('$username','$password2','$email');";
$result = mysqli_query($connection, $query);
if($result){ // returned TRUE, e.g. in case of a DELETE sql
$_SESSION["username"] = $username;
header("Location: ../profile.php");
} else { // returned FALSE
//echo "Error: " . mysqli_error($connection);
echo "Error during register <a href='../register.php'>Back To Register</a>";
die();
}
}
} else {
header("Location: ../index.php");
}
After taking a few minutes testing your code, found that you're using the wrong function.
mysqli_fetch_array():
Fetch a result row as an associative, a numeric array, or both
You're trying to fetch an associative array.
As opposed to mysqli_num_rows():
Gets the number of rows in a result
Replace (and which seems to have been taken from FĂ©lix's answer)
if(count(mysqli_fetch_array($result_check)) === 1)
with
if(mysqli_num_rows($result_check) == 1)
or
if(mysqli_num_rows($result_check) > 0)
Your original post contained:
if(mysqli_fetch_array($result_check) === 1)
which still stands to be the wrong method.
I even said to use mysqli_num_rows() in a comment, but nothing was said about it:
if(mysqli_num_rows($result_check) >0) and make sure $username is defined. We don't know how/where if it is even defined.
Now, if THAT fails, then your form element isn't named, and/or something else in your form is failing you.
I.e.: <input type="text" name="username">
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Error reporting should only be done in staging, and never production.
Regarding using MD5.
That isn't considered safe to use anymore, as far as password hashing goes.
That technology is old and is considered broken.
For password storage, use CRYPT_BLOWFISH or PHP 5.5's password_hash() function.
For PHP < 5.5 use the password_hash() compatibility pack.
Pulled from ircmaxell's answer which uses PDO with prepared statements and password_hash():
Just use a library. Seriously. They exist for a reason.
PHP 5.5+: use password_hash()
PHP 5.3.7+: use password-compat (a compatibility pack for above
All others: use phpass
Don't do it yourself. If you're creating your own salt, YOU'RE DOING IT WRONG. You should be using a library that handles that for you.
$dbh = new PDO(...);
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $dbh->prepare("insert into users set username=?, email=?, password=?");
$stmt->execute([$username, $email, $hash]);
And on login:
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $dbh->prepare($sql);
$result = $stmt->execute([$_POST['username']]);
$users = $result->fetchAll();
if (isset($users[0]) {
if (password_verify($_POST['password'], $users[0]->password) {
// valid login
} else {
// invalid password
}
} else {
// invalid username
}
Footnotes:
I noticed you are using headers.
You should add exit; after each header. Otherwise, your code may want to continue executing.
header("Location: ../profile.php");
exit;
and do the same for the other one also.
You're also using sessions. session_start(); isn't present in your posted and will fail if it isn't included; an insight.
here
if(mysqli_fetch_array($result_check) === 1) {
the value returned by mysqli_fetch_array won't be an integer but an array. You seem to want to count it:
if(count(mysqli_fetch_array($result_check)) === 1) {
In the case somehow two users would have been inserted for whatever reason, checking if count is greater than 0 may prevent a third one being inserted:
if(count(mysqli_fetch_array($result_check)) > 0) {

Having trouble logging a user in using PHP and PDO

From the PDO manual:
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
I have this code:
<?php
require 'core.inc.php';
if(isset($_POST['user']) AND isset($_POST['pass'])){
if(!empty($_POST['user']) AND !empty($_POST['pass'])){
$user = $_POST['user'];
$pass = $_POST['pass'];
require 'connect.inc.php';
$st = $db_pdo->prepare("SELECT id FROM users WHERE user=? AND pass=?");
$st->bindParam(1, $user);
$st->bindParam(2, $pass);
$st->execute();
$result = $st->fetchColumn();
if($st->rowCount() > 0){
$id_arr = $st->fetch();
$id = $id_arr[0];
$_SESSION['user_id'] = $id;
header('Location: edit.php');
} else { echo 'Username or password incorrect';}
} else { echo 'You must fill in all fields.';}
}
?>
The number of rows returned is always 0, as stated in the manual. No surprise there.
1) I want to log a user in and set his $_SESSION id to his user ID from a db.
2) I suck so much at PDO it's not even funny, I can't figure out what function to use to log the user in. If the number or rows is always 0, clearly the Username or password incorrect will appear all the time.
Try this :
try
{
$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$bdd = new PDO('mysql:host='.$host.';dbname=' . $dbname, $dbuser, $dbpassword, $pdo_options);
$request = $bdd->prepare('SELECT id FROM users WHERE user = :user AND pass = :password');
$request->execute(array('user' => $_POST['user'],
'password' => $_POST['pass']
));
$data = $request->fetch();
if ($data)
{
session_start();
$_SESSION['ID'] = $data['id'];
//you can run other verification here if you want
header('Location: edit.php');
}
else
{
echo 'Username or password incorrect';
}
$requete->closeCursor();
}
catch(Exception $erreur)
{
die('Login error : '.$erreur->getMessage());
}
Hope that helps .

Categories