Hey I'm learning a new way of querying my databases because its meant to be better and more secure, this i building prepared statements that can be reused.
The problem is this is a different way of looking at it and im not used to it yet and still have some things that aren't clear to me.
So my script tries to bind three paras to a query to allow a user to login to my site. I am using the same script as before, this used user name and password... This works just fine:
$query = "SELECT *
FROM user
WHERE email = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query))
{
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
if($stmt->fetch())
{
//$uid = $stmt->fetch(id);
//$_SESSION['uid'] = $uid;
$stmt->close();
return true;
}
}
but when i check if the user is admin i doesn't like it at all:
$query = "SELECT *
FROM user
WHERE email = ? AND password = ? AND isAdmin = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query))
{
$stmt->bind_param('ssi', $un, $pwd, $isAdmin);
$stmt->execute();
if($stmt->fetch())
{
//$uid = $stmt->fetch(id);
//$_SESSION['uid'] = $uid;
$stmt->close();
return true;
}
}
Also i declare isAdmin as a global private var at the start of the class like so:
private $isAdmin = "1";
So yeah i know that the user i am testing has a 1 for isActive on the database but when it does into this script it returns false.
Like i said i'm new to this style of writing queries so any help would be amazing.
Thanks for the time.
Okay so i think i've got it. I added the isActive var to the function that is using it instead of it being global now it works fine.
Thanks for you help. Any other tips on the matter would be more than welcome!
Related
I have a simple problem whitch I can't solve, because I am starting with OOP and in the same time with MySQLi.
I need these function universal for everything and I need SET statement dynamically changed.
This is my update function these not working
public function updateUser($user, $pass, $dbSet) {
if($this->getUser($user, $pass) != NULL) {
$sql = $this->connection->prepare("UPDATE users SET ? WHERE user = ?");
$sql->bind_param('ss', $dbSet, $user);
$sql->execute();
$sql->close();
return true;
} else {
return false;
}
}
Variable $dbSet contains different values. For example:
$dbSet = "last_activity = ".$last_activity;
Or complex
$dbSet = "name = ".$newName.", surname = ".$newSurname.", email = ".$newEmail;
But when I change it for one SET statement, it works...
...
$sql = $this->connection->prepare("UPDATE users SET last_activity = ? WHERE user = ?");
...
I have made a prepared statement, supposed to login a user, everything works just fine, but I'm facing a problem with bind_result(). What I mean is that it is not working at all and I can't get the query's result and assign it to the SESSION
Here is my code:
session_start();
$sesUsername = "";
$sesCid = "";
$sesFirstName = "";
$sesLastName = "";
$mysqli = new mysqli($host_l, $username_l, $password_l, $dbName_l);
$loginQuery = "SELECT username, cid, first_name, last_name FROM Users WHERE username=? and password=?";
if($stmt = $mysqli->prepare($loginQuery)){
$stmt->bind_param('ss',$usernameEsc, $passwordEsc);
$stmt->execute();
/* Store the result (to get properties) */
$stmt->store_result();
/* Get the number of rows */
$num_of_rows = $stmt->num_rows;
/* Bind the result to variables */
$stmt->bind_result($sesUsername, $sesCid, $sesFirstName, $sesLastName);
if($num_of_rows == 1){
$_SESSION['username']= $sesUsername; // This is not working
return true;
}
else {
http_response_code(401);
}
/* free results */
$stmt->free_result();
/* close statement */
$stmt->close();
}
/* close connection */
$mysqli->close();
The code redirects me to the members area, but in there the session variable username is empty.
Why I can't get it working? I know that I'm missing something really small, but as a newbie, I can't spot the problem.
You have to do:
$stmt->fetch();
to get the results into the variables.
try this:
$stmt->bind_result($sesUsername, $sesCid, $sesFirstName, $sesLastName);
while ($stmt->fetch()) {
$_SESSION['username']= $sesUsername;
}
I';m working on changing my code from using MySQL to MySQLi, and its all seemed to be going fine, but I hit a bit of a wall, I'm currently stuck on changing over my function user_exists and I have tried looking into different reason why and what's going wrong but it seems to be the query, i did var_dump($result) and got the response NULL and was told that its down to my query then, so i tried an sql search on phpmyadmin and got a result so im thinking its down to me binding $username to the ? as the errors i get is of that it cannot find the username im trying to log in with.
function user_exists($username) {
$db = $GLOBALS['db'];
$username = trim($username);
//sql
$sql = "SELECT COUNT(`user_id`) FROM `users` WHERE `username` = ?";
//Prepare
$result = $db->prepare($sql);
//Bind
$result->bind_param('s', $username);
//execute
$result->execute();
//Bind-Results - the 2 codes below are noted out cause im not sure they are needed but have tried with and without them
//$result->bind_result($user_id);
//$result->fetch();
if (false === $result) {
return false;
}
return ($result->num_rows === 1);
}
i can provide the code to my signin.php but im not sure it would be useful as it all worked before i started changing the function.
if someone could point out what, where and why its not working, can you please explain so i can understand so Im good for the future and maybe able to help others out.
You need to call $result->store_result() before checking the number of rows. mysqli_stmt::store_result() will load the result set from the prepared statement so you can access results and properties.
EDIT: This is sort of how I would do it though (untested):
function user_exists($username) {
global $db;
//sql
$sql = "SELECT `user_id` FROM `users` WHERE `username` = ?";
//Prepare
if (!($result = $db->prepare($sql)) return false;
//Bind
if (!$result->bind_param('s', trim($username))) return false;
//execute
if (!$result->execute()) return false;
//Bind-Results
$result->bind_result($user_id);
$result->fetch();
$result->close();
return $user_id ?: false;
}
Here is how my user_exist() function ended up
function user_exists($username) {
$db = $GLOBALS['db'];
//sql
$sql = "SELECT user_id FROM `users` WHERE `username` = ?";
//Prepare
$result = $db->prepare($sql);
//Bind
$result->bind_param('s', $username);
//execute
$result->execute();
//store result
$result->store_result();
if (false === $result) {
return false;
}
return ($result->num_rows === 1);
}
I hope this will help someone. But if any of the code shouldn't be there, i apologise in advance, the code was there for a reason at one point but as im learning all this still, no one advised me that it shouldnt be there.. hope it helps
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 am fighting now like hours to figure out how to make possible to use SHA1 + PDO + Prepared Statement combination and still be able to log in to web page :) So my question is how to do so? Here is my code:
if (!empty($user) && !empty($password))
{
$password = $this->doHash($user, $password);
$stmt = $db_login->prepare("SELECT COUNT(*) FROM account WHERE username=:user AND sha_pass=:password");
$stmt->bindValue(':user', $user, PDO::PARAM_STR);
$stmt->bindValue(':password', $password, PDO::PARAM_STR);
$stmt->execute();
$results_login = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($results_login['COUNT(*)'] > 0)
{
$_SESSION['user_name'] = $results_login['username'];
$_SESSION['user_id'] = $results_login['id'];
return true;
}
else
{
return false;
}
}
else
{
return false;
}
My function doHash looks like this:
public function doHash($user, $password)
{
return sha1(strtoupper($user).":".strtoupper($password));
}
So my problems are: $results_login*** never processes with the SELECT COUNT(*) version, and with SELECT * version it processes sometimes, but not always. So how do I put it together to work as intended, result in true, and fill all the variables I need? Thank you.
Your SQL statement is only counting, it is not selecting the username and id, you would need to use this as your SQL statement, or something like it:
"SELECT * FROM account WHERE username=:user AND sha_pass=:password"
For your password binding, the following should work just fine. I would also use rowCount and only fetch, not fetchAll. Give this a try and see if it works.
$stmt->bindValue(':password', doHash($user,$password), PDO::PARAM_STR);
$stmt->execute();
if($stmt->rowCount()==1){
$results_login=$stmt->fetch(PDO::FETCH_ASSOC);
$_SESSION['user_name'] = $results_login['username'];
$_SESSION['user_id'] = $results_login['id'];
return true;
}else{
return false;
}