Me again, more issues that I really can't find the cause off.
The below code is producing: "Issue" which means the first IF statement is false, should be true.
PHP:
function login($email, $password, $mysqli) {
//Use prepared statements to stop SQL Injection
if ($stmt = $mysqli->prepare("SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT = 1")) {
$stmt->bind_param('s', $email); //Bind "$email" to paramater
$stmt->execute(); //Execute the query
$stmt->store_result();
$stmt->bind_result($user_id, $email, $db_password, $salt, $perms); //get variables from result
$stmt->fetch();
$password = hash('sha512', $password.$salt); //hash the password with the unique salt
if ($stmt->num_rows == 1) { //If user exists
//Check that user account isn't locked
if (checkbrute($user_id, $mysqli) == true) {
//Account is locked, alert user
return false;
} else {
if ($db_password == $password) { //Check that passwords match
//matches
echo "matches";
}
}
} else {
echo "No user found!";
}
} else {
echo "Issue";
}
}
$email and $password are not blank, and the $mysqli is the database object. Any ideas?
I can't figure it out at all, all looks fine to me.
You should really add mysql error reporting. It would of told you there was an issue in your query near LIMIT = 1.
Query should be:
SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT 1
To add the error reporting, change the echo "issue"; to be:
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
Limit = 1 should be LIMIT 1. Here's the if corrected :
if ($stmt = $mysqli->prepare("SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT 1"))
Related
I'm making a basic registration system with the help of a tutorial; the tutorial doesn't say how to make it so that it verifies if an email the user tried to register with has been taken, but it does so for the username. How do I make it so that it verifies both the username and email are free and not in the database? And yes, I did enter my database details properly, I just removed them for this post.
(By the way, this is a register.php file which the site goes to after entering details and pressing enter in another webpage.)
<?php
$DATABASE_HOST = '';
$DATABASE_USER = '';
$DATABASE_PASS = '';
$DATABASE_NAME = '';
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if (mysqli_connect_errno()) {
die ('Failed to connect to MySQL: ' . mysqli_connect_error());
}
if ($stmt = $con->prepare('SELECT id, password FROM accounts WHERE username = ?')) {
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
die ('Email is not valid!');
}
if (preg_match('/[A-Za-z0-9]+/', $_POST['username']) == 0) {
die ('Username is not valid!');
}
if (strlen($_POST['password']) > 20 || strlen($_POST['password']) < 5) {
die ('Password must be between 5 and 20 characters long!');
}
$stmt->bind_param('s', $_POST['username']);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
echo 'Username exists, please choose another!';
} else {
if ($stmt = $con->prepare('INSERT INTO accounts (username, password, email) VALUES (?, ?, ?)')) {
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt->bind_param('sss', $_POST['username'], $password, $_POST['email']);
$stmt->execute();
echo 'You have successfully registered, you can now login!';
} else {
echo 'Could not prepare statement!';
}
}
$stmt->close();
} else {
echo 'Could not prepare statement!';
}
$con->close();
?>
Do it the same way you check if the username is already taken. Change your query to select id, password, email from accounts where username = ? or useremail = ?, make sure you add the email in bind_params and if it's already taken, you'll get a row.
Note that you won't be able to tell if the username is taken or if the email is. If you want to be able to tell, you may run two different queries, or compare results as follows.
Just fetch 1 row (limit 1) and if either the username or email address exists, notify the user. The code below should work.
$stmt = $con->prepare('select username, useremail from accounts where username = ? or useremail = ? limit 1');
$stmt->bind_param('ss', $_POST['username'], $_POST['useremail']);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($user_name, $user_email);
$stmt->fetch();
$stmt->close();
if ($user_name == $_POST['username']) {
// Username is taken
} else if ($user_email == $_POST['useremail']) {
// Email is taken
} else {
// Email and username are both available
}
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;
I am having troubles with a PHP login script which checks if you A.) Have registered then B.) Have you clicked the activation link (this is called active in my database)
function login($email, $password, $mysqli, $active) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, hash, active
FROM members
WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password, $salt, $active);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
if ($stmt->num_rows == 1) {
// If the user exists we check if the account is locked
// from too many login attempts
if (checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password . $user_browser);
if ($actve != 1){
return false;
header("location ../error.php?err=Account not activated");
exit();
}else{
return true;
header("location ../index.php");
exit();
}
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
if (!$mysqli->query("INSERT INTO login_attempts(user_id, time)
VALUES ('$user_id', '$now')")) {
header("Location: ../error.php?err=Database error: login_attempts");
exit();
}
return false;
}
}
} else {
// No user exists.
return false;
}
} else {
// Could not create a prepared statement
header("Location: ../error.php?err=Database error: cannot prepare statement");
exit();
}
}
function checkbrute($user_id, $mysqli) {
// Get timestamp of current time
$now = time();
// All login attempts are counted from the past 2 hours.
$valid_attempts = $now - (2 * 60 * 60);
if ($stmt = $mysqli->prepare("SELECT time
FROM login_attempts
WHERE user_id = ? AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $user_id);
// Execute the prepared query.
$stmt->execute();
$stmt->store_result();
// If there have been more than 5 failed logins
if ($stmt->num_rows > 5) {
return true;
} else {
return false;
}
} else {
// Could not create a prepared statement
header("Location: ../error.php?err=Database error: cannot prepare statement");
exit();
}
}
yes, I know I am using a template from wikihow. But somewhere in the code even if I set active to 0 or 1 in MySQL it logs you in whatever the value is but has an error msg account not activated. I do not know if there is a return true/false statement missing and I have been troubleshooting for days with no avail.
Without seeing how the login method is used it's hard to know for sure, but based on what you have shared the next thing I would try would be:
correct the typo if ($actve != 1){
Move the three calls that set username user_id and login_string on the $_SESSION in to the else block so that they only get set in the case of the password matching AND the $active variable being 1.
See what happens then.
I'm trying to make a login script for a project that I have. I came accross an open source and i typed some and copy/paste some. I went through the whole thing. I found that the login Function on the if statement where it says mysql->prepare is just skipping. I do not know if it is something with the database or an error on the script.
The place where I got the script was this
http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL
my test page is ertechs.t15.org is the login.php for logging in.
username is test_user#example.com and the password is 6ZaxN2Vzm9NUJT2y.
Thanks in advance.
and this is where i'm having the problem. this function
function login($email, $password, $mysqli) {
echo "Function login";
// Using prepared statements means that SQL injection is not possible.
$prep_smt = "SELECT id, username, password, salt FROM members WHERE email = ? LIMIT 1";
$smt = $mysqli->prepare($prep_smt);
if ($stmt)
{
echo "Tst passed";
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password, $salt);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
echo "password= =".$password;
if ($stmt->num_rows == 1) {
echo "row";
// If the user exists we check if the account is locked
// from too many login attempts
if (checkbrute($user_id, $mysqli) == true) {
echo "brute true";
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
echo "pass match";
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
echo "pass correct";
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/",
"",
$username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512',
$password . $user_browser);
// Login successful.
return true;
} else {
echo "Password Failed";
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts(user_id, time)
VALUES ('$user_id', '$now')");
return false;
}
}
} else {
echo "user doesnt exist";
// No user exists.
return false;
}
echo "whatever";
}
echo "end Function Login";
}
$smt = $mysqli->prepare($prep_smt);
if ($stmt)
Notice the missing t in $stmt?
I have this login and registration script from the net. Everything is working fine.
Objectives:
Usernames entered by the user will only be alphabets. If the username entered is not exist in the database, it will automatically add a number 1 on the username, example, user1.
Let's say the database have already had user1, user2, user3. Whenever a user entered user, it will then check what is the last incrementing number which in this case, it is 3, so it will then add into the database as user4.
Problems:
As I am trying to learn PDO as much as I could and it is still pretty difficult for me to understand. Also, I do not have any idea where should I start from.
Below are my current working code:
if (isset($_POST['submit'])) {
if(empty($_POST['username']) || empty($_POST['password'])){
$errors[] = 'All fields are required.';
}else if(!ctype_alpha($_POST['username'])){
$errors[] = 'Please enter only alphabet letters.';
}else{
if ($users->user_exists($_POST['username']) === true) {
$errors[] = 'That username already exists';
}
}
if(empty($errors) === true){
$username = htmlentities($_POST['username']);
$password = $_POST['password'];
$users->register($username, $password);
header('Location: register.php?success');
exit();
}
}
public function user_exists($username) {
$stmt = $this->db->prepare("SELECT COUNT(`id`) FROM `userinfo` WHERE `username`= ?");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
try{
$stmt->execute();
$rows = $stmt->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
die($e->getMessage());
}
}
public function register($username, $password){
$password = sha1($password);
$stmt = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->bindValue(2, $password, PDO::PARAM_STR);
try{
$stmt->execute();
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
Is there any kind souls out there can help me out on this? Letting me know where should I start and what should I do? Or the flow of the whole procedure in achieving my objectives.
Any help will be much appreciated! Thanks in advance.
Here is a example how to change your function to check if the user exist .. and which is the last index.
It is not pretty but will do the job and may be point you to the right ideas.
public function register($username, $password){
$password = sha1($password);
//check if the user exists and find first posible free index
$_username = $username;
if($this->db->query("SELECT * FROM `userinfo` WHERE `username` = 'user' ")){
$n = 1;
$max_index = 20;
while ($n < $max_index ) { //just to be safe
$_username = $username . $n;
if (!$this->db->query("SELECT * FROM `userinfo` WHERE `username` = '" . $_username . "' ")) {
break;
}
$n++;
}
if($n == $max_index){
die("Sorry ,there already (".$max_index.") entries of this username.");
}
}
//continue as normal just use $_username in the final query
$stmt = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$stmt->bindValue(1, $_username, PDO::PARAM_STR);
$stmt->bindValue(2, $password, PDO::PARAM_STR);
try{
$stmt->execute();
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
First of all you have to add a Sql-Wildcard like % _ * meaning see here to find all usernames they starts with "user" and have one or more charakter behind the "user"-string. Currently you only will get the username that excatly matchs the insert username.
But you could get some trouble by using the wrong wildcard, then
SELECT COUNT(id) FROM userinfo LIKE username = user%;
will always selct usernames like user1, user2, user3 but also something like userhorst..
To the pdo, the pdo help you to protect you system from sql injections. The prepare function sends only something like a query with wildcars for your parameter, thats means they send your statement without the parameters, to the Database. After this you send with the bindValue-function the single values to the Database. And finally you will excecute the statement. During this process the datapase can check each sended value for invalid signs.
Finally you have to check your if-statement. You will only get true when one user with the same name was in the database in all other cases (0,2,3,4,5,6,7) you get false.. But you want
if countUsers equal 0 then:
return false;
else
return true;
fi
Another part is you should thinking about using the sha1-hash, there are still better hashs to protect your passwords.
You can select all usernames like user* using:
SELECT username FROM `userinfo` WHERE username LIKE 'user%'
Next you should sort your results using asort:
asort($array_of_usernames);
then use substr or preg_match to get the number at the end of the username:
$number = substr($each_username, -1, 2) //within a foreach
Increment the number gotten then insert into database.
$new_username = "user" . $number++;
Thanks for the help guys!
Below are my current working code which I manage to tweak here and there based on the help given:
public function register($username, $password){
$stmt = $this->db->prepare("SELECT username FROM `userinfo` WHERE `username` LIKE :username");
$parse_username = "%".$username."%";
$stmt->bindValue(':username', $parse_username, PDO::PARAM_STR);
$stmt ->execute();
$user = $stmt->fetch();
$n = 1;
if($user){
$db_username = $user["username"];
$username_counter = preg_match("/".$username."(\d+)/", $db_username, $matches) ? (int)$matches[1] : NULL;
while ($n < $username_counter ) { //just to be safe
$new_username = $username . $n;
if (!$user) {
break;
}
$n++;
}
if($n == $username_counter){
$n++;
$new_username = $username.$n;
}
}else if(!$user){
$new_username = $username.$n;
}
$password = sha1($password);
$query = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$query->bindValue(1, $new_username);
$query->bindValue(2, $password);
try{
$query->execute();
$_SESSION['new_username'] = $new_username;
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
I am not sure that my way of coding is the best or professional, it is just based on my little logical knowledge of the flow. If there are any area where I can improve or rewrite, help me out if you wish to. =)