I am buidling a small job application website, and i'm using a the basis of a login system taken from a Nettuts.com tutorial.
The logging in works fine, but I am having trouble getting the details for the currently logged in user, for example if a user enters their personal details, i can process the data into the database but it's not linked to which user!
I ideally want the id put into a variable called $userID.
I need a way to identify the user currently logged in, so i can update my insert statements to something like ...
'UPDATE cv where userID = $userID'.
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT *
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
if($stmt->fetch()) {
$stmt->close();
return true;
}
}
}
}
class Membership {
function validate_user($un, $pwd) {
$mysql = New Mysql();
$ensure_credentials = $mysql->verify_Username_and_Pass($un, md5($pwd));
// if above = true
if($ensure_credentials) {
$_SESSION['status'] = 'authorized';
$_SESSION['username'] = $un;
$_SESSION['password'] = $pwd;
header("location: ../myIWC.php");
} else return "Please enter a correct username and password";
}
function log_User_Out() {
if(isset($_SESSION['status'])) {
unset($_SESSION['status']);
unset($_SESSION['username']);
unset($_SESSION['password']);
if(isset($_COOKIE[session_name()]))
setcookie(session_name(), '', time() - 1000);
session_destroy();
}
}
function confirm_Member() {
session_start();
if($_SESSION['status'] !='authorized') header("location: ../login.php");
}
$currentUN = $_SESSION['username'];
$currentPWD = $_SESSION['password'];
$mysql = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or die('There was a problem connecting to the database');
$stmt = $mysql->prepare('SELECT id FROM users WHERE username = ? AND password = ? LIMIT 1');
$stmt->bind_param('ss',$currentUN, $currentPWD);
$stmt->execute();
$stmt->bind_result($currentID);
}
Think of rewriting your verify_Username_and_Pass function so it return an array of user data, or writing a new function that gets it.
Then in your validate_user function, save this data to session:
$_SESSION['user_data'] = $user_data; // got from database
Well I would say the code given in the tutorial isn't a very good example. The database class should be just that and only handle database functions it shouldn't really have user functions in there (verify_Username_and_Pass). Also from a security point of view I would strongly recommend against storing unencrypted passwords in the session.
I appreciate however the code snippets you've provided are probably part of a wider implementation and as such you won't be able to play around with it too much. As such the code below will work in your context.
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT id
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
$stmt->bind_result($id);
if($stmt->fetch()) {
$stmt->close();
return $id;
} else {
return false;
}
}
}
Then in your user class
if($ensure_credentials !== false) {
$_SESSION['id'] = $ensure_credentials;
$_SESSION['status'] = 'authorized';
$_SESSION['username'] = $un;
$_SESSION['password'] = $pwd;
header("location: ../myIWC.php");
} else return "Please enter a correct username and password";
Related
Sorry, but once again I return with a long post for those that can spend a little of their time helping out a troubled noob.
I've been having some difficulties and asked here previously for any guidance on how to draw any users first and last name from the database, when only given the username and password at login.
When my code was edited now it seems anyone can login with whatever they desire.
Login.php script as follows:
<?php
session_start();
require_once 'classes/membership.php';
$membership = new Membership();
// If the user clicks the "Log Out" link on the index page.
if(isset($_GET['status']) && $_GET['status'] == 'loggedout') {
$membership->log_User_Out();
}
// Did the user enter a password/username and click submit?
if($_POST && !empty($_POST['username']) && !empty($_POST['pwd'])) {
$response = $membership->validate_User($_POST['username'], $_POST['pwd']);
}
?>
This points to Membership.php first:
<?php
require 'mysql.php';
class Membership {
function validate_user($un, $pwd) {
$mysql = New Mysql();
$ensure_credentials = $mysql->verify_Username_and_Pass($un, md5($pwd));
list($ensureCredentials, $data) = $mysql->verify_Username_and_Pass($un, md5($pwd));
if($ensure_credentials) {
$_SESSION['status'] = 'authorized';
$_SESSION['fname'] = $data['fname'];
$_SESSION['lname'] = $data['lname'];
header("location: medlem.php");
} else return "Please enter correct username and password";
}
function log_User_Out() {
if(isset($_SESSION['status'])) {
unset($_SESSION['status']);
if(isset($_COOKIE[session_name()]))
setcookie(session_name(), '', time() - 1000);
session_destroy();
}
}
function confirm_Member() {
session_start();
if($_SESSION['status'] !='authorized') header("location: login.php");
}
}
Which then again points forward to mysql.php:
<?php
require_once 'includes/constants.php';
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT *
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
// UPDATE : I added correct usage of the stmt here.
$result = $stmt->get_result();
if($row = $result->fetch_array()) {
$stmt->free_result();
$stmt->close();
// returning an array the first item is the validation the second is the data.
return array(true, $row);
}
}
// if there is no just return empty data, and false for validation.
return array(false, array());
}
}
For the sake of re-usability I've used constants for this project:
<?php
// Define constants here
define('DB_SERVER', 'localhost');
define('DB_USER', 'myusername');
define('DB_PASSWORD', 'mypassword');
define('DB_NAME', 'sameige_membership');
With this current script set, it will login with whatever I set in the username and password field. The webpages are also supposed to post first and lastname to tell the user who and if he is logged in posted by $_SESSION('fname/lname').
The login works as it's supposed to when I revert to what I had in the beginning. Before adding to query part for drawing first and lastname from DB.
Here is the original one:
<?php
require_once 'includes/constants.php';
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT *
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
if($stmt->fetch()) {
$stmt->close();
return true;
}
}
}
}
To my understanding this scirpt should compare $_POST['username']/['password'] to the selected username and password fields in the database. And if they are correct it should comeback with a login and redirect to the medlem.php page. If else it should return to enter correct username and password.
This however logs in and redirect nonetheless.
Any answer to what I am doing worng would be greatly appriciated, as I am a total noob on the subject.
Regards, Josh
First of all your code about checking the user input is wrong... You should check if isset($_POST['username'] && isset($_POST['password']) and not if($_POST) like you do.
Second you say : $response = $membership->validate_User($_POST['username'], $_POST['pwd']); and your class is : validate_user.... It's case sensitive (use Dreamweaver if you can, it warns you about mistakes like these)
3rd solve them and check again.
<?php
session_start();
require_once 'classes/membership.php';
$membership = new Membership();
// If the user clicks the "Log Out" link on the index page.
if(isset($_GET['status']) && $_GET['status'] == 'loggedout') {
$membership->log_User_Out();
}
// Did the user enter a password/username and click submit?
Use isset($_POST['submit']) in place of just $_POST and note methods are case sensitive. So it would be validate_user not validate_User
if(isset($_POST['submit']) && !empty($_POST['username']) && !empty($_POST['pwd'])) {
$response = $membership->validate_user($_POST['username'], $_POST['pwd']);
}
?>
Now in your mysql.php, I would do it like this:
<?php
require_once 'includes/constants.php';
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT *
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
// UPDATE : I added correct usage of the stmt here.
$result = $stmt->get_result();
if($row = $result->fetch_assoc()) {
$stmt->free_result();
$stmt->close();
// returning an array the first item is the validation the second is the data.
$result['data']=$row;
$result['validation']=true;
return $result;
}
}
// if there is no just return empty data, and false for validation.
$result['data']=array();
$result['validation']=false;
return $result;
}
}
Now I will have the following changes in Membership.php
function validate_user($un, $pwd) {
$mysql = New Mysql();
$ensure_credentials = $mysql->verify_Username_and_Pass($un, md5($pwd));
$data=$ensure_credentials['data'];
$validation=$ensure_credentials['validation'];
if($validation) {
$_SESSION['status'] = 'authorized';
$_SESSION['fname'] = $data['fname'];
$_SESSION['lname'] = $data['lname'];
header("location: medlem.php");
} else return "Please enter correct username and password";
Hope this works for you....:)
I write a simple php login class that only operate on php sessions to login user in the system.
My Question is that this class is secure enough to be used on production environment ?
class.login.inc.php
class Login
{
//setSessionFunction sets a login session with user id and all user details array
private function setSession($user_id,$user_details)
{
$_SESSION['user_id'] = $user_id;
$_SESSION['user_details'] = $user_details;
$_SESSION['key'] = $this->hashSession();
}
//GetIp function is used to get ip address of client
private function hashSession()
{
return sha1($_SERVER['HTTP_USER_AGENT'] . getIP());
}
//get sessions and verify them
public function getSession(){
if(isset($_SESSION['user_id']) && ($_SESSION['user_id']!== '') )
if($this->verifySessionUser($_SESSION['user_id']) === true )
if($this->hashSession() == $_SESSION['key'])
return true;
else
return false;
}
//Logout Function
public function logout(){
$_SESSION['user_id'] = null;
$_SESSION['key'] = null;
$_SESSION = array();
session_unset();
session_destroy();
}
public function verifyUser($username,$password){
$password = sha1($password);
$conn = new mysqli(DB_HOST,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
if(!$conn) die("Connection Error To DATABASE" . mysqli_connect_errno());
$sql = "SELECT * FROM user WHERE username = ?";
$mysqli = $conn->prepare($sql);
if(!$conn) die("Query Error To DATABASE In Class Session" . mysqli_errno($conn));
$mysqli->bind_param("s",$username);
$mysqli->execute();
$result = $mysqli->get_result();
$mysqli->close();
$conn->close();
if($result->num_rows > 0)
{
$r = $result->fetch_assoc();
if($r['password'] === $password)
{
$this->setSession($r['user_id'],$r);
return true;
}else return false;
}
else
return false;
return false;
}
//Private DataBase Verification of User Credentials
private function verifySessionUser($user_id){
$conn = new mysqli(DB_HOST,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
if(!$conn) die("Connection Error To DATABASE" . mysqli_errno());
$sql = "SELECT * FROM user WHERE user_id = ?";
$mysqli = $conn->prepare($sql);
if(!$conn) die("Query Error To DATABASE In Class Session" . mysqli_errno());
$mysqli->bind_param("d",$user_id);
$mysqli->execute();
$result = $mysqli->get_result();
$mysqli->close();
$conn->close();
if($result->num_rows > 0)
{
return true;
}
else
return false;
}
}
securepage.php
$user = new Session();
if($user->getSession() == true)
{
header("location: admin.php");
exit();
}
Is there any security measures i should consider in future ?
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';
}
}
im doing a system for school which by the user will be admin, teacher and parents.
im having problem to differentiate two user right now which is admin and parents.
i cant make sure that admin will directly go to admin.php and parent type will be on parent.php
any helps will be great! thanks in advance.
and the problem now is that the authentication for the user went wrong if the user enter a wrong username/password, they still can make it to the system.
<?php
session_start();
require("conection/connect.php");
$msg="";
if(isset($_POST['btn_log'])){
$uname=$_POST['unametxt'];
$pwd=$_POST['pwdtxt'];
$type=$_POST ['type'];
$sql=mysql_query("SELECT * FROM users_tbl
WHERE username='$uname' AND password='$pwd' AND type='$type'
");
$cout=mysql_num_rows($sql);
if (isset($type))
{
$_SESSION['Parent'] = $type;
header("location: parent.php");
}
else {
$_SESSION['Admin'] = $type;
header("location: admin.php");
exit;
}
}
?>
First don't use mysql_ it's deprecated.
I assume... $type = a means admin and p means oarent.
$sql=mysql_query("SELECT * FROM users_tbl WHERE username='$uname' AND password='$pwd'");
$count=mysql_num_rows($sql);
if($count>0)
{
if ($type=='p')
{
$_SESSION['Parent'] = $type;
header("location: parent.php");
}
elseif($type=='a') {
$_SESSION['Admin'] = $type;
header("location: admin.php");
exit;
}
}
else
{
echo "Wrong username or password";
}
here some solutions. You didn't check if the 'cout' was > 0 (mean found) !
mysql_ driver
Here a solution with your driver (mysql_) :
<?php
session_start();
require("conection/connect.php");
$msg = "";
if(isset($_POST['btn_log'])){
if(isset($_POST['unametxt'], $_POST['pwdtxt'], $_POST['type'])) {
$uname = mysql_real_escape_string($_POST['unametxt']);
$pwd = mysql_real_escape_string($_POST['pwdtxt']);
$type = mysql_real_escape_string($_POST['type']);
$sql = mysql_query("SELECT * FROM users_tbl WHERE username = '$uname' AND password = '$pwd' AND type = '$type'");
$cout = mysql_num_rows($sql);
if($cout > 0){
$_SESSION['type'] = $type;
if($type == "parent")
header("location: parent.php");
else if($type == "admin")
header("location: admin.php");
exit();
}
}
}
PDO version
The mysql_ driver is deprecated and you should use PDO instead. So I did the script for PDO driver too :
<?php
session_start();
require("connection/connect.php"); // PDO connection on $db variable
$db = connect();
// Function to connect an user
function login($db, $uname, $password){
$req = $db->prepare("SELECT * FROM users_tbl WHERE username = :username AND password = :password");
$req->bindParam("username", $uname, PDO::PARAM_STR);
$req->bindParam("password", $password, PDO::PARAM_STR);
$req->execute();
$user = $req->fetch();
if(isset($user['username'])){
$_SESSION['user'] = $user; //store all user datas (including type !)
return true;
}
return false; // fail connection
}
// logic to handle connection form
if(isset($_POST['btn_log'], $_POST['unametxt'], $_POST['pwdtxt'], $_POST['type'])){
if(login($db, $_POST['unametxt'], $_POST['pwdtxt'])){
if(isset($_SESSION['user']['type']) AND $_SESSION['user']['type'] == "admin")
header("location: admin.php");
else
header("location: parent.php");
exit();
}
else
echo "A problem occured !";
}
connect.php (pdo)
define("SQL_USER", "root"); // user
define("SQL_HOST", "localhost"); // host
define("SQL_PASS", ""); // password
define("SQL_DBNAME", ""); //db name
function connect(){
try {
$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$pdo_options[PDO::ATTR_DEFAULT_FETCH_MODE] = PDO::FETCH_ASSOC;
return new PDO('mysql:host='.SQL_HOST.'; dbname='.SQL_DBNAME, SQL_USER, SQL_PASS, $pdo_options);
}
catch (Exception $e){
die("Error connecting to database");
}
}
I have a problem. I want to get the email of a user, the email is a special column in a table called users in my database. I created a login-system that is working well, but I still want to get the e-mail of the user who is currently logged in.
I am really new to php and mysql. :(
This is my code in login.php:
<?php
require 'Mysql.php';
class Membership {
//Check if input is correct
function validate_user($un, $pwd) {
$mysql = New Mysql();
$ensure_credentials = $mysql->verify_Username_and_Pass($un, $pwd);
//input correct
if($ensure_credentials) {
$_SESSION['status'] = 'authorized';
$_SESSION["username"] = $un;
$_SESSION["email"] = $ensure_credentials['email'];
header("location: ?status=authorized");
}
function log_User_Out() {
if(isset($_SESSION['status'])) {
unset($_SESSION['status']);
if(isset($_COOKIE[session_name()]))
setcookie(session_name(), '', time() - 10000);
session_destroy();
}
if(isset($_SESSION["username"])) {
unset($_SESSION["username"]);
}
if(isset($_SESSION["email"])) {
unset($_SESSION["email"]);
}
}
}
and here from Mysql.php:
<?php
require "/data/logindata/constants.php";
class Mysql {
private $conn;
function __construct() {
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('There was a problem connecting to the database.');
}
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT *
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
$stmt->bind_result($username, $email); // the columns fetched with SELECT *
if (!$stmt->fetch()) {
return false;
}
return array(
'username' => $username,
'email' => $email
);
}
return false;
}
}
Instead of returning a boolean, you may return some user data with verify_Username_and_Pass function. There you can include authenticated user's email:
function verify_Username_and_Pass($un, $pwd) {
$query = "SELECT username, password
FROM users
WHERE username = ? AND password = ?
LIMIT 1";
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('ss', $un, $pwd);
$stmt->execute();
$stmt->bind_result($username, $email); // the columns fetched with SELECT *
if (!$stmt->fetch()) {
return false;
}
return array(
'username' => $username,
'email' => $email
);
}
return false;
}
....
$ensure_credentials = $mysql->verify_Username_and_Pass($un, $pwd);
//input correct
if($ensure_credentials) {
$_SESSION['status'] = 'authorized';
$_SESSION["username"] = $un;
$_SESSION["email"] = $ensure_credentials['email'];
header("location: ?status=authorized");
}
First of all be sure to sanitize every variable inserted by final users.
It's very important to sanitize your variable to avoid SQL injection.
Then on the Session variable user I'm gonna save the user Id and to get his/her email I'm gonna make a function that should receive the session id to return an email.
Now I'm gonna write a couple of functions that could be useful:
function logged() {
return (isset($_SESSION['id_user'])) ? true : false;
}
function getEmail($userId) {
$userId = sanitize(userId);
$query = "SELECT userEmail FROM users WHERE id_user =" . $userId;
$name = mysql_result(mysql_query($query), 0);
return $name;
}
function sanitize($data) {
return mysql_real_escape_string($data);
}