PHP LOGIN AND AUTHENTICATION:
The Complete Tutorial (2019)
Today you will learn exactly how to build a PHP login and authentication class.
In fact, this step-by-step guide will show you:
- How to store the accounts on the database
- How to use Sessions and MySQL for login
- All you need to know about security
- …and more
So: if you need to work on a PHP login system, this is the guide you are looking for.
Let’s get started.

TABLE OF CONTENTS
STEP 1
STEP 2
Database Structure
STEP 3
Add, Edit And Delete Accounts
STEP 4
Login And Logout
Exclusive Bonus for Subscribers (highly recommended):
Get the PDF Checklist with the 5 most common PHP Authentication Mistakes you must avoid.
Click To Unlock The PDF
Step 1:
Getting Started
In this chapter you will learn how your authentication system is structured.
You will also see how to connect to the database and how to start the PHP Session.
It will only take a few minutes.
Let’s go.

In this tutorial you are going to build a basic PHP login and authentication system.
This system is composed of three different parts:
- A Database where to store the accounts information. All the details are in the next chapter.
- A PHP Class where to write the code logic for all the operations (add an account, login and logout…). This class will be called “Account”.
- A way to remember the remote clients that have already been authenticated. For this purpose, you’re going to use PHP Sessions.

So far, so good.
First of all, let’s create an example script where you will use the Account class.
Open your favourite code editor, create an empty PHP script an save it as “myApp.php” inside a directory of your choice.
Note: you need a working local PHP development environment (like XAMPP).
If you need help setting up one, read the Getting Started chapter of my “How to learn PHP” tutorial.
Next, you need to connect to your SQL database.
The best way to do it is to create a separate “include” file with the connection code, like this one taken from my MySQL tutorial:
<?php
/* Host name of the MySQL server */
$host = 'localhost';
/* MySQL account username */
$user = 'myUser';
/* MySQL account password */
$passwd = 'myPasswd';
/* The schema you want to use */
$schema = 'mySchema';
/* The PDO object */
$pdo = NULL;
/* Connection string, or "data source name" */
$dsn = 'mysql:host=' . $host . ';dbname=' . $schema;
/* Connection inside a try/catch block */
try
{
/* PDO object creation */
$pdo = new PDO($dsn, $user, $passwd);
/* Enable exceptions on errors */
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
/* If there is an error an exception is thrown */
echo 'Database connection failed.';
die();
}
Change the connection parameters as required, then save the above code as a PHP script named “db_inc.php” inside the same directory of myApp.php.
Every time you need to use the database, simply include this file and the $pdo connection object will be available as a global variable.
So, go back to myApp.php and include the database connection file:
<?php
require './db_inc.php';
Very handy, isn’t it?
Now, create one more PHP script which will contain the Account class (for now just leave it empty, you’ll go back to it later). Save it as “account_class.php” inside the same directory.
Just like for db_inc.php, you can include this script every time you will need to use the Account class in any of your applications.
Let’s do that right away in myApp.php:
<?php
require './db_inc.php';
require './account_class.php';
Here you go.
The last thing to do is to start the PHP Session. This is easily done with the session_start() function.
session_start() must be called before any output is sent to the remote client, therefore it’s a good practice to call it before including other scripts.
You can do this in myApp.php just like this:
<?php
session_start();
require './db_inc.php';
require './account_class.php';
Very well!
Now let’s dive into the details, starting from the database structure.
Step 2:
Database Structure
This chapter will show you exactly how to set up the database tables used by the Account class.
You’ll get the step-by-step instructions to create the tables yourself, including the full SQL code.
You’ll complete this step in no time.
Let’s begin.

Now, you’re going to create the database tables where the accounts data is stored.
If you’re not familiar with databases or if you don’t know exactly how to use PHP with MySQL, you can find everything you need here:
The Account class uses two MySQL tables:
- accounts
- account_sessions
The accounts table contains all the registered accounts along with some basic information: username, password hash, registration time and status (enabled or disabled).
The specific table columns are:
- account_id: the unique identifier of the account (this is the table’s primary key)
- account_name: the name used for logging in, or simply “username” (each name must be unique inside the table)
- account_passwd: the password hash, created with password_hash()
- account_reg_time: the registration timestamp (when the account has been created)
- account_enabled: whether the account is enabled or disabled, useful for disabling the account without deleting it from the database
Note: For this tutorial, I assume the MySQL Schema is named mySchema. If you are using a different schema name, be sure to change all the examples’ code accordingly (just search for “mySchema” and replace it with your own).
This is how this table looks in phpMyAdmin:

As you can see, it’s a very simple table.
(In the next chapters you will see exactly how each column is used.)
Here is the SQL code to create the table including the indexes:
--
-- Table structure for table `accounts`
--
CREATE TABLE `accounts` (
`account_id` int(10) UNSIGNED NOT NULL,
`account_name` varchar(255) NOT NULL,
`account_passwd` varchar(255) NOT NULL,
`account_reg_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`account_enabled` tinyint(1) UNSIGNED NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Indexes for table `accounts`
--
ALTER TABLE `accounts`
ADD PRIMARY KEY (`account_id`),
ADD UNIQUE KEY `account_name` (`account_name`);
--
-- AUTO_INCREMENT for table `accounts`
--
ALTER TABLE `accounts`
MODIFY `account_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
To create the table with phpMyAdmin, first select your Schema from the list on the left, then click on the SQL tab and paste the code:
1 – Select your Schema from the left menu:

2 – Click on the “SQL” tab in the top menu:

3 – Paste the SQL code in the text field:

4 – Click “Go” in the bottom right corner:

The account_sessions table contains the Session IDs used for the Session-based authentication.
Here are the table columns:
- session_id: the PHP Session ID of the authenticated client (this is also the primary key)
- account_id: the ID of the account (pointing to the account_id column of the accounts table)
- login_time: the timestamp of the session login (useful to handle session timeouts)
This is how this table looks in PhpMyAdmin:

And here is the SQL code to create the table:
--
-- Table structure for table `account_sessions`
--
CREATE TABLE `account_sessions` (
`session_id` varchar(255) NOT NULL,
`account_id` int(10) UNSIGNED NOT NULL,
`login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Indexes for table `account_sessions`
--
ALTER TABLE `account_sessions`
ADD PRIMARY KEY (`session_id`);
Create the account_sessions table by following the same steps as for the accounts table.
That’s it!
You just finished setting up your database.
Let’s move on to the next chapter (now the real fun begins….)
Step 3:
Add, Edit And Delete Accounts
Now you will learn exactly how to handle your accounts.
You are going to implement the class methods for adding new accounts and for editing and deleting them.
Let’s dive in.

Now, it’s time to write the Account class.
Open the account_class.php script you saved earlier and write the basic class structure:
<?php
class Account
{
/* Class properties (variables) */
/* The ID of the logged in account (or NULL if there is no logged in account) */
private $id;
/* The name of the logged in account (or NULL if there is no logged in account) */
private $name;
/* TRUE if the user is authenticated, FALSE otherwise */
private $authenticated;
/* Public class methods (functions) */
/* Constructor */
public function __construct()
{
/* Initialize the $id and $name variables to NULL */
$this->id = NULL;
$this->name = NULL;
$this->authenticated = FALSE;
}
/* Destructor */
public function __destruct()
{
}
}
For now, there are just the constructor, the destructor and two class properties (which will contain the account ID, the account name and the authenticated flag set to TRUE after a successful login, as you will see in the next chapter).
Before moving on, let’s see how errors are handled.
Many different errors can occur (a username is not valid, a database query failed…), and each class method must be able to signal such errors to the caller.
This is done with Exceptions.
If you never used exceptions before, don’t worry: they are easier than you think.
And you will see exactly how to use them with the next examples.
All right.
Let’s get started with the first class method: addAccount().
How To Add A New Account

This function adds a new account to the database.
It returns the new account ID (that is, the account_id value from the accounts table) on success. If the operation fails, it throws an exception with a specific error message.
Let’s look at the code:
/* Add a new account to the system and return its ID (the account_id column of the accounts table) */
public function addAccount(string $name, string $passwd): int
{
/* Global $pdo object */
global $pdo;
/* Trim the strings to remove extra spaces */
$name = trim($name);
$passwd = trim($passwd);
/* Check if the user name is valid. If not, throw an exception */
if (!$this->isNameValid($name))
{
throw new Exception('Invalid user name');
}
/* Check if the password is valid. If not, throw an exception */
if (!$this->isPasswdValid($passwd))
{
throw new Exception('Invalid password');
}
/* Check if an account having the same name already exists. If it does, throw an exception */
if (!is_null($this->getIdFromName($name)))
{
throw new Exception('User name not available');
}
/* Finally, add the new account */
/* Insert query template */
$query = 'INSERT INTO myschema.accounts (account_name, account_passwd) VALUES (:name, :passwd)';
/* Password hash */
$hash = password_hash($passwd, PASSWORD_DEFAULT);
/* Values array for PDO */
$values = array(':name' => $name, ':passwd' => $hash);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
/* Return the new ID */
return $pdo->lastInsertId();
}
Let me explain all the steps.
Before adding the new account to the database, addAccount() performs some checks on the input variables to make sure they are correct.
In particular:
- it calls isNameValid(), a class method that returns TRUE if the passed string can be a valid username
- then, it calls isPasswdValid(), that returns TRUE if the passed string can be a valid password
- finally, it calls getIdFromName(): this method looks for the passed username on the database, and it returns its account_id if it exists or NULL if it doesn’t
If the username passed to addAccount() is not valid (for example, it’s too short), an exception is thrown and the method stops its execution.
Similarly, an exception is thrown if the password is not valid or if the username is not available.
If everything is fine, the new account is finally added to the database and its ID is returned.
(An exception is also thrown if a PDO exception is caught, meaning there was an error while executing the SQL query).
Here is the full code of isNameValid(), isPasswdValid() and getIdFromName():
/* A sanitization check for the account username */
public function isNameValid(string $name): bool
{
/* Initialize the return variable */
$valid = TRUE;
/* Example check: the length must be between 8 and 16 chars */
$len = mb_strlen($name);
if (($len < 8) || ($len > 16))
{
$valid = FALSE;
}
/* You can add more checks here */
return $valid;
}
/* A sanitization check for the account password */
public function isPasswdValid(string $passwd): bool
{
/* Initialize the return variable */
$valid = TRUE;
/* Example check: the length must be between 8 and 16 chars */
$len = mb_strlen($passwd);
if (($len < 8) || ($len > 16))
{
$valid = FALSE;
}
/* You can add more checks here */
return $valid;
}
/* Returns the account id having $name as name, or NULL if it's not found */
public function getIdFromName(string $name): ?int
{
/* Global $pdo object */
global $pdo;
/* Since this method is public, we check $name again here */
if (!$this->isNameValid($name))
{
throw new Exception('Invalid user name');
}
/* Initialize the return value. If no account is found, return NULL */
$id = NULL;
/* Search the ID on the database */
$query = 'SELECT account_id FROM myschema.accounts WHERE (account_name = :name)';
$values = array(':name' => $name);
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
$row = $res->fetch(PDO::FETCH_ASSOC);
/* There is a result: get it's ID */
if (is_array($row))
{
$id = intval($row['account_id'], 10);
}
return $id;
}
Both isNameValid() and isPasswdValid() perform a simple length check.
However, you can easily edit them to perform additional checks, for example forcing the password to have at least one capital letter and one digit.
If you have any doubt about these methods, just leave me a comment.
Ok, BUT:
How do you use this method from your application?
Well, it’s very simple.
This is what you need to write inside myApp.php:
<?php
session_start();
require './db_inc.php';
require './account_class.php';
$account = new Account();
try
{
$newId = $account->addAccount('myNewName', 'myPassword');
}
catch (Exception $e)
{
/* Something went wrong: echo the exception message and die */
echo $e->getMessage();
die();
}
echo 'The new account ID is ' . $newId;
It’s easy to read, elegant and efficient.
All right:
Let’s move on to the next method: editAccount().
How To Edit An Account

This method lets you change the name, the password or the status (enabled or disabled) of a specific account.
The first function argument is the Account ID of the account to be changed.
The next arguments are the new values to be set: the new name, the new password and the new status (as a Boolean value).
Like addAccount(), this function checks for the validity of the parameters before actually modifying the account on the database.
The name and the password are verified with isNameValid() and isPasswdValid(), the same methods used by addAccount().
The account ID is verified by a new method: isIdValid().
Also, the new name must not be already by other accounts.
Here’s the code:
/* Edit an account (selected by its ID). The name, the password and the status (enabled/disabled) can be changed */
public function editAccount(int $id, string $name, string $passwd, bool $enabled)
{
/* Global $pdo object */
global $pdo;
/* Trim the strings to remove extra spaces */
$name = trim($name);
$passwd = trim($passwd);
/* Check if the ID is valid */
if (!$this->isIdValid($id))
{
throw new Exception('Invalid account ID');
}
/* Check if the user name is valid. */
if (!$this->isNameValid($name))
{
throw new Exception('Invalid user name');
}
/* Check if the password is valid. */
if (!$this->isPasswdValid($passwd))
{
throw new Exception('Invalid password');
}
/* Check if an account having the same name already exists (except for this one). */
$idFromName = $this->getIdFromName($name);
if (!is_null($idFromName) && ($idFromName != $id))
{
throw new Exception('User name already used');
}
/* Finally, edit the account */
/* Edit query template */
$query = 'UPDATE myschema.accounts SET account_name = :name, account_passwd = :passwd, account_enabled = :enabled WHERE account_id = :id';
/* Password hash */
$hash = password_hash($passwd, PASSWORD_DEFAULT);
/* Int value for the $enabled variable (0 = false, 1 = true) */
$intEnabled = $enabled ? 1 : 0;
/* Values array for PDO */
$values = array(':name' => $name, ':passwd' => $hash, ':enabled' => $intEnabled, ':id' => $id);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
}
And here is the code of the isIdValid() method:
/* A sanitization check for the account ID */
public function isIdValid(int $id): bool
{
/* Initialize the return variable */
$valid = TRUE;
/* Example check: the ID must be between 1 and 1000000 */
if (($id < 1) || ($id > 1000000))
{
$valid = FALSE;
}
/* You can add more checks here */
return $valid;
}
How To Delete An Account

The last method of this chapter is deleteAccount().
This is quite straightforward: it takes an account ID and deletes it. The account Sessions inside the account_sessions table are also deleted.
Here’s the code:
/* Delete an account (selected by its ID) */
public function deleteAccount(int $id)
{
/* Global $pdo object */
global $pdo;
/* Check if the ID is valid */
if (!$this->isIdValid($id))
{
throw new Exception('Invalid account ID');
}
/* Query template */
$query = 'DELETE FROM myschema.accounts WHERE account_id = :id';
/* Values array for PDO */
$values = array(':id' => $id);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
/* Delete the Sessions related to the account */
$query = 'DELETE FROM myschema.account_sessions WHERE (account_id = :id)';
/* Values array for PDO */
$values = array(':id' => $id);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
}
Very well!
You’re ready for the next step: login and logout.
Step 4:
Login And Logout
In this chapter you will learn how remote clients can login (and logout) using your class.
You will see how to:
- login with username and password, and
- login using PHP Sessions
Let’s go.

A remote client can login in two ways.
The first is the classic way: by providing a username and password couple. This is the “real” login.
After a successful login, a Session for that remote client is started.
The second way is by restoring a previously started Session, without the need for the client to provide name and password again.
Let’s start with the username and password login.
Login With Username And Password

This is done with the login() class method.
Here’s what this function does:
- it checks if the provided $username and $password variables are valid. If they are not, the function immediately returns FALSE (meaning the authentication request failed)
- then, in looks for the username on the database account list. If it’s there, it checks the password with password_verify()
- If the password matches then the client is authenticated, and the function sets the class properties related to the current account (its ID and its name). The $authenticated property is set to TRUE.
- finally, it creates or updates the client Session and returns TRUE, meaning the client has successfully authenticated.
Here’s the code:
/* Login with username and password */
public function login(string $name, string $passwd): bool
{
/* Global $pdo object */
global $pdo;
/* Trim the strings to remove extra spaces */
$name = trim($name);
$passwd = trim($passwd);
/* Check if the user name is valid. If not, return FALSE meaning the authentication failed */
if (!$this->isNameValid($name))
{
return FALSE;
}
/* Check if the password is valid. If not, return FALSE meaning the authentication failed */
if (!$this->isPasswdValid($passwd))
{
return FALSE;
}
/* Look for the account in the db. Note: the account must be enabled (account_enabled = 1) */
$query = 'SELECT * FROM myschema.accounts WHERE (account_name = :name) AND (account_enabled = 1)';
/* Values array for PDO */
$values = array(':name' => $name);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
$row = $res->fetch(PDO::FETCH_ASSOC);
/* If there is a result, we must check if the password matches using password_verify() */
if (is_array($row))
{
if (password_verify($passwd, $row['account_passwd']))
{
/* Authentication succeeded. Set the class properties (id and name) */
$this->id = intval($row['account_id'], 10);
$this->name = $name;
$this->authenticated = TRUE;
/* Register the current Sessions on the database */
$this->registerLoginSession();
/* Finally, Return TRUE */
return TRUE;
}
}
/* If we are here, it means the authentication failed: return FALSE */
return FALSE;
}
isNameValid() and isPasswdValid() are the very same methods you already know.
What’s new here is registerLoginSession().
So, what does this function do, exactly?
It’s very easy:
Once the remote client has been authenticated, this function gets the ID of the current PHP Session and saves it on the database together with the account ID.
This way, the next time the same remote client will connect, it will be automatically authenticated just by looking at its Session ID.
(The Session ID is linked to the remote browser, so it will remain the same the next time the same client will connect again).
If you are not familiar with Sessions, I suggest you spend a few minutes reading my guide:
Here’s the code for registerLoginSession():
/* Saves the current Session ID with the account ID */
private function registerLoginSession()
{
/* Global $pdo object */
global $pdo;
/* Check that a Session has been started */
if (session_status() == PHP_SESSION_ACTIVE)
{
/* Use a REPLACE statement to:
- insert a new row with the session id, if it doesn't exist, or...
- update the row having the session id, if it does exist.
*/
$query = 'REPLACE INTO myschema.account_sessions (session_id, account_id, login_time) VALUES (:sid, :accountId, NOW())';
$values = array(':sid' => session_id(), ':accountId' => $this->id);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
}
}
Let me explain how it works.
Remember the account_sessions table?
registerLoginSession() inserts a new row into that table, with the current Session ID (given by the session_id() function) in the session_id column, the authenticated account ID in the account_id column and the login_time column set to the current timestamp.
Put simply, this new row says:
“This Session ID (in the session_id column) belongs to a remote user who has already logged in as the account with this ID (in the account_id column), and it has logged in at this time (the login_time column).”
If a row with the same Session ID (that is the table’s primary key) already exists, that row is replaced.
If you were wondering what the “REPLACE” SQL command does, it’s exactly that, that is:
- inserts a new row if another row with the same key (the Session ID) does not exits
- otherwise, it simply updates that row
Very handy 🙂
Now let’s move on to the Session-based login.
Session-based Login

The Session-based login is done with the sessionLogin() method.
This function gets the current Session ID (using session_id()) and looks for it into the account_sessions table.
If it’s there, it also checks that:
- the Session is not older than 7 days
- the account linked to the session is enabled
If everything is ok then the client is authenticated, the account-related class properties are set, and the method returns TRUE.
If, for some reason, the authentication fails then the function returns FALSE.
Here is the sessionLogin() code:
/* Login using Sessions */
public function sessionLogin(): bool
{
/* Global $pdo object */
global $pdo;
/* Check that the Session has been started */
if (session_status() == PHP_SESSION_ACTIVE)
{
/*
Query template to look for the current session ID on the account_sessions table.
The query also make sure the Session is not older than 7 days
*/
$query =
'SELECT * FROM myschema.account_sessions, myschema.accounts WHERE (account_sessions.session_id = :sid) ' .
'AND (account_sessions.login_time >= (NOW() - INTERVAL 7 DAY)) AND (account_sessions.account_id = accounts.account_id) ' .
'AND (accounts.account_enabled = 1)';
/* Values array for PDO */
$values = array(':sid' => session_id());
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
$row = $res->fetch(PDO::FETCH_ASSOC);
if (is_array($row))
{
/* Authentication succeeded. Set the class properties (id and name) and return TRUE*/
$this->id = intval($row['account_id'], 10);
$this->name = $row['account_name'];
$this->authenticated = TRUE;
return TRUE;
}
}
/* If we are here, the authentication failed */
return FALSE;
}
Note
Be sure to check the Session Cookie Lifetime parameter in your PHP configuration (usually, the php.ini file). This parameter is named session.cookie_lifetime, and it specifies how many seconds a Session should be kept opened.
After that time, a Session will be closed and a new Session ID will be created, forcing the remote client with the expired Session to authenticate again with username and password.
The default value is 0, meaning a Session lasts only until the browser is closed. This is usually not very useful, so you probably want to set it higher, at least a few days.
For example, this is how to set the Session lifetime to 7 days (7 days = 604800 seconds):
session.cookie_lifetime=604800
Finally, let’s see how to logout a remote client.
Logout

The logout() method clears the account-related class properties ($id and $name) and deletes the current Session from the account_sessions table.
The PHP Session itself is not closed because there is no need for it. Also, the Session may be needed by other sections of the web application.
However, this Session can no longer be used to log in with sessionLogin().
This is the code:
/* Logout the current user */
public function logout()
{
/* Global $pdo object */
global $pdo;
/* If there is no logged in user, do nothing */
if (is_null($this->id))
{
return;
}
/* Reset the account-related properties */
$this->id = NULL;
$this->name = NULL;
$this->authenticated = FALSE;
/* If there is an open Session, remove it from the account_sessions table */
if (session_status() == PHP_SESSION_ACTIVE)
{
/* Delete query */
$query = 'DELETE FROM myschema.account_sessions WHERE (session_id = :sid)';
/* Values array for PDO */
$values = array(':sid' => session_id());
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
}
}
To check whether the current remote user is authenticated, you can use the isAuthenticated() method.
This function returns the $authenticated property, which is set to TRUE after a successful authentication:
/* "Getter" function for the $authenticated variable
Returns TRUE if the remote user is authenticated */
public function isAuthenticated(): bool
{
return $this->authenticated;
}
Hey, you are almost done!
Before looking at some code examples in the next chapter, there is one more bonus method I want to show you.
This function closes all the account open Sessions except for the current one.
In other words, it’s what you need to do if you want to implement the “Exit from all my other open sessions” functionality you probably saw in some online service (like Google or Facebook).
The best part?
It’s insanely simple. Here it is:
/* Close all account Sessions except for the current one (aka: "logout from other devices") */
public function closeOtherSessions()
{
/* Global $pdo object */
global $pdo;
/* If there is no logged in user, do nothing */
if (is_null($this->id))
{
return;
}
/* Check that a Session has been started */
if (session_status() == PHP_SESSION_ACTIVE)
{
/* Delete all account Sessions with session_id different from the current one */
$query = 'DELETE FROM myschema.account_sessions WHERE (session_id != :sid) AND (account_id = :account_id)';
/* Values array for PDO */
$values = array(':sid' => session_id(), ':account_id' => $this->id);
/* Execute the query */
try
{
$res = $pdo->prepare($query);
$res->execute($values);
}
catch (PDOException $e)
{
/* If there is a PDO exception, throw a standard exception */
throw new Exception('Database query error');
}
}
}
I hope you are enjoying this guide! Why don’t you share it with your friends?
It’s just 1 second of your time and you’ll make me happy 🙂
Step 5:
Examples And Download Link
You made it!
In this chapter you will find some clear examples to better understand how to use your new Account class.
You will also find the links to download the whole PHP class file as well as the examples.

How can you use your Account class from your web application?
Let’s see a few examples.
Go back again to your myApp.php example app and open it in your code editor.
Your file should look like this:
<?php
/* Start the PHP Session */
session_start();
/* Include the database connection file (remember to change the connection parameters) */
require './db_inc.php';
/* Include the Account class file */
require './account_class.php';
/* Create a new Account object */
$account = new Account();
All right.
In the following code examples, you will see how to perform all the Account class operations you learned in this tutorial.
To test them yourself, copy the code snippets one at a time and paste them in myApp.php, after the code shown above.
After the examples, you will also find the link to download the class PHP file as well as a myApp.php file with all the examples shown here.
(Note: the getId() and getName() methods, used in the following examples, are simple getter functions to get the $id and $name class attributes).
Let’s begin.
1. Insert a new account:
try
{
$newId = $account->addAccount('myUserName', 'myPassword');
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
echo 'The new account ID is ' . $newId;
2. Edit an account.
$accountId = 1;
try
{
$account->editAccount($accountId, 'myNewName', 'new password', TRUE);
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
echo 'Account edit successful.';
3. Delete an account.
$accountId = 1;
try
{
$account->deleteAccount($accountId);
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
echo 'Account delete successful.';
4. Login with username and password.
$login = FALSE;
try
{
$login = $account->login('myUserName', 'myPassword');
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
if ($login)
{
echo 'Authentication successful.';
echo 'Account ID: ' . $account->getId() . '<br>';
echo 'Account name: ' . $account->getName() . '<br>';
}
else
{
echo 'Authentication failed.';
}
5. Session Login.
$login = FALSE;
try
{
$login = $account->sessionLogin();
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
if ($login)
{
echo 'Authentication successful.';
echo 'Account ID: ' . $account->getId() . '<br>';
echo 'Account name: ' . $account->getName() . '<br>';
}
else
{
echo 'Authentication failed.';
}
6. Logout.
try
{
$login = $account->login('myUserName', 'myPassword');
if ($login)
{
echo 'Authentication successful.';
echo 'Account ID: ' . $account->getId() . '<br>';
echo 'Account name: ' . $account->getName() . '<br>';
}
else
{
echo 'Authentication failed.<br>';
}
$account->logout();
$login = $account->sessionLogin();
if ($login)
{
echo 'Authentication successful.';
echo 'Account ID: ' . $account->getId() . '<br>';
echo 'Account name: ' . $account->getName() . '<br>';
}
else
{
echo 'Authentication failed.<br>';
}
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
echo 'Logout successful.';
7. Close other open Sessions (if any).
try
{
$login = $account->login('myUserName', 'myPassword');
if ($login)
{
echo 'Authentication successful.';
echo 'Account ID: ' . $account->getId() . '<br>';
echo 'Account name: ' . $account->getName() . '<br>';
}
else
{
echo 'Authentication failed.<br>';
}
$account->closeOtherSessions();
}
catch (Exception $e)
{
echo $e->getMessage();
die();
}
echo 'Sessions closed successfully.';
If you have any question about how to use the Account class, just leave a comment below.
Click the link below to download a ZIP file with:
- The Account class script (account_class.php)
- The myApp.php example file with all the above usage examples
- The db_inc.php file with the example PDO connection
Would you like to talk with me and other developers about PHP and web development? Join my Facebook Group: Alex PHP café
See you there 🙂
Step 6:
Login Security
Security is crucial for a web application.
In this chapter you will find some quick, actionable steps to use the Account class securely.
Here we go.

You know that security is crucial for web applications.
And it’s even more important for a web authentication system.
So:
Let’s see what are the steps you should take in order to use this class securely.
1. Ensure Password Security
This class uses password_hash() and password_verify() to store the password hash on the database and to match it against the plain-text password provided by the client.
These functions take care of using a strong hashing algorithm with a pseudo-random salt.
If you need to change how the accounts data is stored on your database, be sure to keep the passwords safe:
If possible, keep using password_hash() and password_verify().
In any case, never store the passwords in plain text and never use weak hashing algorithms (like MD5).
2. Ensure Database Security
SQL Injection attacks are one of the most common attacks used against web applications.
In this tutorial, you used the PDO extension for database operation. Every potentially unsafe string is sent to the database using prepared statements.
If you are not familiar with PDO, you can use the MySQLi extension instead. MySQLi supports both prepared statements (preferred) or escaping.
In any case, I suggest you read my guide on SQL Injection prevention to make sure you know what has to be done to avoid such attacks.
If you need some clear explanation and examples on how to use PDO and MySQLi, you can find everything you need in my PHP with MySQL Complete Guide.
3. Perform Input Validation
Input validation is another cornerstone of web security.
In this class, some basic validation on the username, the password and the account ID values is done by these three methods:
- isNameValid()
- isPasswdValid()
- and isIdValid()
I encourage you to edit these functions and make them as strict as possible.
For example, if you decide the username must contain only a definite set of characters, a good validation step would be to check every character against a whitelist, like this:
function whitelistText($string): bool
{
$valid = TRUE;
$whiteList = 'abcdefghijklmnopqrstuvwxyz123456789';
for ($i = 0; $i < mb_strlen($string); $i++)
{
$char = mb_substr($string, $i, 1);
if (mb_strpos($whiteList, $char) === FALSE)
{
$valid = FALSE;
}
}
return $valid;
}
4. Ensure Sessions Security
The Session ID, used for Session-based login, is sent inside HTTP cookies.
Therefore, the most important thing to do to make it safe is to enable HTTPS.
With HTTPS in place, Session attacks like data sniffing become much harder.
However, Sessions have other potential security flaws (like the Session Fixation vulnerability) that needs to be mitigated by a correct configuration.
The most important PHP configuration values you should check are Use Strict Mode, Use Only Cookies and Cookie Secure.
You can find them inside your php.ini file:
- session.use_strict_mode=1
- session.use_only_cookies=1
- session.cookie_secure=1
Make sure to leave them enabled. However, you may need to disable them when working on your local development environment.
The full list of Session security related configuration options is here.
Exclusive Bonus for Subscribers (highly recommended):
Get the PDF Checklist with the 5 most common PHP Authentication Mistakes you must avoid.

Click To Unlock The PDF
Step 7:
Questions & Answers
In this last chapter you will find the answers to some of the most asked questions about PHP authentication.
If you have any other question, just leave a comment below.

Question #1
How do you encrypt passwords using PHP?
PHP provides an easy way to create secure password hashes and match them against plain text passwords.
In fact, you can create a password hash with the password_hash() function, and match an existing hash against a plain text password with password_verify().
password_hash() takes care of using a strong enough hashing algorithm and adding a pseudo-random salt to the hash.
Question #2
How do you add a password salt using PHP?
A Salt is a pseudo-random string used when encrypting or hashing a string (like a password).
Salts are used to improve protection against some kinds of attack, like dictionary-based attacks.
Different algorithms use salts in different ways, but if you just want to use a salt for password safety, you can rely on the password_hash() function (see the previous question).
In fact, this function automatically adds a pseudo-random salt to the hash for you.
Question #3
Are PHP Session variables secure?
Session data is stored on the server where PHP is running (unless a different Session storage is used). Therefore, Session data is as secure as the server is.
Session variables are not sent through the network. Only the Session ID is.
If configured properly (see the previous chapter about Login Security), Sessions are safe enough for most uses.
In security-critical applications, however, it may be a good idea to set the Session timeout to a very low value (see the session.cookie_lifetime parameter).
Question #4
Can PHP Sessions be hacked?
Session hijacking, or hacking, is theoretically possible.
Two main attack types exist:
Fixation attacks can be prevented by enabling Sessions Strict Mode in your PHP configuration (see the Login Security chapter for the details).
Session Hijacking attacks are a pool of different techniques for stealing or predicting a Session ID, which could then be used by the attacker to impersonate the victim.
Such attacks include traffic sniffing, XSS attacks and MITM (main-in-the-middle) attacks.
Using HTTPS mitigates or solves most of them.
Conclusion
With this tutorial you learned how a complete PHP login and authentication system works.
You saw how to perform a username/password login as well as a Session-based login.
You also learned how to add, edit and delete accounts from the database, how to be sure your system is secure, and more.
Let me know what you think in the comments.
PS If this guide has been helpful to you, please spend a second of your time to share it… thanks!
Thank You very much for this. GOD Bless You
Thank you Chinasa.
This is high-level php mysql stuff. Thankyou so much.
Thank you Samuel.
Hi Alex,
I dit try is by replacing the login with sessionLogin and that works well.
Is there anything against that?
sessionLogin() works until you logout, but a Session-based login (or cookie-based login) should not last forever. It’s better to force the user to login with username and password after some time (days or weeks).
Hi Alex,
I have a problem with the logout function.
In your example you start with calling the login function. That means you need the password, which means you have to fill in the password again or you have to save your password somewhere That would mean a safety risk.
Can’t you do it without using the password?
The password isn’t stored anywhere, so the risk of a password leak is virtually none.
Only a secure password hash is saved on the database. Even if an attacker is able to retrieve that hash, it can’t be used to login in any way.
I hope this solve your doubt, let me know if it doesn’t.
Hi Alex,
I have a problem with your logout example.
Because you don’t close the session itself, after the sessionlogin the it is effectively not loged out.
Why dom’t you add a session_destry()
Hi,
the Session is not destroyed because you may still need it for your web application.
The logout() function takes care of deleting the Session ID from the database, so the user can no longer log in even if the Session is still open (as explained in the logout section).
If you are using the Session only for authentication, you can add the code to close the session in the logout() function.
This article is horrible to follow because of all the code boxes with horizontal scroll bars. Not worth the effort, unfortunately.
Hi Steve,
I’m sorry for that, a WordPress update messed up with the code boxes. The problem should be fixed now, please try reloading the page and let me know how it goes.
Thanks!
Very perceptive, I am really excited with this work it has made loads of work easier for me.
I’m glad this tutorial has helped you, Jerry!
How to hide login if user already logged in
Hi,
you can check whether the remote user is authenticated with isAuthenticated(). For example:
if ($account->isAuthenticated())
{
/* Do not display the login form */
}
else
{
/* Do display the login form */
}
Hi Alex,
This is a really useful and well written tuition blog but …
I cannot get some of the functions to work unless I delete the code following the declaration e.g. public function getIdFromName(string $name): ?int does not work for me if I do not delete the : ?int.
I’ve not come across this syntax before and cannot find it in the PHP manual. Is this something new? I notice you also have functions followed by :bool ; that also do not work for me.
Please put me out of my misery and explain what they do and why they do not work in PHP V7 on XAMPP.
Thanks in advance – Kevin
Hi Kevin,
first of all, thank you very much for your words!
The :int, :bool etc. syntax defines the function return value. So, :bool means the function returns a Boolean, :int means the function returns an Integer number.
The ? before int, : ?int, simply means that the function can also return a NULL value.
This syntax is supported from PHP version 7.something, maybe your version is a bit too old. However, you can safely remove all the declarations and everything will work exactly the same.
The only purpose of those declarations is to make the code more solid, but the functionality is exactly the same.
Let me know if everything works for you after removing them.
Hi Alex,
Cancel that , I’ve just found the answer.
It seems that PHP7 introduced strict return data types – I must have missed this.
Also, I must no be running PHP7 or above in XAMPP. I need to check.
Thanks again for a very useful class.
Kevin
Hi Alex, at what point do we modify the $ _SESSION variable so that we can later compare its existence in cases where a user successfully logs in, and renders a restricted view such as ::(View_dashboard) and later makes the logout
Hi Igor,
thanks for your question.
The class uses the Session ID only. No other information is written in the $_SESSION array, unless you write it yourself. This way, you have more control over the users and you can perform operations like closing all the open sessions (there is an example in the tutorial for that).
The “$account->sessionLogin()” check can be used to check the Session, much like you would do with “if ($_SESSION[‘login’])”.
So:
if ($_SESSION[‘login’])
{
render page…
}
Becomes:
if ($account->sessionLogin())
{
render page…
}
The class method does it all for you, and it’s more safe. Of course, you can also set a $_SESSION variable if you prefer.
Let me know if it’s clear.
Ok, only AFTER downloading the code I have been to correctly figure out the aim of this tutorial
I suggest this slight modification to the intro
from
“We are going to write a PHP class named User that will provide all these functionalities. We will also see how to add new accounts and how to edit and delete existing ones using static functions.”
to
“The end goal of this tutorial is to create a reusable PHP class that holds and provides all the users, logins and sessions functionalities.
I’ll treat one by one all the sections of this User class and we will also see how to add new accounts and how to edit and delete existing ones using static functions and
at the end of this post you will also find a link to download the full Class code assembly”
This little distinction allows the newbie to get the point of the first PDO snippet .. I was asking myself … what is this? A stand alone file? Should I put it somewhere into my code?”
At first sight I was not realizing that it was one section of a class we were going to build, many newbies would give up with these abstractions 🙂
I hope you get what I mean
Regards
P.S. Do you kindly have a link to a tutorial where you use this class? Just to see its correct implementation. Thank you
Hi Robert,
thank you for your insights.
I’m rewriting this tutorial from scratch (to make it simpler, better and more comprehensive), it should be ready by the end of this week. Stay tuned 🙂
Thank you for the tutorial
Just wanted to hint that at the very begin … you just start talking like
“Our User class will work with two database tables: the first is called accounts and the other one is called sessions.”
but you don hint 🙂 which is the name of the db that later you will use, “test”.
It is just a little particular, but newbie following the tutorial step by step will be confused
Thank you for all of this your website
I don’t understand how we are to instantiate the user class without resetting the user_id variable. The cookie_login function is reliant upon the login function returning true (and setting the correct user_id), meaning that we have to login using username and password to populate the user_id in order for the cookie_login function to be able to compare the logged in users id in the database, defeating its purpose entirely. Every time I refresh the user class is re-instantiated and the variable reset to the default null, meaning i have to re-login. The code would make a lot more sense if the front end php/html was available to view.
Hi Alex,
thank you for this guide!
I’m having a problem understanding the beginning of the login function, specifically the following IFs:
———————————————————————————————–
if ((mb_strlen($name) 24))
return TRUE;
if ((mb_strlen($password) 24))
return TRUE;
———————————————————————————————–
We are checking both username and password, but why are we returning TRUE?
If the name is too small / too big, shouldn’t we return FALSE or is there a reason we are returning TRUE that I do not see?
Thanks in advance,
Peter
Im getting this error on trying to use the class! Any ideas?
Warning: Missing argument 1 for User::__construct(), called in C:\xampp\htdocs\UserDashboard\test.php on line 6 and defined in C:\xampp\htdocs\UserDashboard\classes\auth_class.php on line 57
Notice: Undefined variable: db in C:\xampp\htdocs\UserDashboard\classes\auth_class.php on line 65
Nevermind I fixed it! It was late and I was being an idiot!
Hi,
Thanks for sharing this. I am still learning a lot about OOP and I tried to understand your code. However, I couldn’t figure out at what point you would get notified if one would enter an existing user name but a wrong password. Obviously, the password_verify would not work but would it also return a boolean ” false” back to the login page?
Or how is this done?
HI Alex can you make similar topic in procedural way also. This topic helps me in grooming my OOP concepts.
Hi, I’m actually rewriting this tutorial from scratch to make it better and easier to understand. I’ll make sure to clearly explain the OOP concepts.
Thanks! Waiting for it….
Alex,
Your article is good, but it’s missing some critical information like how to create the database in the first place. I have prepared a couple of files for you to include in this article to help someone get this thing working from the ground up, in a HOWTO kind of way. Would you be interested in getting the files from me and including them in this article, so it becomes even more accessible?
Professor Graham Leach
Blockchain Curriculum Lead, MSc-MET
School of Design, Hong Kong Polytechnic University
Hi Graham,
thank you for your comment.
Truth is: I’ve already scheduled a complete rewrite of this post to make it more clear and complete.
I would love to get the files from you and see how I can use them for the post rewrite, so feel free to send them to me.
Thanks
Hi Alex,
Sorry to have another question, just trying to figure out how it works so I can actually use it properly. And i found something with the login that seems ‘off’ to me, but maybe it is intended this way.
At the start we set the constant ‘session_time’
And we use this in the creation of the cookie, in the create_session function.
I see we store login time etc. but I don’t see anywere were we check on the server side of it is still a valid session. I would expect something in the cookie_login, possibly in the select query.
As it is now, I set the session time to 1hour yesterday. Logged in, left the tab alone. Today I went back to the tab, changed the cookie expire time on the client side.
And I could continue to use the login.
I would assume you might want a server side check on the expire as well.
I could also add a separate cron script to clean up the database of old sessions, which I would most likely do anyway. But should the select not have an extra ‘where session_time not expired’. So you check this server side the moment a page is called. The query is run anyway, so why not check the expire as well?
Hi,
you’re right!
You can change the query inside cookie_login(), just like you said, but even better: you can create a private function to clean all the expired cookie sessions and call it before logging the user in.
That will solve both the authentication and the clean up problems.
Right now I cannot edit the post but I’ll do it asap. I’ll reply here when it’s done.
Thanks again for pointing it out 🙂
Hey Martijn,
thanks again for your feedback.
I just added the clean_sessions() function: it takes care of deleting all expired sessions from the database.
The cookie_login() function calls clean_sessions() right before checking the cookie. Let me know if you like this solution.
Hi Alex,
After playing around with it, I still like it a lot.
I managed to add 2 optional 2fa methods, all works great. Learning a lot about doing it the ‘OOP’ way.
But I was just thinking security wise: Could the cookies not be brute forced AND what to do about it?
I know its quite a long string of ‘random’ numbers/chars, but…
In theory, someone could try over and over again with a different cookie value, until you get a hit right? I know someone else needs to have a valid login with a cookie with the same value, in the same timeframe. And if I use what I learned from this script on a website, and the website becomes more popular, the greater the change this could happen right? (the greater the pool of valid cookie values, the greater the change someone guesses the right value)
I already shortened the required time to login again. Should decrease the amount of valid cookie values.
But is this a valid concern and what could be done about it.
Hey Martijn,
nice question.
Guessing a cookie is indeed possible, but even a popular website doesn’t usually have so many logged users (millions / billions). Also, trying lot of different cookie logins is a very suspect behaviour that would be probably detected by the server intrusion detection system (all hosting services have one).
Anyway, a way to improve cookies’ security is to make them bigger. For example, you could use a 64bit string or even a 128bit string instead of a 32bit one. That way, the chances of guessing a valid cookie are reduced dramatically.
You can also save some browser’s information along with the cookie, like the browser’s name and version, the operating system and so on. Since cookies are bound to browsers that information does not change, and an attacker would need to replicate them as well for the login attempt to be successful.
Hi Alex,
I see, I was thinking about browsers as well, also knowing that that can be quite easily ‘faked’ – but as you say, in combination with the random string – jacked up to 64/128bit would be an extra layer that needs to be ‘faked’.
Thanks for the input, had not thought about it that way.
Hi Alex, great tutorial. Gave me some great insight in classes, a part of PHP I had not used yet.
But I’m trying it out and the login check doesn’t seem to work properly for me.
I assumed from reading this tutorial that you check if the visitor is logged in via this:
if($user->cookie_login() == TRUE){ //logged in }else{ //not logged in }
But this always returns logged in for me.
I made a page that included the class, does $user = new $User($db); and then the check. When I visit the page, it always shows logged in. even in another browser.
I also did a var_dump of $_COOKIE, just to be sure. But it doesn’t matter if there is or isnt a cookie. it is always logged in according to the script. -> and thats exactly what we were trying to prevent whit this I assume 🙂
The rest of the script seems to work, I can register a user, a new user shows up in the DB, when I use the login part, a cookie is created and a sessions entry is created in the DB
Any idea what might be wrong?
Hi Martijn,
I read my code again I see that it’s not very clear. I apologize for that.
The functions in this class return true if no errors occur, false otherwise.
cookie_login() returns false only if there is an error (like an SQL error), otherwise it always returns true.
To see if the user is actually authenticated, you have to check the is_authenticated attribute (which is private, so you have to make a getter function).
This true/false behaviour is used in some advanced applications but it’s probably misleading here. Sorry for that.
I definitely need to update this post with a more user-friendly code 🙂
Hi Alex,
As being new to OOP it was not clear to me. Having read up about it, I see what needs to be done. I think the script itself is still great, the text around is just a bit unclear to a beginner.
Thanks for the quick reply. I’ll try to work something out 🙂
I do not see a is_authenticated attribute in your class, anywhere. Am I missing something?
Hi,
I have updated the tutorial a few days ago. The attribuite you are looking for is the $authenticated property, which is private and can be retrieved with the isAuthenticated() class method:
if ($account->isAuthenticated())
{
echo ‘User authenticated’;
}
else
{
echo ‘User *not* authenticated’;
}
Great tutorial. But wondering where is the download link! 😀
Download link added (thanks!) 😉
so where is the completed code now and how do we implement it
Hi Will,
you can simply copy the class definition (the code snippet beginning with “class User”) and then copy all the functions inside the class.
Then, it’s just a matter of including the class in your project, just like you would do with any other class, and create a new “User” object.
At the beginning of the tutorial you can also find the SQL code to create the tables used by the class and an example of how to create a PDO connection.
If you prefer to download a full example file I can prepare one and add a download link at the end of the tutorial.
Hi Alex,
I’m trying to use your class on a web app I’m developing from scratch (OOP noob here). Can you please have a full example – with implementation? No need for pretty forms, just the basic look.
Thank you!
Hi Alex, perfect material, as always. Didn’t you think about to expand your tutorial to use both DB table and LDAP authentication? I’m not very skilled in php and I need to make authentication both ways. LDAP authentication is not very difficult to setup and I have already working solution, but I’m not sure how to implement it to your solution.
Hi Marc, yes, that’s a good idea. Thanks for the suggestion.
This is my oldest tutorial so I will probably update it in the near future to make it more clear and complete. I will take care of adding an LDAP authentication section too.
This is excellent stuff. Thankyou so much. I have one question tho, I am doing 2 step auth and am using a session as the only obstacle in the way for full access is this secure enough?
It’s very simple but is it too simple that it is insecure. In the user table based off of ur class i have added a column called extra_security. 0 = off / 1 = on and when u login this is part of session creation: $_SESSION[‘uaccess’] = ($user[0][‘extra_security’] == 0 ? ‘1’ : ‘0’); and if on you go to 2nd screen and then i just set the session to uaccess 1 you then have full access but of course if disabled it is full access straight away.
The logic for 2 step auth: Login->ifcorrect(create session with all data but uaccess = 0)->Login2->ifcorrect(set uaccess = 1)->full access
Sorry for my wording but just want to make sure what i am doing is secure or how i could make it more secure as ur class is amazing!
Hi Jack,
generally speaking, it’s perfectly fine to use sessions to track users’ authentication steps.
Your 2-step logic seems fine, too. You may also consider using a different cookie for the second authentication step, so you can use different login timeouts (for example, asking for username/password every time but for the second step only once a week).
How is the second step implemented?
Hi Alex,
Thanks for your quick reply. How would you suggest i do the cookie to keep validating?
The 2nd step is implemented by a switch case system. If 2 step auth on run the correct create session function otherwise do normal function then if 2 step on it redirects you to login2 which is a page you can only access if partloggedin() and asks you to enter a code. For the 2 step auth i based it on this tutorial but made my code neater etc. https://www.9lessons.info/2016/06/google-two-factor-authentication-login.html
switch ($userAuthenticated[0][‘extra_security’]) {
case1:
$this->createUserExtraSession($userAuthenticated);
break;
default:
$this->createUserSession($userAuthenticated);
}
Also can i ask if you arte able to share the session table sql code & also for your opinion on sql table structure. I am currently doing verify / forgot password and am wondering should i create the columns in the user table (verify_code, reset_code, reset_code_issued) or should i create a token table with code, issued, type) what do you think would be best.
Thanks again
Hey Jack,
would you mind joining my Facebook group to keep talking there?
Sharing lot of code is quite difficult here on the blog comments, in my opinion.
Here’s the link: https://www.facebook.com/groups/289777711557686/
Thanks
For the cookie_login function, where is the column ‘session_login’ coming from?
UNIX_TIMESTAMP(session_login)
Hi Tan!
Sorry, my mistake: it’s “session_start”, not “session_login”. I have fixed it, thanks for pointing it out!