I've done a login and registration for my site and it works fine.
Now I just want to make a simple profile page where the user can see all their details.
I'm only able to get back the username, so I'm unsure how to get the rest of their details.
Here is the code for registering and logging in:
function selectUser($conn, $username, $password)
{
$query = "SELECT password FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_OBJ))
{
if (md5($password) == $row->password)
{
$_SESSION['username'] = $username;
//$_SESSION['password'] = $password; DO NOT DO THIS
echo "Welcome, you are now logged in as " . $username;
return true;
}
return false;
} else {
//echo "Your details were not found";
return false;
}
}
function selectNew($conn, $name, $username, $password, $contact, $occupation, $role, $picture)
{
$query = "INSERT INTO login VALUES (NULL, :name, :username, :password, :contactNumber, :occupation, :role, :pic)";
$stmt = $conn->prepare($query);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':username', $username);
$stmt->bindValue(':password', $password);
$stmt->bindValue(':contactNumber', $contact);
$stmt->bindValue(':occupation', $occupation);
$stmt->bindValue(':role', $role);
$stmt->bindValue(':pic', $picture);
$affected_rows = $stmt->execute();
if ($affected_rows == 1)
{
return true;
} else {
return false;
}
}
Don't worry, the password has been hashed.
heres what I've tried:
function selectUser($conn, $username, $password)
{
$query = "SELECT * FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
$row = $stmt->fetch();
echo $row['occupation'];
echo $row['role'];
}
2nd attempt:
if(isset($_SESSION["username"]))
{
echo "Welcome, you are now logged in as <b>".$_SESSION['username']."</b> <img class='clientView' src='images/loginIcon.png' alt='client'>"; }
else {
echo "You are currently not logged in";
}
$user = $_SESSION["username"];
$query = "SELECT * FROM login WHERE username = :username";
$term = $conn->prepare($query);
$term->bindValue(':username', $user);
$term->execute();
if ($username = $term->fetch(PDO::FETCH_OBJ))
{
echo "<li><h3>" . $user->username ." ". $user->user_ID . "</h3></li>";
}
The simple answer is to replace your query in selectUser(...) with SELECT * FROM login WHERE username = :username. Note the * after the SELECT command, which functions as a wild card and thus asks for every single column of each row it finds (instead of just the password column as you are currently asking for.
You could then, as you iterate over the returned rows, access other columns of the user via your $row variable. Just like you access the user's hashed password with $row->password, you could access $row->contactNumber.
A note about good practice:
Depending on the case, I would not recommend doing a wildcard (*) SELECT command at login. In fact, I would recommend simply hashing the password prior to the query and attempting to then qualify your query with WHERE username = :username AND password = :password (obviously, bind the hashed password to :password). Instead of asking for the password column, or wildcard columns, you could SELECT the row's unique ID.
This way, you don't even need to iterate over the returned rows at all...you only have to make sure any row returned (see num_rows) to see if the user can be successfully "logged in". You can then cache the returned row's unique ID into your session, and then do subsequent queries as necessary for other pieces of information...such as the user's role or contact number. This effectively brings the complexity of all of your query processing down from linear time to constant time...a minor, but still non-trivial, improvement for an application.
Also, as a word of warning, this login system is very simple and easily spoofed. PHP sessions provide some security, but they are not full-proof. A sniffer snagging the session cookie will allow them to log in as the user whom they sniffed it from. I would recommend looking into adding in your own session layer as well once you have the rest of your login system implemented. And absolutely use SSL.
A note about optimization:
Using a wildcard (*) in a SELECT command is actually a prime place for a speed bottleneck to occur. If you know exactly what columns you want from the database, it is best to ask for them explicitly. For example, instead of *, you could do password,occupation,role.
$_SESSION['username'] = $username;
You have user name in session right.
Just pass this value in where condition of mysql .and get the entire record from login table .just show where ever you want to show.
You can change your SELECT statement to return the other values you want to store in your $_SESSION variables and then access them each with $row->{variable}
Just make sure you populate the $_SESSION after you do your password check
Not dissimilar to your existing code - use the session variable you set when the user logs in
$username=!empty( $_SESSION['username'] ) ? $_SESSION['username'] : false;
$sql='select * from `login` where `username`=:username;';
$stmt=$conn->prepare( $sql );
if( $stmt && $username ){
$stmt->bindValue(':username',$username);
$result=$stmt->execute();
if( $result ){
$rs=$stmt->fetchAll( PDO::FETCH_OBJ );
/* display results from $rs */
/*
There should most likely only be one record!!
*/
$row=$rs[0];
foreach( $row as $column => $value )echo $column.' '.$value;
}
}
Related
This question already has an answer here:
Verifying password_hash() in PDO prepared statements
(1 answer)
Closed 7 months ago.
how I can put my variable $passHash from register function to login function
I need that cause I try to use password_verify() method which required my hash
I try additional got my hashe password from database and put to the password_verify() but it not working.
public function register($uname, $email, $pass) {
$passHash = password_hash($pass, PASSWORD_DEFAULT);
$sqlQuery="INSERT INTO UserData (userName, userEmail, userPassword) VALUES (:userName,:userEmail,:userPassword)";
$stmt = $this->db->prepare($sqlQuery);
$stmt->bindparam(':userName', $uname);
$stmt->bindparam(':userEmail', $email);
$stmt->bindparam(':userPassword', $passHash);
if($stmt->execute()) {
return true;
} else {
return $stmt->error;
}
}
public function login($emailUser,$passUser){
$sqlQuery= "SELECT * FROM UserData WHERE userEmail=? AND userPassword=? ";
// $sqlQuery.Id;
$stmt = $this->db->prepare($sqlQuery);
$stmt->execute([$emailUser, $passUser]);
$result = $stmt->fetch(PDO::FETCH_ASSOC); <-- NOT WORKING SO I try get hash variable from register function
$checkPassword=password_verify($passUser,$result["userPassword"]);
if($checkPassword==true){
if($stmt->rowCount()==0){
echo "err";
}else{
echo "success";
}
}else{
echo 'bad pass';
}
}
Steps to run a successful login attempt:
Collect the username/identifier from the login client.
$emailUser = $_POST['email'];
$passUser = $_POST['password'];
Send only that to the MySQL to retrieve only that row, including the hashed password and the row identifier.
SELECT UserId, userPassword FROM UserData WHERE userEmail=?
Using PHP check the hashed password from the database matches the value given by the user
if(password_verify($passUser, $result['userPassword']){
...
allow access....
NEVER send the password to MySQL, it's worthless.
Use $stmt->fetchAll(); to retrieve the data row
It is bad practise to do SELECT * instead you should select the columns you actually want to use.
your $stmt->rowCount()==0 clause will always fail, because it is after the password has been tested and passed, so remove this whole section.
It is bad practise to tell people specifically their password has failed, as this can be used to fish for if someone has an email on this system. Instead state "Your email OR password are incorrect" so it can't so easily be established by 3rd parties if a certain persons email is on a system.
I have a PHP script using PDO where I check a user's submitted email/password against a database. If the query returns a row, it is supposed to take the user to a success page, or if the credentials are incorrect they are supposed to be taken to a failed login page. However, the user is always taken to the fail page.
$sql = "SELECT email, password FROM user WHERE email= $email AND password = $password";
$stm = $db->prepare($sql);
$stm->execute();
$result = $stm->fetchColumn();
if ($result !== FALSE) {
header('Location: ./success.html');
}
else {
header('Location: ./failed.html');
}
Your original problem was simply missing quotes around the variables inserted into the query.
Just fixing that problem would leave you vulnerable to SQL injection attacks. Making proper use of statement preparation and execution will solve that problem. And never, never, store plaintext passwords. When you save them, use password_hash and then use code like this to verify them.
$password = $_POST["password"];
$email = $_POST["email"];
$sql = "SELECT password FROM user WHERE email= ?";
$stm = $db->prepare($sql);
$stm->execute([$email]);
$result = $stm->fetchColumn();
if ($result !== FALSE) {
if (password_verify($password, $result[0])) {
header("Location: ./success.html);
exit;
}
}
header("Location: ./failed.html");
More details on password hashing can be found elsewhere on SO.
And please note that for brevity I'm not checking the result of the prepare() or execute() functions. You should be doing this.
I am writing a deliberately vulnerable web application. I'd like to figure out how to check username and password, matching against the database and each other as well.
So: if the username exists in the database and the password exists in the database and the username and password belongs together. I'm fully aware how to send a query which checks for both at the same time and returns either true or false, so please don't start on that. My goal is to individually check for both so I can inform the user which one is not working.
Here's my code but as I'm not really a PHP person this is obviously not working:
<?php
if(isset($_POST["submit"])){
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);
$sql_username = "SELECT id FROM users WHERE username = '$username'";
$sql_password = "SELECT id FROM users WHERE password = '$password'";
$result_username = mysqli_query($conn, $sql_username);
$result_password = mysqli_query($conn, $sql_password);
$row_username = mysqli_fetch_array($result_username);
$row_password = mysqli_fetch_array($result_password);
$count_username = mysqli_num_rows($result_username);
$count_password = mysqli_num_rows($result_password);
if($count_username > 0 && $count_password < 0) {
echo "Invalied password";
} else if ($count_username < 0 && $count_password > 0) {
echo "Invalied username";
} else {
"Welcome";
}
}
?>
Any hints?
Edit
$conn can be used as I'm getting it from another php file.
<?php
//set up a connection and all that prerequisite stuff
$sqlConnectionNameHere = new mysqli($sql_host, $sql_username, $sql_password, $sql_dbname);
$username = 'bob'; //the username that will be checked
$password = 'securepassword1'; //the password that will be checked
$query = $sqlConnectionNameHere->query("SELECT username, password FROM users WHERE username='$username' LIMIT 1"); //make your query
if ($query->num_rows != 1){ //if the datbase didn't return any rows, the user with $username must not exist
die('User not found!');
}
while ($user = $query->fetch_assoc()){
if ($user['password'] != $password){
die('Invalid Password');
}
}
//if they've made it here, the user exists and the password matches!
echo 'Welcome!';
?>
This is a really barebones way of doing it. You may want to add more security to this.
Hope this helps. Best of luck to you!
I know its way cooler to let the user know wether the username or password is wrong. But this actually helps get unwanted indivuduals to pass this test. Since they can test if a specific user is present or not. From there this individual would bruteforce the password. So its a good practice to just check for username AND password.
Furthermore you can store the password as a hash. This way not even the hoster of your db has a direct access to the passwords. Use MD5 or SHA. As example the credentials in your db would look like:
User Password
Admin 098f6bcd4621d373cade4e832627b4f6
This is a MD5 hash. You'll get this hash if you process md5('test'). A hash is a one way "encryption" function. You check it by hashing the user-input and comparing this result with the stored hash.
If you check for this password you'd bind it like this:
$stmt->bind_param("ss", $_POST['username'], md5($_POST['password']));
$mysqli = new mysqli("localhost", "my_user", "my_password", "my_db");
Plaintext password(not recommended!) - prepared select
$stmt = $mysqli->prepare("SELECT id FROM users WHERE username=? AND password=?");
// type string, string ("ss")
$stmt->bind_param("ss", $_POST['username'], $_POST['password']);
// hashed (recommended)
// $stmt->bind_param("ss", $_POST['username'], md5($_POST['password']));
$stmt->execute();
// set target for the id-column
$stmt->bind_result($id);
// Will be TRUE if a row has been found
if( $stmt->fetch() ) {
echo "Welcome! user:{$id}";
} else {
echo "Invalid username or password";
}
For details have a look at mysqli prepare
And a little more security related: Password hashing
I have a file register.php for my site.
$username=filter_var($_POST['username'], FILTER_SANITIZE_STRING);
$sql="SELECT username FROM users WHERE username=?";
$stmt=$con->prepare($sql);
$stmt->bind_param('s', $username);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
while ($row = $result->fetch_object()) {
if(empty($row->username)) {
echo "different username. IS OK !!";
} else {
echo "<font color='red'>*</font>".$username."<font color='red'> : this username already exist in DB!!</font><br />";
}
}
Here I compare the ($username from form) with ($row->username from DB)
$row->username exist only if $username is already register. So, if this exist, will go on ELSE part.
If $row->username doesn't exist (is empty) , because SELECT from sql will find no attribute, my code must go on IF part and display this message "different username. IS OK !!"
Why IF part doesn't work? I know sql will return 0, or NULL or "" or something like this. If I put a username which is not already registered, the code don't show the specific message. Because in this part I want to change the message with the code which permit to register new username.
empty($row->username) is not really empty if SQL can't find something to return?
Another problem is : I have a registered username "Test". MySQL is not case-sensitive, but in php, I can register another username "test". The code in php will run as a new register, but in MySQL nothing will happening because "username is unique" there. So, in "check username" from above, I need to check 2 insensitive variables ($username and $row->username). Because if in DB I have Test, and I want to register new user "test", this code will let me to do it. I want to show a error message if this happening.
All you need is to verify if no rows are returned.
$username=filter_var($_POST['username'], FILTER_SANITIZE_STRING);
$sql="SELECT username FROM users WHERE username=?";
$stmt=$con->prepare($sql);
$stmt->bind_param('s', $username);
$stmt->execute();
$count = $stmt->num_rows;
if ($count == 0) {
// Username not in table
} else {
// Username already exists
]
To be sure that all your usernames are lowercase, simply convert it to lowercase before inserting it.
$username = strtolower($username);
i think you should covert your database and php variable into same case then compare it for checking.
$username=filter_var($_POST['username'], FILTER_SANITIZE_STRING);
$sql="SELECT LCASE(username) AS username FROM users WHERE username=?";
$stmt=$con->prepare($sql);
$stmt->bind_param('s', strtolower($username)); // used strtolower();
$stmt->execute();
Try this code, hope this helps...
thanks for fast answers. Honestlly, I don't know where was the issue, because now it's run perfect, without strtolower method. This is my code now:
$sql="SELECT username FROM users WHERE username=?";
$stmt=$con->prepare($sql);
$stmt->bind_param('s', $username);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_object();
$stmt->close();
if(empty($row->username)) {
// if a cell from below is empty, go on ELSE part
if (!empty($username) && !empty($password) && !empty($email) && !empty($country)) {
$sql="INSERT INTO users (username, password, email, borned, gender, country, phone, register_date) VALUES (?,?,?,?,?,?,?, now())";
$stmt = $con->prepare($sql);
$stmt->bind_param('sssssss', $username, $password, $email, $borned, $gender, $country, $phone);
$stmt->execute();
$stmt->close();
header ("Location: login.php");
} else {
echo "<font color='red'>*Must complete required cells !!</font> ";
}
// end of register dates
} else {
echo "<font color='red'>*</font>".$username."<font color='red'> : this username already exist in DB!!</font><br />";
}
I have user "Test", if try to register "test" will give a message that the user is already registered.
Thanks again, the thread can be deleted is somebody consider that can not help somebody :D
Hey guys ive put together a basic user log in for a secure admin area and it seems to work great, if you enter a correct user/pass you get access, if you enter the wrong user pass, you get no access. However if you enter nothing in both fields you get access.
This is how it works.
Creating a user, a basic form POSTS to this php file.
<?php
$con = mysqli_connect(credentials are all good) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$some_str = md5(uniqid(mt_rand(), true));
$base_64str = base64_encode($some_str);
$modified_base64 = str_replace('+', '.', $base_64str);
$gensalt = substr($modified_base64, 0, 22);
$format_str = "$2y$10$"; // 2y for Blowfish and 10 times.
$salt = $format_str . $gensalt . "$";
$hashed_pass = crypt($escapedPass, $salt);
$query = "INSERT INTO `userpass` (`username`, `password`, `salt`) VALUES ('$escapedUser', '$hashed_pass', '$salt'); ";
if(isset($escapedUser) && isset($hashed_pass))
{
mysqli_query($con, $query);
header("Location: ausers.php");
exit();
}
Echo "Something went wrong!";
?>
The database appears to be storing these fine
We then log in with this code
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$saltQuery = "select salt from userpass where username = '$escapedUser';";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
if(isset($escapedUser) && isset($hashed_pass))
{
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
}
header("Location: alogin.htm");
exit();
}
Echo "Something went wrong!";
?>
So as i said, this seems to work fine for when any user pass combination is given whether access granted or denied however using no user and pass and pressing log in allows entry. Any ideas? THeres no blank rows in the database table.
Side question, is this salt/hash method correct, its my first attempt.
For your login code, your condition relies on an isset() test. You perform this test on $escapedUser and $hashed_pass. Both of these variables were actually assigned values earlier in the code! Once you assign a value to the variable, it will pass the isset() test, even if the value is an empty string. You might want to use an empty() check, perhaps on the original $_POST variables.
Moving on to the inner condition, which tests if the mysql query returns exactly 1 row of results. If there were truly no rows with empty values, then this condition would never pass because the query would return 0 rows. But it is passing. Two things to consider:
Notice that your registering code uses the same isset() test. Therefore it is very possible that someone used your registration form, submitted empty fields, and successfully registered a row with empty user and password fields. Have you explicitly queried your database for empty fields and actually come up with 0 results?
Your query uses SELECT *. Perhaps this is causing the query to return some sort of aggregate value (like a COUNT() or something that always has a result no matter what). Perhaps try explicitly defining the columns to return?
I cannot comment on your salt/hash method as I have no experience in that part. Hope you find this helpful!
In my opinion you need more than one level of checks in any form, whether it be registration, comments, login, etc. The way I prefer to go about it is a tiered approach. It may work better for you, but it's just an example.
By doing it this way, you ensure that your input will never be empty. Another issue I see with your login script is that you never compare the input with the database so how can you know if they entered the correct information? The only thing allowing them to login is that the query returned a record. This is also why they can login with a blank form.
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
/* Ensures that form was submitted before any processing is done */
if (isset($_POST)) {
$User = $_POST['user']);
$Pass = $_POST['pass']);
if (!empty($User)) {
if (!empty($Pass)) {
$escapedUser = mysqli_real_escape_string($con, $User);
$escapedPass = mysqli_real_escape_string($con, $Pass);
/* you need to verify the password here, before adding the salt */
$saltQuery = "select salt from userpass where username = '$escapedUser'";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
/* you need to verify the username somewhere here */
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
} else {
header("Location: alogin.htm");
exit();
}
} else {
echo "Please enter a password.";
}
} else {
echo "Please enter a username.";
}
} else {
echo "You have not entered any information.";
}
?>