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 .
Related
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;
}
?>
As I was changing my MySQLi to PDO, I encountered an error when fetching hashed strings from my users table.
This was the code I used before:
CheckPassword VERIFIES VALID USING MYSQLI
$mysqli = new mysqli("localhost","_USER_","_PASS_","_DB_");
$username = '_USERNAME_';
$pass = '_PASSWORD_';
$sql = "SELECT * FROM `users` WHERE username='$username' LIMIT 1";
$result = $mysqli->query($sql);
if($assoc = $result->fetch_assoc()){
$db_pass = $assoc['userpass'];
require 'PasswordHash.php';
$hash_cost_log2 = 8;
$hash_portable = FALSE;
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
if($hasher->CheckPassword($pass, $db_pass)) {
echo "valid"; // VERIFIES VALID
} else {
echo "invalid";
}
}
The reason why I switched to PDO was to prevent SQL Injections.
But now: CheckPassword VERIFIES INVALID USING PDO
$pdo = new PDO('mysql:dbname=_DB_;host=localhost', '_USER_', '_PASS_',
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$username = '_USERNAME_';
$pass = '_PASSWORD_';
$stmt = $pdo->prepare('SELECT * FROM `users` WHERE username = :u LIMIT 1');
$stmt->bindParam(':u', $username);
$stmt->execute();
if($fetch = $stmt->fetch(PDO::FETCH_ASSOC)){
$db_pass = $fetch['userpass'];
require 'PasswordHash.php';
$hash_cost_log2 = 8;
$hash_portable = FALSE;
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
if($hasher->CheckPassword($pass, $db_pass)) {
echo "valid";
} else {
echo "invalid"; // VERIFIES INVALID
}
}
}
How is it that; MySQLi fetches the hashed string different compared to PDO? No matter what encryption I use for hashing the passwords, it CANNOT validate them as true when fetching using PDO, BUT only when fetching using MySQLi?
The reason because when you comparing the password that the user enter and the password that in the database , its different , the pass that the user enter to log in to his account is not hashed while the one in the database is , so we need a way to hash the entered pass and validate it with the already hashed pass in the database . How to do that ? here
This is an example from a code that i use in my Control panel :
<?php
// connect to your database
if(isset($_POST['btn-login']))
{
$User_name = $_POST['userlogin'];
$password_user = $_POST['pass'];
$FetchUserData = $conn->prepare("SELECT * FROM users WHERE userlogin = ?");
$FetchUserData->execute(array($User_name));
$FetchedData = $FetchUserData->fetch(PDO::FETCH_ASSOC);
if ($FetchedData)
{
$password = $FetchedData['userpassword']; // Save the fetched password inside variable
$isPasswordCorrect = password_verify($password_user, $password);
if( $password_user == $isPasswordCorrect )
{
$_SESSION['login_user']=$User_name;
header("location: home.php");
}
else
{
echo "Password is wrong":
}
}
else
{
echo "User is not exist ";
}
}
?>
This Code line is the code used to hash the enterd pass with the exist pass in the database :
$isPasswordCorrect = password_verify($password_user, $password);
Small explanation :
password_verify(parameterA,parameterB)
parameterA : The password that you want it to be validate .
parameterB : the password that you want it to be validated with .(
database that is stored in the database )
Hope this answer be helpful for you .
So I'm enabling users to create accounts with a username and password. I have managed to encrypt the password when a user creates a new account using:
$hash = password_hash($password, PASSWORD_BCRYPT);
However I'm having trouble with password_verify when logging in, could someone please help me with what I have? I know it's something like this:
password_verify($password, $hash)
But I don't know how to structure it or where to add it in the code. Thanks in advance. This is what I have:
<?php
if (isset($_GET["username"]) && isset($_GET["password"]) ){
$username = $_GET["username"];
$password = $_GET["password"];
$result = login( $username, $password);
echo $result;
}
function makeSqlConnection()
{
$DB_HostName = "";
$DB_Name = "";
$DB_User = "";
$DB_Pass = "";
$con = mysql_connect($DB_HostName,$DB_User,$DB_Pass) or die(mysql_error());
mysql_select_db($DB_Name,$con) or die(mysql_error());
return $con;
}
function disconnectSqlConnection($con)
{
mysql_close($con);
}
function login($username, $password)
{
$con = makeSqlConnection();
$sql = "select * from login where username = '$username' and password = '$password';";
$res = mysql_query($sql,$con) or die(mysql_error());
$res1 = mysql_num_rows($res);
disconnectSqlConnection($con);
if ($res1 != 0) {
return 1;
}else{
return 0;
}// end else
}// end of Function
?>
The general practice is as follows:
Fetch password hash from the database where the username = the inputted username.
If rows are found, then there's a user
Now you compare the inputted password against the hash stored in the database.
I'll outline the above flow in some pseudo code for you here:
$query = SELECT password FROM users WHERE username = '$username'
$data = FETCH_THE_DATA($query);
if(password_verify($USER_INPUTTED_PASSWORD, $data['password'])) {
// password is correct
} else {
// password is in-correct
}
Notes
Stop using mysql_* functions. The library is deprecated as it's unreliable and will be removed in future releases of PHP.
You're better off using PDO or MySQLi Prepared Statements
You should always read the manual - password_verify(), it states clearly that you compare the "user inputted password" against the hashed version which is stored in your database.
Since I'm feeling good and sleepy today, I'll write a bunch of codes.
This is an example how to use PDO with prepared statement. You will have to tweak it according to your needs and you have to check if the post/get not empty as well.
I prefer to use POST request for login so this example will use POST request..
This is my user class. Which use placeholders and binding instead of passing the parameters into the query directly. This will give some protections against SQL injection attack.
class User{
private $dbh;
function __construct(){
$this->dbh = new PDO("mysql:host=".DB_SERVER.";dbname=".DB_NAME.';charset=utf8mb4', DB_USER, DB_PASSWORD) or die('db connect error');
}
function create($username, $password){
$status = false;
try{
$stmt = "INSERT INTO login (username, password)
VALUES (?, ?)";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->bindParam(2, $password);
$status = $qry->execute();
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
public function getPassword($username){
$status = false;
try{
$stmt = "SELECT * FROM login WHERE username = ? LIMIT 1";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->execute();
$status = $qry->fetch(PDO::FETCH_ASSOC);
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
}
This is how to create the user. Note that I don't check if the username already exist. You can either implement it yourself or use unique index on username column provided that the collation is case insensitive.
I have also increased the cost from the default that is 10 and I defined PASSWORD_DEFAULT to be used because I want the PHP engine to always use the strongest available algorithm (currently bcrypt).
function hashPassword($password){
$password = password_hash($password, PASSWORD_DEFAULT,array('cost' => 16));
return $password;
}
$user = new User;
$_POST['password'] = hashPassword($_POST['password']);
if(!$user->create(trim($_POST['username']),$_POST['password'])){
echo 'Failed creating user';
}else{
echo 'User created';
}
This is how to verify the password.
$user = new User;
$getPassword = $user->getPassword(trim($_POST['username']));
if(!$getPassword){
echo 'Error fetching user';
}else{
if(!password_verify($_POST['password'], $getPassword['password'])){
echo 'Login failed';
}else{
echo 'Login successful';
}
}
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
I have to make a login system on my website, but my users don't have the same things on their sites so I will $_GET my users' customers_id (from database) in the URL when they are logged in.
But I cannot see how.
my login code is this.
<?php
$email = $_POST['user'];
$password= $_POST['pass'];
$login = $_POST['login'];
$user_custermers_id = $_GET['id'];
if($login == 'Login' || isset($login))
{
global $wpdb;
$get = mysql_query("SELECT * FROM das_custermer_users WHERE email = '$email' AND password ='" . md5($password)."'") or die(mysql_error());
$result = mysql_num_rows($get);
if($result == 0)
{
$msg = "Wrong E-mail or Password";
}
else
{
session_start();
$_SESSION['email'] = $email;
header("location: http://dashboard.tg.com");
}
}
?>
You're writing really bad and dangerous code. What if I catch $_POST['email'] and change it to '--;DELETE your_data_base; ?
You don't check what data you have and SQL injection is possible in your example.
if($login == 'Login' || isset($login))
this condition is without sense because if there is $login== 'login' then isset is TRUE so second OR condition is unneccesary
session_start();
you should move it to 1st line.
global is an old PHP syntax avoid it.
$user_custermers_id = $_GET['id']; this is really bad. You should cast to to int or use intval()
If I were you I would use PDO connection. PDO has PDOStatement::rowCount you can use this property to check if there are any rows.
PDO throws exceptions so mysql_errror() is not needed. mysql_num_rows() is deprecated as of PHP 5.5.0, and will be removed in the future so avoid it.
I found this sample in internet. This code should be also in try catch block to handle exceptions
$login = mysql_escape_string(trim($_POST['login']));
$pass = mysql_escape_string(trim($_POST['pass']));
$dbh = new PDO('mysql:host=localhost;dbname=mydatabase', 'user', 'pass');
$sth = $dbh->prepare("SELECT * FROM table WHERE login = ? AND pass = ?");
$sth->bindParam(1, $login);
$sth->bindParam(2, md5($pass));
$sth->execute();
if ($sth->rowCount() > 0)
{
// session stuff,
// refresh page
}