Reputation: 51
I'm creating a login page where the user name and password are entered and then checked against the database to see if they match (I have posted on this previously but my code was completely incorrect so I had to start over) Upon clicking the submit button the user should be directed to the homepage (index.php) if the two values match up or an error message should appear stating "Invalid login. Please try again." Very simple basic stuff. Yet, I cannot get any variation to work.
Here is my code without the validation check. I believe this code is right but, if not, could someone please explain as to why. I am not asking anyone to write any code, just explain why it is not working properly.
<?php
function Password($UserName)
{
//database login
$dsn = 'mysql:host=XXX;dbname=XXX';
$username='*****';
$password='*****';
//variable for errors
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
//try to run code
try {
//object to open database
$db = new PDO($dsn,$username,$password, $options);
//check username against password
$SQL = $db->prepare("Select USER_PASSWORD FROM user WHERE USER_NAME = :USER_NAME");
$SQL->bindValue(':USER_NAME', $UserName);
$SQL->execute();
$username = $SQL->fetch();
if($username === false)
{
$Password = null;
}
else
{
$Password = $username['USER_PASSWORD'];
}
return $Password;
$SQL->closeCursor();
$db = null;
} catch(PDOException $e){
$error_message = $e->getMessage();
echo("<p>Database Error: $error_message</p>");
exit();
}
?>
Now the validation code. I've googled this and found several hundred ways to do so but this method most closely matches my coding style. It is incomplete and I would like some help as to how to finish it properly and then where to place it within the code above. My assumption is right after this comment: "//check username against password". Now I've seen this version twice and in one version the check is for txtUserName and the other is just username. I believe there should be else statements after each if statement to direct them to the index.php page. Also, the third if statement is the check to see if the password matches the username. No variation of this did I understand. They were far too complex.
function Login()
{
if(empty($_POST['txtUserName']))
{
$this->HandleError("UserName is empty!");
return false;
}
if(empty($_POST['txtPassword']))
{
$this->HandleError("Password is empty!");
return false;
}
$username = trim($_POST['txtUserName']);
$password = trim($_POST['txtPassword']);
if(!$this->($username,$password))
{
return false;
}
}
I know I am asking a lot here. But I am very new to PHP and am really trying hard to learn it. And there is way too much info out there and most of it is not for beginners. Any, and all, help would be greatly appreciated.
Upvotes: 1
Views: 19656
Reputation: 4967
To begin with, let's assume that we have a PDO connection, just like you do already, for example with this function:
You can do something like:
// Usage: $db = connectToDataBase($dbHost, $dbName, $dbUsername, $dbPassword);
// Pre: $dbHost is the database hostname,
// $dbName is the name of the database itself,
// $dbUsername is the username to access the database,
// $dbPassword is the password for the user of the database.
// Post: $db is an PDO connection to the database, based on the input parameters.
function connectToDataBase($dbHost, $dbName, $dbUsername, $dbPassword)
{
try
{
return new PDO("mysql:host=$dbHost;dbname=$dbName;charset=UTF-8", $dbUsername, $dbPassword);
}
catch(Exception $PDOexception)
{
exit("<p>An error ocurred: Can't connect to database. </p><p>More preciesly: ". $PDOexception->getMessage(). "</p>");
}
}
So that you can have a database connection like this:
$host = 'localhost';
$user = 'root';
$dataBaseName = 'databaseName';
$pass = '';
$db = connectToDataBase($host, $databaseName, $user, $pass);
So far we have the same stuff as you.
Now, I assume that we're on a PHP page where the user submitted his username and password, to begin with: check if we really received the username and the password, with the ternary oprator:
// receive parameters to log in with.
$userName = isset($_POST['userName']) ? $_POST['userName'] : false;
$password = isset($_POST['password']) ? $_POST['password'] : false;
Now you can validate if those inputs were actually posted:
// Check if all required parameters are set and make sure
// that a user is not logged in already
if(isset($_SESSION['loggedIn']))
{
// You don't want an already logged in user to try to log in.
$alrLogged = "You're already logged in.";
$_SESSION['warningMessage'] = $alrLogged;
header("Location: ../index.php");
}
else if($userName && $password)
{
// Verify an user by the email address and password
// submitted to this page
verifyUser($userName, $password, $db);
}
else if($userName && (!($password)))
{
$noPass = "You didn't fill out your password.";
$_SESSION['warningMessage'] = $noPass;
header("Location: ../index.php");
}
else if((!$userName) && $password)
{
$noUserName = "You didn't fill out your user name.";
$_SESSION['warningMessage'] = $noUserName;
header("Location: ../index.php");
}
else if((!$userName) && (!($password)))
{
$neither = "You didn't fill out your user name nor did you fill out your password.";
$_SESSION['warningMessage'] = $neither;
header("Location: ../index.php");
}
else
{
$unknownError = "An unknown error occurred.". NL. "Try again or <a href='../sites/contact.php' title='Contact us' target='_blank'>contact us</a>.";
$_SESSION['warningMessage'] = $unknownError;
header("Location: ../index.php");
}
Now, let's assume that everything went well and you already have a database connection stored in the variable $db, then you can work with the function
verifyUser($userName, $password, $db);
Like already mentioned in the first else if statement:
// Usage: verifyUser($userName, $password, $db);
// Pre: $db has already been defined and is a reference
// to a PDO connection.
// $userName is of type string.
// $password is of type string.
// Post: $user exists and has been granted a session that declares
// the fact that he is logged in.
function verifyUser($userName, $password, $db)
{
$userExists = userExists($userName, $db); // Check if user exists with that username.
if(!($user))
{
// User not found.
// Create warning message.
$notFound= "User not found.";
$_SESSION['warningMessage'] = $notFound;
header("Location: ../index.php");
}
else
{
// The user exists, here you can use your smart function which receives
// the hash of the password of the user:
$passwordHash = Password($UserName);
// If you have PHPass, an awesome hashing library for PHP
// http://www.openwall.com/phpass/
// Then you can do this:
$passwordMatch = PHPhassMatch($passwordHash , $password);
// Or you can just create a basic functions which does the same;
// Receive 1 parameter which is a hashed password, one which is not hashed,
// so you hash the second one and check if the hashes match.
if($passwordMatch)
{
// The user exists and he entered the correct password.
$_SESSION['isLoggedIn'] = true;
header("Location: ../index.php");
// Whatever more you want to do.
}
else
{
// Password incorrect.
// Create warning message.
$wrongPass = "Username or password incorrect."; // Don't give to much info.
$_SESSION['warningMessage'] = $wrongPass;
header("Location: ../index.php");
}
}
}
And the function userExists($userName, $db) can be like:
function userExists($userName, $db)
{
$stmt = $db->prepare("SELECT * FROM users WHERE USER_NAME = :USER_NAME;");
$stmt->execute(array(":USER_NAME "=>$userName));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result)
{
// User exists.
return true;
}
// User doesn't exist.
return false;
}
Where the function Password is like:
function Password($UserName)
{
$stmt = $db->prepare("Select USER_PASSWORD FROM user WHERE USER_NAME = :USER_NAME;");
$stmt->execute(array(":USER_NAME"=>UserName));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result)
{
return $result['USER_PASSWORD'];
}
// No result.
return false;
}
Again, make sure you're not matching plain text passwords, or basic shai1, md5 encryptiones etc. I really recommend that you take a look at PHPass.
I hope I'm making myself clear.
Upvotes: 3