Jump to content

Recommended Posts

Hello,

 

how can I restrict a page from login authenticating against info in a MySQL DB for a second time? Right now a login check against username and password in a MySQL table and allows access against that data. This works fine, but I want to disallow access once a person has logged in once and logged out.

 

My current code

 

<?php
//ini_set("display_errors","1");
//ERROR_REPORTING(E_ALL);

session_start();
/*logout after 65 minutes*/
function login_validate() {
/*Set the timeout on a login session. */
/*Default timout is ten minutes (600 seconds). */
$timeout = 15;
$_SESSION["expires_by"] = time() + $timeout;
}

$con = mysql_connect("localhost","ETSI","Editor") or die('Could not connect: ' . mysql_error());

mysql_select_db("ETSI_Internal") or die(mysql_error());




// Same checking stuff all over again.
if(isset($_POST['submit'])) {
   if(empty($_POST['username']) || empty($_POST['pwid']) ) {
    echo "<h2 style='color:#039;font-size:14px;font-family:arial, helvetica,sans-serif'>Please fill in both your username and password to access the editor exam. You will be redirected back to the login screen in 5 seconds</h2>";
  echo "<meta http-equiv='refresh' content='5; url=EditorLogin.php'>";
                exit;
   }
   // Create the variables again.
   
   $username = mysql_real_escape_string($_POST['username']);
   $pwid = $_POST['pwid'];

   // Encrypt the password again with the md5 hash. 
   // This way the password is now the same as the password inside the database.
   //$pwid = md5($pwid);

   // Store the SQL query inside a variable. 
   // ONLY the username you have filled in is retrieved from the database.
   $query = "SELECT username,pwid,name
           FROM   Table
           WHERE
           pwid = '$pwid'
           AND
           username='$username'";

   $result = mysql_query($query) or die(mysql_error());
   if(mysql_num_rows($result) == 0) { 
      // Gives an error if the username/pw given does not exist.
      // or if something else is wrong.
     echo "<h2 style='color:#039;font-size:14px;font-family:arial, helvetica,sans-serif'>You have entered a username or password that does not match our database records. please try again. You will be directed back to the login screen in 5 seconds. </h2> " . mysql_error();
echo "<meta http-equiv='refresh' content='5; url=EditorLogin.php'>";
exit();
/*
this would benefit from a redirect to a page giving better information to
the user and maybe logging some errors.
*/
   } else {
      // Now create an object from the data you've retrieved.
      $row = mysql_fetch_object($result);
      // You've now created an object containing the data.
      // You can call data by using -> after $row.
      // For example now the password is checked if they're equal.

      // By storing data inside the $_SESSION superglobal,
      // you stay logged in until you close your browser.
  $_SESSION['name'] = $row->name;
     $_SESSION['username'] = $username;
      $_SESSION['sid'] = session_id(); 
      // Make it more secure by storing the user's IP address.
      $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
      // Now give the success message.
      // $_SESSION['username'] should print out your username.

//move this to after your redirect further below..
      
   }
}

// Start a session. If not logged in will be redirected back to login screen.

if(!isset($_SESSION['username'])){
header("Location:ExamLogin.php");
exit;
}
echo "<div id='welcome'><h3>Welcome! You are now logged in " . $_SESSION['name'] . "</h3>";

echo "<a class='logout' href='logout.php'>Logout</a></div>";

?>

you could do that.

 

i would simply put it in the user table if they are only allowed to log in once with a given user/password.

 

sometime like login_flag.

 

check the flag as well as the username and password when they log in. if they have a successful login then update that user record and set the flag. now it won't be usable again. if you want to keep a login timestamp you can just add another field and update that when you update the flag.

 

hope that makes sense.

somewhat. So login_flag would be a field in my user table, and I could set it up as INT and insert a 1 when the user logs in. I guess I would just need to write another SQL query to do this?

 

$query1 = "INSERT  INTO tablename
           SQL query here

 

confused on how I would do the checking though in PHP

basically your standard login code except check for login_flag = 0 as well as the username/pw when they try to login.

 

if it all checks out and they log in then just do an update

 

UPDATE users SET login_flag = 1, login_date = NOW() WHERE user = username

(assuming the you want the login timestamp)

 

something like that.

ok, I think I can get that part to work (won't be trying till Monday). What about echoing a message once they have logged/in out once advising them of the restriction? Would it be something like IF {login_flag ==1 echo "you have already logged in"} ?

ya something like that. you can check the user/password first then echo a statement if that fails ("login failed"). if the user/pw checks out then check the flag and if that fails echo "already logged in once" or whatever you like.

 

it seems like you're on the right path.

Just a thought...

if u use sessions, you can store the session id in the user record.

since php maintains the sessions, (and you can have it expire after a certain amount of time)

u just need to compare a session id and whats stored in the user record.

but of course, you will need another variable in the session, to know if this is a new session or an ongoing session.

 

I currently am using sessions. Anyway you can post a little code to give me an idea of what you are referring to? Also, would I still need a flag in MySQL.

 

Just set the login time when the user logs in the first time as schilly suggested. Then when a user attempts to log in you can ascertain that the account has already been used to log in previously. Then once the user's session ends they will not be able to get back in using the previous credentials.

problem with time, or login values, your not shure from which user its coming from, reason I suggested the session id, since session id's are pretty unique, u can say that if the sessionid matches whats in the user record, than the user is logged in already. since php handles cleanup of the sessionid, this will also nullify long standing logins (ppl who dont logout)

 

login.php

<?php
session_start();
$user=array();
if(isset($_SESSION['loggedin']) // user already logged in
   die('Already Logged in');
/* query database for username and password */
/* assume we fetch userrecord into $user */
if(!empty($user)) { // valid user record, so login info was correct
  die('Invalid User/Password');
$_SESSION['loggedin']=$user['id'];
$sessionid=sessionid();
mysql_query('UPDATE users SET sessionid='{$sessionid}' WHERE id={$user['id']}"; // Update user record with their session id

<?php

 

logout.php

session_start();
if(isset($_SESSION['loggedin']))
{
    // query db for userrecord, $user holding the user record
   if(sessionid()==$user['sessionid']) session_destroy();
}

 

otherpages.php

<?php
session_start()
if(!isset($_SESSION['loggedin'])
  die('Must be logged in');
$sessionid=sessionid();
$user=array();
// query db to retrive userrecord, note, that the userid logged in is in $_SESSION['loggedin'])
// so can do something like mysql_query("SELECT * FROM users WHERE id={$_SESSION['loggedin']} AND sessionid='{$sessionid}'");
if(empty($user))
  die('Invalid authentication');

 

just some sample code, but should give ya a general idea.

problem with time, or login values, your not shure from which user its coming from, reason I suggested the session id, since session id's are pretty unique, u can say that if the sessionid matches whats in the user record, than the user is logged in already. since php handles cleanup of the sessionid, this will also nullify long standing logins (ppl who dont logout)

 

You shouldn't need to know "which" user it is coming from. User's should be using different login credentials anyhow. Otherwise a user can just go to a different computer and log in. The OPS requirement was

how can I restrict a page from login authenticating against info in a MySQL DB for a second time?

 

So, the first time a login credential is used, simply set a value to show that it was used and log the person in. The OP already stated he was already maintaining the session. I think you are overcomplicating the requirement. Heck, you could even just delete the record with the login credentials after the credentials are used.

Its not overcomplicated.

 

Those solutions provide no way for cleanup, if a user doesnt logs out. This means you will have to provide cleanup code yourself which should run on a interval basis.

php sessions provide for that with expiration perioids, so do coookies but cookies can be falsified.

 

storing a sessionid in the userrecord provides authentication that the user logged in, as sessionids are approx of 26 characters in length, it provides for a decent authentication that the user logged in within the expiry period of the session.

 

if you can show me example code of in as little code as I provided, with cleanup, I might believe that just using a db field loggedin can be simpler.

 

 

 

 

But, you are "assuming" the code should be cleaned up. There may be reasons to retain the data for historical purposes. Likewise, if you don't need the data for historical purposes, then just delete the record when the user logs in and no further clean-up is needed. One other consideration is if the system should provide a warning (e.g. "That username/password has already been used"). In that situation, it "might" make sense to purge records after some time, but still you don't have to. Just use the logon timestamp to determine if the user should be told those credentials have already been used or if you just want to tell them the credentials are not valid.

Example code

$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);

$query = "UPDATE `logins`
          SET `login_timestamp` = NOW()
          WHERE `username` = '$username'
            AND `password` = '$password'
            AND login_timestamp = ''";
$result = mysql_query($query);

if(!$result)
{
    //Query failed, add error handling
    $response = "Query failed";
}
else if(mysql_affected_rows()!=1)
{
    //Record doesn't exist OR credentials have been previously used
    //Can either provide a single error/warning condition, OR can
    //provide different messages for the two conditions as follows:

    $query = "SELECT `login_timestamp`
              FROM `logins`
              WHERE `username` = '$username'
                AND `password` = '$password'";
    $result = mysql_query($query);

    if (mysql_num_rows($result)==1)
    {
        $record = mysql_fetch_assoc($result);
        $response = "That username/password was used on {$record['login_timestamp']}.";
    }
    else
    {
        $response = "That username/password is not valid.";
    }
}
else
{
    //Credentials have not been previously used, log user in
}

Thanks for debating this. It may help if I provide what I am attempting to create and why. I will have an online test for people to take. They will need to login to access this test. The login will be authenticated from a MySQL table which will contain their username and password (the user will be provided this). the exam has a time limit of 60 minutes. After 60 minutes or so, I want to create an automatic logout taking them back to the login screen. If they try and login again, that is when I want to check and see if they logged in previously and if so, restrict another login.

OK, that would have been helpful previously. So, I would assume that if the user, for some reason, closes their browser and then attempts to log in within 60 minutes of the initial login that the user should be able to get back in, correct? Then, a small change to the sample code I provided should work. However, you would need to determine what should happen if a user has a subsequent log in within the 60 minutes. Are you storing thier answers or are they going to have to start over. Also, if the user completes the test do you still want them to be able to log in within the 60 minute time period? If not, you may want to add a "login_allowed" flag as offered previously.

 

Example code

//Escape user input
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
//Update record with current time IF the account has never logged in before
$query = "UPDATE `logins`
          SET `login_timestamp` = NOW()
          WHERE `username` = '$username'
            AND `password` = '$password'
            AND login_timestamp = ''";
$result = mysql_query($query);
//Check if query ran succesfully
if(!$result)
{
    //Query failed, add error handling
    $response = "Query failed";
}
else
{
    //Set flag
    $error = false;
    if(mysql_affected_rows()!=1)
    {
        //Record doesn't exist OR credentials have been previously used
        //Run query to see when the initial login was
        $query = "SELECT `login_timestamp`
                  FROM `logins`
                  WHERE `username` = '$username'
                    AND `password` = '$password'";
        $result = mysql_query($query);

        if (mysql_num_rows($result)!=1)
        {
            //username/password doesn't exist
            $error = "That username/password is not valid.";
        }
        else
        {
            //Get record and check first login time
            $record = mysql_fetch_assoc($result);
            if ($record['login_timestamp']<strtotime("-60 minutes"))
            {
                //username/password was used more than 60 minutes ago
                $error = "That username/password has expired";
            }
        }
    }
    //Check if error occured
    if ($error == false)
    {
        //Credentials have not been previously used OR user
        //logging back in within 60 minutes of initial log in
        //
        //Log user in and restore date 
    }
}

thanks for the code. I would like to store their answers, so if they close the browser and log back in, the answers will still be there and they won't have to start over. Does the code you provided do the logging out or is that something I still need to add. (sorry haven't actually tried it yet).

There is no "logging out" per se. Yes, you could create a Log Out button, but the only time that really makes sense, IMHO, is a financial/shopping site where another user could potentially launch back into a site with sensitive information. 99% of the time users simply close the browser window which destroys the session. (OK there is no such statistic, I just base that on my personal experience and what I typically see other users do).

 

But, the solution is still simple enough. As the users progresses through the test you will need to store their answers to the database. Then if the user logs back in within the 60 minute time period you will be able to determine that. After the user logs in, just query the database to see if there are stored results. If so, you could either take them to the first unanswered question or start them from the beginning and display their previous answers as they step thorough the questions. Personally, I would give the user the option to do either.

I was going to create the exam though as one long form, and one submit button at the bottom to submit all of the answers at once. Would it be better to have a submit for each question/answer? Also, what would prevent the test take from using more than 60 minutes without an automatic logout mechanism?

I was going to create the exam though as one long form, and one submit button at the bottom to submit all of the answers at once. Would it be better to have a submit for each question/answer? Also, what would prevent the test take from using more than 60 minutes without an automatic logout mechanism?

 

Typically, an exam like this is implemented with a single question presented at a time. Of course you can have a single form with all the questions presented, but there is no way to "save" a partially completed test if the user was to accidentally close the browser (it does happen). Well, there is a way to do timed saves using AJAX, but IMHO, that is only making this more complicated than it needs to be.

 

So, if you make it one long form, then the user will need to submit in order for any data to be saved. And, at that point, the whole quiz would be complete anyway I guess. As for an "auto-logout" mechanism you need to be more specific. I was only referring to a function for the user to manually log out which, as I stated above, is kind of pointless in most situations as people don't use it. It seems you are really talking about enforcing the 60 minute time period.

 

For enforcing the time period, you already have the information you need if you are saving the login timestamp. If the person submits a form after 60 minutes of the login, then you reject the submission. This is another reason why having one question submitted at a time would be advantageous as the user could save questions during the time period. With an all-or-nothing approach, if the user exceeds the 60 minutes before submitting the long form, then the user would not get any credit for questions they answered within the time period.

 

In any event, you will want to give the user some visual cue as to the time remaining. JavaScript would be a good method since you could use it to provide a countdown. However, what if the user has JS disabled? If using a long form I would have the page state a static time of when the 60 minutes will end (i.e. "You must submit your answers by 10:22am"). If using a multi-part form, then you could print the time remaining one page load for each question.

 

What it comes down to is you need to develop a process for the workflow of your application. This is before writing any code. Sit down and map out the processes on paper and ensure you have captured all the use cases and exception scenarios. Then write your code.

I think I have a pretty good idea of what I want. I was going to use a flash timer, but that may be too distracting as the user may stare at that instead of the questions.  I also think one question at a time would work, but not sure how to code that. Would it involve JavaScript/JQuery or can it be done w/ just HTML/PHP?  Printing the time remaining when each question is presented would be super cool and I think the way to go. I would also need to restrict any submissions after 60 minutes is up. Most of the form work I have done in the past is with input fields, textarea etc, with one submission so this type of application is a little new to me. That is why all of the questions :-)

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.