Advanced User Authentication Using Sessions

I am creating a website with three types of users:

-those who are registered and are subscribed for current month -those that are registered, but are not subscribed for current month -users that are not registered (you cant be subscribed if you are not regitered) 

I have created code that identifies these 3 kinds of users and acts accordingly. My question is, is that so? I’ve never done this before. Or should I reprogram my approach?

//login.php

 //connect to database and see if a user and password combination exists. Store $exists=0 if not, and $exists=1 if it exists. session_start(); $conn = new mysqli($hn,$un,$pw,$db); if ($conn->connect_error){ die($conn->connect_error); } $query = "SELECT COUNT(1) as 'exists',expiration_date FROM table WHERE email = ? AND password = ?;"; $stmt = $conn->prepare($query); $stmt->bind_param("ss", $email, $password); $email = $_POST["email"]; $password = hash("hashingalgorithm", "salt".$_POST["password"]."salthere"); $stmt->execute(); /* Get the result */ $result = $stmt->get_result(); $num_of_rows = $result->num_rows; $row = $result->fetch_assoc(); $exists = $row["exists"]; $expiration_date = $row["expiration_date"]; /* free results */ $stmt->free_result(); /* close statement */ $stmt->close(); $conn->close(); date_default_timezone_set('Europe/Berlin'); if ($exists==0){ echo "Wrong email or password"; $_SESSION['loginerror'] = 2; header('Location: https://www.homepage.com/login'); }else if ($exists){ if (strtotime($expiration_date) < (strtotime("now"))){//logged in, but not subscribed session_destroy(); session_start(); $_SESSION["authenticated"] = true; header('Location: https://www.homepage.com'); }else{//logged in and ready to go $_SESSION["authenticated"] = true; $_SESSION["email"] = $email; header('Location: https://www.homepage.com'); } }else{ echo "An error with has occured."; } 

Then on every page of my website I use this code to see which user visited me.

 session_start(); if(isset($_SESSION["authenticated"]) && isset($_SESSION["email"])){ $email = $_SESSION["email"]; //connect to database and fetch expiration_date for a user with $email. Store it in $expiration_date $conn = new mysqli($hn,$un,$pw,$db); if ($conn->connect_error){ die($conn->connect_error); } $query = "SELECT expiration_date FROM table WHERE email = ?;"; $stmt = $conn->prepare($query); $stmt->bind_param("s", $email); $email = $_SESSION["email"]; $stmt->execute(); /* Get the result */ $result = $stmt->get_result(); $num_of_rows = $result->num_rows; $row = $result->fetch_assoc(); $expiration_date = $row["expiration_date"]; /* free results */ $stmt->free_result(); /* close statement */ $stmt->close(); $conn->close(); date_default_timezone_set('Europe/Berlin'); if (strtotime($expiration_date) < (strtotime("now"))){//logged in, but not subscribed session_destroy(); session_start(); $_SESSION["authenticated"] = true; header('Location: https://www.homepage.com'); }else{ //html for subsribed and registered user echo <<<_END //html here _END; } }else if(isset($_SESSION["authenticated"]) && !isset($_SESSION["email"])){ // user is logged in, but not subscribed; echo <<<_END //htmlhere _END; }else{// user is not registered nor is subscribed echo <<<_END //htmlhere _END; } 

The code works, but I'm worried about accessing the database on every page after user registration and signing. I actually punish users for registering and subscribing. Is there a more efficient, effective way to solve this problem?

+7
php login session
source share
7 answers

In my understanding, you already have working code. And what you are asking is opinion. You want to remove duplication on each verification page in the database for authentication and subscription.

In my opinion, you need to change the way you use sessions,

  $_session['email'] // email address of user $_session['auth_type'] // holds authentication type $_session['auth_till'] // subscription expire date 

Then allows you to create a function to verify your subscription. This function can be placed in a separate file, for example: init.php. Here we can set the mechanism for starting the session so that in any case the sessions are available.

 if(!isset($_SESSION)) session_start(); // start session if not already started // lets define global vars to hold authentication type of visitor define("SUBSCRIBED",1); define("UN_SUBSCRIBED",2); define("REGISTERED",3); function checkSubscription():bool{ $return = false; if(($_session['auth_type']==SUBSCRIBED)&&(strtotime($_session['auth_till']) < strtotime("now"))) $return= true; return $return } 

And on login.php, use the same technique when setting up session authentication type.

Now any other page can simply use the function to verify the subscription

eg:

 <?php // file: product.php include_once("init.php"); if(!checkSubscription()){ // subscription finished. do what you need to do. otherwise continue. } 

There are many improvements that can be made with your codes. But I think that would suit your needs. Please let me know if you need an additional assistant. Please visit Scape and let me know if there is any useful coding there.

+1
source share

The solution here is to check subscribers (only on the first page where they go to your site), i.e. inside login.php you could use

 // ...your previous code session_start(); // initialize session variables $_SESSION['subscribe_date'] = $_SESSION['authenticated'] = false; if ($exists == 0){ echo "Wrong email or password"; $_SESSION['loginerror'] = 2; header('Location: https://www.homepage.com/login'); } else if ($exists){ $_SESSION["authenticated"] = true; if (strtotime($expiration_date) > (strtotime("now"))){ //logged in,& subscribed $_SESSION["email"] = $email; $_SESSION['subscribe_date'] = $expiration_date; } else { //logged in and not subscribed, do nothin! } header('Location: https://www.homepage.com'); } else { echo "An error has occured."; } 

Then on every other page, all you have to do is check only $_SESSION['subscribe_date'] , and not run the query every time

 if(!empty($_SESSION["subscribe_date"]) && strtotime($_SESSION["subscribe_date"]) > (strtotime("now"))) { // html for subscribed and registered user } else if (!empty($_SESSION["authenticated"])) { // html for registered user } else { // html for unregistered user } 

Also note that I deleted session_destroy(); A very bad idea to call it on every page. Instead, you can disable session variables. those. unset($_SESSION["email"]); You must call session_destroy(); only at the end when the user logs out. Check the warning section session_destroy ()

+2
source share

If it were me, I would split and reorganize these codes into external classes / functions. But if we are talking about small tweaks to your code, here is what I should do:

login.php

 //connect to database and see if a user and password combination exists. Store $exists=0 if not, and $exists=1 if it exists. session_start(); $conn = new mysqli($hn,$un,$pw,$db); if ($conn->connect_error){ die($conn->connect_error); } $query = "SELECT COUNT(1) as 'exists',expiration_date FROM table WHERE email = ? AND password = ?;"; $stmt = $conn->prepare($query); $stmt->bind_param("ss", $email, $password); $email = $_POST["email"]; $password = hash("hashingalgorithm", "salt".$_POST["password"]."salthere"); $stmt->execute(); /* Get the result */ $result = $stmt->get_result(); $num_of_rows = $result->num_rows; $row = $result->fetch_assoc(); $exists = $row["exists"]; $expiration_date = $row["expiration_date"]; /* free results */ $stmt->free_result(); /* close statement */ $stmt->close(); $conn->close(); date_default_timezone_set('Europe/Berlin'); if ($exists==0){ //removed echo, you shouldn't output anything before headers $_SESSION['loginerror'] = 2; header('Location: https://www.homepage.com/login'); //use exit after each header redirect exit; }else if ($exists){ //moved to the top to minimize code redundancy $_SESSION["authenticated"] = true; //it good to have user identifier (eg email) accessible for all authenticated users $_SESSION["email"] = $email; if (strtotime($expiration_date) <= (strtotime("now"))){//logged in, but not subscribed //unset only subscribed sessions, do not destroy all sessions unset($_SESSION["subscribed"]); header('Location: https://www.homepage.com'); exit; }else{ //logged in with active subscribtion $_SESSION["subscribed"] = true; header('Location: https://www.homepage.com'); exit; } }else{ echo "An error with has occured."; } 

code on each page is included

 session_start(); if(isset($_SESSION["authenticated"])){ //merged if-statement for both subscribed and unsubscribed user $email = $_SESSION["email"]; //connect to database and fetch expiration_date for a user with $email. Store it in $expiration_date $conn = new mysqli($hn,$un,$pw,$db); if ($conn->connect_error){ die($conn->connect_error); } //check if subscribed user is still subscribed and unsubscribed user is still unsubscribed $query = "SELECT expiration_date FROM table WHERE email = ?;"; $stmt = $conn->prepare($query); $stmt->bind_param("s", $email); $email = $_SESSION["email"]; $stmt->execute(); /* Get the result */ $result = $stmt->get_result(); $num_of_rows = $result->num_rows; $row = $result->fetch_assoc(); $expiration_date = $row["expiration_date"]; /* free results */ $stmt->free_result(); /* close statement */ $stmt->close(); $conn->close(); date_default_timezone_set('Europe/Berlin'); //I have separated expiration verification and template echoing //first - expiration verification if (strtotime($expiration_date) <= (strtotime("now")) && isset($_SESSION["subscribed"])){ //had been subscribed a second ago, but now he not unset($_SESSION["subscribed"]); header('Location: https://www.homepage.com'); exit; }else if (strtotime($expiration_date) > (strtotime("now")) && !isset($_SESSION["subscribed"])){ //had been unsubscribed, but renewed subscription in the meantime (maybe in another browser with this session still active) $_SESSION["subscribed"] = true; header('Location: https://www.homepage.com'); exit; } //user successfully passed expiraton verification, maybe was few times redirected //second - template echoing if (isset($_SESSION["subscribed"])) { // user is logged in and subscribed; echo ''; }else{ // user is logged in, but not subscribed; echo ''; } }else{ // user is not registered echo ''; } 

Before each code change, comments appear. Here is a short list of the changes I made:

  • use exit after redirecting each header: php - Should I call exit () after calling the Location header:
  • do not output before headings
  • Use 3 session verification variables for each authenticated authenticated user, subscription, and email.
  • do not destroy the whole session if the user is not subscribed, use unset instead
  • I combined both authenticated users (signed and unsubscribed) into a single if statement
  • I checked the expiration check and echo output in the next two steps.
  • on each page I check whether the user has subscribed (the subscription may expire during his session), and if the subscriber has not subscribed, he can use two browsers with active sessions.

There are other minor tweaks that I would do (move date_default_timezone_set on top of each file, etc.), but they are not the subject of your question.

+1
source share

Use a PHP session variable to store information about the current user before executing SQL queries each time the page loads.

For example, when a user logs in, save the user ID for this user session in a session variable:

 $_SESSION['user_id'] = <userid>; 

When loading the next page, check this session variable before running the database query.

 if ($_SESSION['user_id']) { // normal operations } else { // Make your database call } 
+1
source share

In general, when a user logs in for the first time, set the two status flags to $_SESSION :

  $_SESSION['loggedIn'] = true $_SESSION['subscribed'] = bool //true or false 

I assume that only registered users can log in. If the user does something to change their state, update $_SESSION accordingly.

Note: make sure the session is active before checking the values. Also, use session_regenerate_id to prevent session fixation.

Truly complex types can try to serialize the User object and store it in $_SESSION . Then, at each page load, the properties of the User object can be marshaled (unesterified) and come to life again in a new instance of the User object. In this world, you simply check the properties of the User object to make sure that it (a) is registered and (b) signed. The state of the User object will be your interest, not just the highlighted values ​​in the supergalactic $_SESSION .

PHP Guide: Serializing Objects

Book: Object-Oriented Thinking (4th Edition) : See Chapter 12

+1
source share

on login.php you already get expiration_date from the database, you can save it in a session variable

 $_SESSION['expiration_date'] = $row['expiration_date']; 

and on each page you can use the above value to check instead of DB query

 if (isset($_SESSION['expiration_date']) && (strtotime($_SESSION['expiration_date']) < (strtotime("now") )) 
+1
source share

The PHP session model allows you to start a session and retrieve later all the data related to the session that was serialized and stored in the $_SESSION .

Correctly worry about database calls that cause access to each page. Session data can be set using cookie or returned inside the POST or GET method. Therefore, you need to determine the appropriate method for repeating the PHP session identifier and session time of the session.

 $_SESSION['name'] = 'value'; // Stores Session values to avoid database requests ... session_id($sid); // sets the id of existing session session_start(); // retreive stored session data; 

You can set once such flags as registered and subscribed for beinh, which are used later, without database queries during the session or special actions:

  • Subscription - No expected action expected. The user has already met all expectations.
  • Registered - can only subscribe. Thus, before the signature action is signed, the user environment can maintain the database idle until the subscription is requested.
  • Not registered - can only be registered. No data stored. No database queries.

When the session starts, the subscribed and registered flags will be set to FALSE until authentication passes. So, my opinion is that the database should be called only three times per session: when the user is authenticated, registered or signed. As the code shows, you are passing data through POST . Add a hidden sid field to all forms to preserve the session ID. And SELECT from the database all the necessary data (and not the password, of course), which can be useful during the session for user interaction.

+1
source share

All Articles