PHP Prepared Statement Result Array Not Finding Correct Value - php

the PHP below works fine in instances of insertion, but with a select query of bound parameters, not much luck has come through with the json reading. The application I'm creating now always returns false with the if statement evaluating the number of rows. I have a feeling the issue truly lies with the scope of the mysqli_stmt_store_result($query). The login credentials of the user do not work when attempting to login even though they are correct. Please let me know if more information is needed. The database connection is fine.
//parameter checking
$username = safe(stripslashes(trim($_POST['username'])));
$mypassword=hash('sha256', $salt.$_POST['password']);
//sanitize input parameters
function safe($value)
{
global $db;
$secureString = mysqli_real_escape_string($db, $value);
return $secureString;
}
//query check
$query= mysqli_prepare($db, "SELECT * FROM Users WHERE username =? AND password =? AND block_status < 1");
//$result=mysqli_query($db,$query);
mysqli_stmt_bind_param($query,'ss',$username,$mypassword);
mysqli_stmt_execute($query);
/* store result */
mysqli_stmt_store_result($query);
$query2="UPDATE Users SET last_login=NOW() WHERE username ='" . $username . "' AND password = '" . $mypassword . "'";
$result2=mysqli_query($db,$query2);
//if match found, create an array of data and json_encode it
if(mysqli_stmt_num_rows($query)>0)
{
$row=mysqli_fetch_array($query,MYSQLI_ASSOC);
$response=array(
'logged'=>true,
'name'=>$row['name'],
'email'=>$row['email']
);
echo json_encode($response);
}
else
{
$response=array(
'logged'=>false,
'message'=>'Invalid credentials or your access has been revoked'
);
echo json_encode($response);
}
/* free result */
mysqli_stmt_free_result($query);
/* close statement */
mysqli_stmt_close($query);
mysqli_close($db);
?>

According to the docs, you should be using mysql_stmt_store_result() before calling mysql_stmt_num_rows().
Also, you should use parameter binding for your UPDATE query, but only after you've confirmed a successful login.
I highly recommend PDO over MySQLi. The API is much cleaner and easier to understand. Here's how I would do it...
// assuming your user table has a primary key `id`
$stmt = $db->prepare('SELECT `id`, `name`, `email` FROM `Users` WHERE `password` = ? AND `username` = ? AND block_status < 1');
$stmt->execute(array($passwordHash, $username));
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user !== false) {
$response = array('logged' => true) + $row;
$update = $db->prepare('UPDATE `Users` SET `last_login` = NOW() WHERE `id` = ?');
$update->execute(array($row['id']));
} else {
$response = array(
'logged' => false,
'message' => 'Invalid credentials or your access has been revoked'
);
}
$stmt->closeCursor();
header('Content-type: application/json');
echo json_encode($response);
exit;

Related

SQL - Select doesn't retrieve results

I'm using sqlsrv_num_rows in order to check if a user exists in the DB.
When i'm running the query in my DB i'm getting 1 result, but in my PHP I'm not getting anything (echo doesn't print anything). Why is that?
$query = "SELECT TOP 1 id, tourOp FROM users WHERE (valid = 1) AND (email = '".trim($_POST['email'])."') AND (password = '".trim($_POST['password'])."')";
$stmt = sqlsrv_query( $conn, $query);
echo "num: ".sqlsrv_num_rows( $stmt );
if (!sqlsrv_num_rows( $stmt )) {
return (false);
} else {
}
Example query
SELECT TOP 1 id, name FROM users WHERE (valid = 1) AND (email = 'roi#some_email.com') AND (password = '8521')
I'm using PHP and MSSQL.
Explanations:
Function sqlsrv_num_rows() requires a client-side, static, or keyset cursor, and will return false if you use a forward cursor or a dynamic cursor (the default cursor is forward cursor). Execute sqlsrv_query() with additional $options parameter and set the appropriate cursor type with "Scrollable" => SQLSRV_CURSOR_KEYSET
Use parameterized statements. Function sqlsrv_query() does both statement preparation and statement execution and can be used to execute parameterized queries.
If you want to check if the result set has one or more rows, you may use sqlsrv_has_rows().
Example, based on your code:
<?php
$query = "
SELECT TOP 1 id, tourOp
FROM users
WHERE (valid = 1) AND (email = ?) AND (password = ?)";
$params = array(trim($_POST['email']), trim($_POST['password']));
$options = array("Scrollable" => SQLSRV_CURSOR_KEYSET);
$stmt = sqlsrv_query( $conn, $query, $params, $options);
if ($exec === false){
echo print_r( sqlsrv_errors());
echo "<br>";
return (false);
}
$count = sqlsrv_num_rows($stmt);
if ($count === false) {
echo print_r( sqlsrv_errors());
echo "<br>";
return (false);
} else {
echo "num: ".$count;
}
?>
Notes:
Do not send user credentials in plain text.

What could cause a PHP insert into a MYSQL database to wrongly insert data from another user into a row?

A student of mine was saving her score for a learning game to a MySQL database but somehow a different person's name ended up being stored in her database row. How is this possible? Here is the PHP for the insert.
// Get Configuration file
require "configenzymatic.php";
// Connect to your server
$dbh = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
///////////////////////////////////////////////////////
// Status Checker
///////////////////////////////////////////////////////
if ($_GET["status"]) {
echo "online";
exit;
}
///////////////////////////////////////////////////////
// Upload new score
///////////////////////////////////////////////////////
//set POST data as data to be checked and updated
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$email = $_POST['email'];
$password = $_POST['password'];
$level1right = $_POST['level1right'];
$level1wrong = $_POST['level1wrong'];
$level2right = $_POST['level2right'];
$level2wrong = $_POST['level2wrong'];
$level3right = $_POST['level3right'];
$level3wrong = $_POST['level3wrong'];
$level4right = $_POST['level4right'];
$level4wrong = $_POST['level4wrong'];
// check for email and set hash variable
$stm = $dbh->prepare("SELECT * FROM $tname WHERE email=?");
$stm->bindValue(1, $email, PDO::PARAM_STR);
$stm->execute();
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
$hashes = array($row['hash']);
$hash = $row['hash'];
$id = $row['id'];
foreach ($hashes as $hash) {
// If hash matches password, then...
if (password_verify($password, $hash)) {
// Everything is cool -- Insert the data into the database (update)
$stmt = $dbh->prepare("
UPDATE $tname
SET firstname = :firstname
, lastname = :lastname
, hash = :hash
, level1right = :level1right
, level1wrong = :level1wrong
, level2right = :level2right
, level2wrong = :level2wrong
, level3right = :level3right
, level3wrong = :level3wrong
, level4right = :level4right
, level4wrong = :level4wrong
WHERE email = :email
AND id = :id");
$stmt->execute(array($firstname, $lastname, $hash, $level1right, $level1wrong, $level2right, $level2wrong, $level3right, $level3wrong, $level4right, $level4wrong, $email, $id));
$affected_rows = $stmt->rowCount();
// check if row inserted
/* Return number of rows that were updated */
$count = $stmt->rowCount();
echo "$count";
}
}
}
The student inputted her name but someone else's name got inserted. I am totally baffled by this. Does anyone have any idea how this could occur? The person whose name was inserted in place of my student's added data at 12:30:44 today and my student added her data at 13:44:15. How did this data get mixed?
I'm not certain why you had your update wrapped in multiple loops, but it's entirely possible that users with the same password hash could exist, and (I think) would explain the behaviour you're seeing.
You are, presumably, looking to update the single user with the email and password submitted in the form? I assume you also have constraints on your table to ensure that email addresses are unique. So, you're grabbing the single user that matches that email, and checking their password. If it matches, update the single record with the same database ID. No loops!
// get password hash
$stm = $dbh->prepare("SELECT id, hash FROM $tname WHERE email=?");
$stm->execute([$_POST["email"]]);
$row = $stm->fetch(PDO::FETCH_ASSOC);
$hash = $row['hash'];
$id = $row['id'];
if (!password_verify($_POST["password"], $hash)) {
// verification failed, do something to present an error to the user
die();
}
$stmt = $dbh->prepare(
"UPDATE $tname
SET firstname=:firstname, lastname=:lastname,
level1right=:level1right, level1wrong=:level1wrong,
level2right=:level2right, level2wrong=:level2wrong,
level3right=:level3right, level3wrong=:level3wrong,
level4right=:level4right, level4wrong=:level4wrong
WHERE id=:id"
);
$stmt->execute([
":firstname" => $_POST["firstname"],
":lastname" => $_POST["lastname"],
":level1right" => $_POST["level1right"],
":level1wrong" => $_POST["level1wrong"],
":level2right" => $_POST["level2right"],
":level2wrong" => $_POST["level2wrong"],
":level3right" => $_POST["level3right"],
":level3wrong" => $_POST["level3wrong"],
":level4right" => $_POST["level4right"],
":level4wrong" => $_POST["level4wrong"],
":id" => $id
]);
$count = $stmt->rowCount();
echo "$count";
Also note that using named parameters in PDO requires the use of an associative array. Not sure how your original code would update anything at all without that.

getting session into each page

i want to insert into a table depending on the id of the session:
here the code in class.php:
public function activate($activation, $id,$change,$userID){
$stm1= $this->conn->prepare("INSERT INTO `log` (`date`,`change`) VALUES(CURRENT_TIMESTAMP(),'$change') WHERE `user_id` =$userID");
($stm1->execute());
$stmt = $this->conn->prepare("UPDATE `segments` SET `activation` = '$activation' WHERE `id` = '$id'")
or die($this->conn->error);
if ($stmt->execute()) {
$stmt->close();
$this->conn->close();
return TRUE;
}
}
at the top of the page i have this:
require './config.php';session_start();$userID = $_SESSION['user_id'];
and in action.php where the action go i have this:
$conn = new db_class();
$conn->activate($activation, $id,$change,$userID);
echo "Updated successfully.";
exit;
the first query insert into log is not working \ please help
This should be a comment but I don't have the rep yet...
Primarily, you don't do that type of insert with a WHERE clause. The insert will fail.
As an aside, that insert is open to sql injection. Bind your your parameters. Also, you should add error handling. If you had that, you would see the insert fails. Quick example (1 way...there are other ways...and I assumed $change is a string and $userId is an int...)
$sql = 'INSERT INTO log
SET `date` = CURRENT_TIMESTAMP(),
change = :change,
user_id = :user_id;';
$stmt = $this->conn->prepare( $sql );
$stmt->bindParam( ':change', $change, PDO::PARAM_STR );
$stmt->bindParam( ':user_id', $userID, PDO::PARAM_INT );
$result = $stmt->execute();
if (!$result) {
// failure -> get and handle the error
$error_array = $stmt->errorInfo();
} else {
// do something
}
The docs can help > pdo::execute, pdo::errorinfo

check if user exists with php and mysql stmt

I'm creating an authentification file with php and mysql, but I have this mistake in this line:
$stmt2->bind_param('ss',$twitter_id, $name);
The error message is
Call to a member function bind_param() on a non-object in ...
Where's my mistake?
$name in my database is a VARCHAR
$twitter_id in my database is a VARCHAR
$bd is my database connection
If a user is already registered, it should show me a message saying "User already registered", and if the user isn't registered, it should insert a new id and name in my database.
session_start();
if (!isset($_SESSION['userdata'])) {
header("location: index.php");
} else {
$userdata = $_SESSION['userdata'];
$name = $userdata->name;
$twitter_id = $userdata->id;
$stmt = $bd->prepare("SELECT ID_TWITTER FROM USERS");
$stmt->execute();
$stmt->bind_result($checkUser);
if ($stmt->fetch()) {
if($checkUser!==$twitter_id){
$cSQL = "INSERT INTO USERS (ID_TWITTER, FULL_NAME) VALUES(?,?)";
$stmt2 = $bd->prepare($cSQL);
$stmt2->bind_param('ss',$twitter_id, $name);
$stmt2->execute();
$stmt2->close();
} else {
echo "User already exits";
}
}
$stmt->close();
}
Could it be a typo? does $bd exist or should it be $db ?
Shameless plug: I do this exact thing in a project I have on github. Feel free to use the classes for whatever you like; they are mostly copy-pastable.
Your real issue is that $bd->prepare() returned false.
Check that you actually called it correctly and set it to new mysqli(*params)
The error Call to a member function ... on a non-object in ... means that $db is not an object, which means that it was not instantiated to an object. Thus, $this->method() isn't possible. bind_param(string $format, mixed &*vars); uses pass-by-reference and if this fails, it throws an error.
Try it yourself by sticking this in there:
$stmt->bind_param("ss", "string", "string");
To get around this issue where it can fail, check if $db->prepare() returns true:
if ($query = $bd->prepare($sql)) {
//stuff
}
In addition, in the first query you do it is probably not a good idea to be adding the overhead of a prepare for a single query that only checks row count without user input.
Solved : it works now
$stmt = $bd->prepare("SELECT ID_PROVIDER FROM USERS WHERE ID_PROVIDER = ?");
$stmt->bind_param('s', $twitter_id);
$stmt->execute();
$stmt->bind_result($checkUser);
while ($stmt->fetch()) {
$result = $checkUser;
}
if (empty($result)) {
$cSQL = "INSERT INTO USERS (ID_TWITTER, FULL_NAME)
VALUES(?,?)";
$stmt2 = $bd->prepare($cSQL);
$stmt2->bind_param('ss', $twitter_id, $name);
$stmt2->execute();
$stmt2->close();
}else {
echo "User already exits";
}

I'm a little confused, PHP says $results is a non-object of the mysqli class

I'm trying to fetch results using mysqli->fetch_row() (or fetch_object(), fetch_array()), yet when I go to run the code at run time it gives me the following error:
Fatal error: Call to a member function fetch_row() on a non-object in...on line 23.
The var in question that does this is $results in the code below. $user and $password gain their values from another .php file that this file is being included in so that's not really important at the moment. Now correct me if I'm wrong but if $results is being set = to $db->query($query) then isn't it supposed to inherit the properties of $db aka the mysqli class?
class mySQLHelper{
public function checkPass($user, $pass){
global $db;
$db = new mysqli();
$db->connect('localhost', 'root', '', 'mydb');
if (mysqli_connect_errno()){
echo 'Can not connect to database';
echo mysqli_connect_errno(). mysqli_connect_error();
exit;
return false;
}
$query = "SELECT user, password FROM Users WHERE user = $user AND password = $pass " ;
echo $query;
$results = $db->query($query);
while ($row = $results->fetch_row()){
echo htmlspecialchars($row->user);
echo htmlspecialchars($row->password);
}
$results->close();
$url = 'http://'. $_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])."/";
if(!$results){
// mysqli_close($db);
// header("Location:.$url.login.php&msg=1");
}
else{
// mysqli_close($db);
// header("Location:.$url.featured.php");
}
}
}
Your query is failing on this line:
$results = $db->query($query);
Because of this, $results is false - not a result object as you expect.
To fix the issue, you need to add quotes around your variables (or use prepared statements):
$query = "SELECT user, password FROM Users WHERE user = '".$user."' AND password = '".$pass."' " ;
I would suggest updating to use a prepared statement to prevent SQL-injection issues too though:
$stmt = $db->prepare('SELECT user, password FROM Users WHERE user = ? AND password = ?');
$stmt->bind_param('ss', $user, $pass);
$stmt->execute();
$results = $stmt->get_result();
You script is lacking error checking, and therefore the error in the query is not handled.
$query = "SELECT user, password FROM Users
WHERE user = '$user' AND password = '$pass' " ;
// ^ quotes needed
echo $query;
$results = $db->query($query);
// handle a error in the query
if(!$results)
die($db->error);
while ($row = $results->fetch_row()){
echo htmlspecialchars($row->user);
echo htmlspecialchars($row->password);
}
If you user & password field text or varchar, then you need to use single quote around them
$query = "SELECT user, password FROM Users WHERE user = '".$user."' AND password = '".$pass."' " ;
You have to check, if query runs properly:
if ($result = $mysqli->query($query))
{
}
Use: var_dump($results) to check what it contains
Why are you checking if($results) after trying to manipulate it?
This...
$results->close();
//...
if(!$results){
//...
}
Should be...
if(!$results){
//...
}
$results->close();

Categories