ajoo Posted April 11, 2013 Share Posted April 11, 2013 (edited) Hi all, I have another problem associated with logins using sessions and stuff. On my machine I have Apache and mysql installed. The browser I use is Google Chrome. Everything is working fine. There is a very simple login system which, like all login systems, has a ID and password field. The user has to fill in the ID and password and these are checked against a database and the user is logged in. However before the ID and password are checked, the code checks if the $_session variable is set to and if it is it declares that the user is logged in and redirects the user to a secure page. There the user sees a personalised message and can logout. This is what is desired but this is not happening. Find below the code. There are 5 files namely 1. index.php, 2. loginproc.php 3. securedpage.php 4. logout.php and 5. config.inc In the file INDEX.PHP,is the following bit of code ///////////////// CODE NEVER TRAVERSED ///////////////////// RED RED RED //////////////// Check, if user is already login, then jump to secured pageif (isset($_SESSION['username'])) {echo $_SESSION['username']. "Already Logged in @ index 8";echo " You are being logged out as you have logged in from another page ";session_destroy();header('Location: index.php');///////////////// CODE NEVER TRAVERSED ///////////////////// RED RED RED ////////////// which never gets executed and I wonder why. These lines check at the outset if the user is logged in. If he is logged in and an attempt is made to login again these lines should be executed terminating the first session or at least that's what I want but for some baffling reason that does not occur. I try and create that scenario as follows. I log into the system once thru google chrome. Then i use another tab to login using the same ID and password. And to my surprise i am logged in and reach the secured page again. So I then have 2 logins on 2 different browser pages by the same ID and in both browsers the secured page is displayed. What I am trying is ofcourse that once a person is logged in and another login attempt is made, the first session be destroyed and a notification to that displayed on the first logged in browser page. I am unable to see where the mistake lies. I would be most grateful for any help and suggestions. Thanks all. <?php ///////// INDEX.PHP ///////////////////// // Inialize session session_start(); ///////////////// CODE NEVER TRAVERSED ///////////////////// RED RED RED ////////////// // Check, if user is already login, then jump to secured page if (isset($_SESSION['username'])) { echo $_SESSION['username']. "Already Logged in @ index 8"; echo " You are being logged out as you have logged in from another page "; session_destroy(); header('Location: index.php'); ///////////////// CODE NEVER TRAVERSED ///////////////////// RED RED RED ////////////// } else { echo " Hi new user ";} if (isset($_SESSION['username'])) {echo $_SESSION['username']."Already Logged in @ index 14";} ?> <html> <head> <title>PHPMySimpleLogin 0.3</title> </head> <body> <h3>User Login</h3> <table border="0"> <form method="POST" action="loginproc.php"> <tr><td>Username</td><td>:</td><td><input type="text" name="username" size="20"></td></tr> <tr><td>Password</td><td>:</td><td><input type="password" name="password" size="20"></td></tr> <tr><td> </td><td> </td><td><input type="submit" value="Login"></td></tr> </form> </table> </body> </html> <?php ///////// LOGINPROC.PHP //////////// // Inialize session session_start(); // Include database connection settings include('config.inc'); // Retrieve username and password from database according to user's input $login = mysql_query("SELECT * FROM members WHERE (Username = '" . mysql_real_escape_string($_POST['username']) . "') and (Password = '" . mysql_real_escape_string($_POST['password']) . "')"); echo " Login = $login"; // Check username and password match if (mysql_num_rows($login) == 1) { // Set username session variable echo " Ok Hi there - Welcome "; $_SESSION['username'] = $_POST['username']; // Jump to secured page header('Location: securedpage.php'); } else { // Jump to login page echo " Can't find you"; //header('Location: index.php'); } ?> <?php /////////////////// SECURED PAGE //////////////////// // Inialize session session_start(); // Check, if username session is NOT set then this page will jump to login page if (!isset($_SESSION['username'])) { header('Location: index.php'); } else { echo " Welcome". $_SESSION['username']; } ?> <html> <head> <title>Secured Page</title> </head> <body> <p>This is secured page with session: <b><?php echo $_SESSION['username']; ?></b> <br>You can put your restricted information here.</p> <p><a href="logout.php">Logout</a></p> </body> </html> This is content of ‘logout.php’: <? <?php /////////// LOGOUT. PHP /////////////////// // Inialize session session_start(); // Delete certain session unset($_SESSION['username']); // Delete all session variables session_destroy(); // Jump to login page header('Location: index.php'); ?> <?php ////CONFIG.INC ///////////////// $hostname = 'localhost'; // Your MySQL hostname. Usualy named as 'localhost', so you're NOT necessary to change this even this script has already online on the internet. $dbname = 'test'; // Your database name. $username = 'root'; // Your database username. $password = ''; // Your database password. If your database has no password, leave it empty. // Let's connect to host mysql_connect($hostname, $username, $password) or DIE('Connection to host is failed, perhaps the service is down!'); // Select the database mysql_select_db($dbname) or DIE('Database name is not available!'); ?> Edited April 11, 2013 by ajoo Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/ Share on other sites More sharing options...
mac_gyver Posted April 11, 2013 Share Posted April 11, 2013 each of your header() redirect statements need an exit statement after it to prevent the rest of the code on the page from running. you also cannot echo or output any characters to the browser before a header() statement. if you are actually seeing the echoed output, the header() statement won't work at all and if you are not seeing the output and the header() is working it means that php is buffering output and echoing things to help you debug won't work. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424121 Share on other sites More sharing options...
ajoo Posted April 11, 2013 Author Share Posted April 11, 2013 (edited) Thanks for the advise. I'll look into it and revert with the outcome. Is there any way that i can make the program to pause for a few seconds after the echo commands to be able to check the program flow for debugging purposes? Thanks again. Ok I have just made the changes with the exit(); at the appropriate places as you advised and reran the login to be met with the same results. However if you can suggest some way for me to pause the program and check the output of the echo commands, it may give me a great insight into the program and thus maybe an approach to the solution. Eagerly awaiting a reply to this and thanks all. Edited April 11, 2013 by ajoo Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424131 Share on other sites More sharing options...
mac_gyver Posted April 11, 2013 Share Posted April 11, 2013 you would need to temporarily comment out the header() statements. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424137 Share on other sites More sharing options...
ajoo Posted April 11, 2013 Author Share Posted April 11, 2013 (edited) Ok thanks again sir. I'll revert with the findings again. Well for all practical purposes I just need to make that change in index.php. Thanks. Any other suggestions are most welcome. Edited April 11, 2013 by ajoo Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424139 Share on other sites More sharing options...
DavidAM Posted April 11, 2013 Share Posted April 11, 2013 I usually just change the header() to die() until I figure out the problem. At any rate: What I am trying is ofcourse that once a person is logged in and another login attempt is made, the first session be destroyed and a notification to that displayed on the first logged in browser page. There is no relationship between the two sessions. They are distinct client sessions (only related to the page request), one session cannot know about the other. The solution would require on login, write the session ID to the user's database record. on page access, if the session ID of the request does not match the one in the database (for the user in the $_SESSION array), tell them they logged in from somewhere else, and kick them to the logout script. That's off the top of my head, I've never tried this. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424230 Share on other sites More sharing options...
jcbones Posted April 11, 2013 Share Posted April 11, 2013 Just run it on a token system. If they don't have the correct token, they get logged out, or never logged in. This would be set inside the session, and not the database. A simple md5 of the browser (HTTP_USER_AGENT) should suffice for what you are looking to do. Tokens can be set in a cookie, or in the URI. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1424243 Share on other sites More sharing options...
ajoo Posted April 19, 2013 Author Share Posted April 19, 2013 Hi. Thanks all for their replies. I am surprised to find that my last reply to this post here is missing and so I'll repost that with a new question. Firstly I tried all the advise by Mac and it all worked great. I used that and now have a login system that prevents multiple login by the same person twice. So thanks for that. I guess to have it working in a real system I would need to use a database as suggested by David. Once i do that I'll post my results here again. I am not aware of the token system suggested by jcbones but i'll explore that too. If you could provide me wid some more information on tokens or a reference site I'll be happy. So now my system works with a small hitch. Like I mentioned that I would like the user to get logged out of the first session once he logs in the second time from the same or new machine. With my code and help from you all what i have achieved is the prevention of the second login. I'ld be grateful if someone can suggest how I might be able to ensure that the 1st session of the user is terminted when he logs into the sytem a second tme. This should be somewhat like a yahoo chat login system which logs out the user with a message which says that the user has been logged out because he has logged in from another machine, once the second login by the same user occours. Thanks loads. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425740 Share on other sites More sharing options...
davidannis Posted April 19, 2013 Share Posted April 19, 2013 Why not do something like this? if ($_SESSION['destroyed_on_dupe']){ echo "This session was destroyed because you logged in from...."; // maybe destroy the session here die(); } elseif (isset($_SESSION['username'])) { echo $_SESSION['username']. "Already Logged in @ index 8"; echo " You are being logged out as you have logged in from another page "; $_SESSION['destroyed_on_dupe']=true ; unset($_SESSION['username']) die(); } Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425742 Share on other sites More sharing options...
ajoo Posted April 19, 2013 Author Share Posted April 19, 2013 Hi david, Just by looking at the code, because i tried something like this, I feel that this would logout from the second session and not the first session. So it would probably not allow a second login. Where as what I am trying to achieve is that the 2nd login occurs destroying the first. Isn't there any function that allows the sessions to be destroyed by name. for eg. If i have jack logged in at time = t1 and then jack logs in again at a later date t2, is there no function which can identify and then logout jack at t1 with a message appearing on the screen of Jack at t1. ( session 1) In case i am missing something that you suggested then kindly rephrase it for me. Thanks all. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425752 Share on other sites More sharing options...
White_Lily Posted April 19, 2013 Share Posted April 19, 2013 you could do an active system, when a user logs in, get the script to change the users status in the database to "Active" when they log in. This way, when they try to log in from another window, browser, computer, etc... all you have to do is check if a cell in that users row is "active" if it is, then the user is already logged, if it isn't active, then obviously allow the user to log in. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425758 Share on other sites More sharing options...
davidannis Posted April 19, 2013 Share Posted April 19, 2013 (edited) You are right. Here's how I would approach it. Create a table session_status. Fields: username, session_id (autoincrement), timestamp, status If a user logs in check the table for other entries with same user ID - change status to "logged out because new login" Create a new record with status = "active" set $_SESSION['session_id'] If a user accesses a page and is already logged in check the status of the record that matches his sessioin_id to make sure that he hasn't been logged out (status must = acitve). Edited April 19, 2013 by davidannis Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425769 Share on other sites More sharing options...
ajoo Posted April 19, 2013 Author Share Posted April 19, 2013 The problem still remains that which set of commands would target the first session on say computer1 to terminate it while the same user is trying to logon from computer 2 without having logged off from the first machine. The program is idle an computer1 and the code is being executed on machine 2. How then would that code on machine 2 trigger code on machine 1 to log out from there ? Can you please try and demonstrate with some actual code? At least a pointer. Thanks. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425793 Share on other sites More sharing options...
davidannis Posted April 19, 2013 Share Posted April 19, 2013 Sure I will write a little demo. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425797 Share on other sites More sharing options...
davidannis Posted April 19, 2013 Share Posted April 19, 2013 This works for me: Login page: <?php session_start(); $link = mysqli_connect("localhost", 'XXXXX', 'XXXXXXXX', 'testdb') or die("Unable to connect!"); if ($_POST['username']!=''){// this is someone logging in //in the real world we'd check for a valid password here $query="UPDATE sessions SET status='X' WHERE username='".$_POST['username']."'";//make all other sessions for this user die $result=mysqli_query($link, $query); $username=$_POST['username']; // add a record to the database $query="INSERT INTO sessions VALUES ('', '$username','A')"; $result=mysqli_query($link, $query); $_SESSION['id']=mysqli_insert_id($link); $_SESSION['username']=$_POST['username'];// Now this session is logged in echo 'login success'; die(); } ?> <!-- To change this template, choose Tools | Templates and open the template in the editor. --> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> <form method="POST" action="testlogin.php"> <input type="text" name="username" value="david"> <input type="submit"> </form> <?php ?> </body> </html> Regular Page: <?php session_start(); $link = mysqli_connect("localhost", 'XXXXXXX', 'XXXXXXXX', 'testdb') or die("Unable to connect!"); if ($_SESSION['username']!=''){ $query="SELECT status FROM sessions WHERE id='".$_SESSION['id']."'"; $result= mysqli_query($link, $query); $sessions= mysqli_fetch_assoc($result); if ($sessions['status']=='X'){ echo 'you were booted'; die('too bad'); } }else{ die ('you need to login'); } ?> <h1>YOu are logged in</h1> You'll need to hash, salt, and check passwords, sanitize input, and catch errors. This is quick and dirty to demo the idea. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425806 Share on other sites More sharing options...
seandisanti Posted April 19, 2013 Share Posted April 19, 2013 (edited) each of your header() redirect statements need an exit statement after it to prevent the rest of the code on the page from running. No it doesn't. When you do a header redirect, anything after it basically doesn't exist. even if you put an exit() it would never be reached. Be sure if you're going to use an active flage to identify logged in users in the database, that you also check at random intervals to toggle the status of users that did not log out but are not actively on the page. The easiest way to do that is probably with a time of the last time they loaded a page. it would take just a second to add that to the database, and then on login, instead of checking just the active flag, you can see when they were last active, someone with an active flag for example that hasn't loaded any page but login in the last hour is probable safe to start a new session for. You can also use the actual session id's in the database, so that you delete the session file and essentially kill all $_SESSION variables for the previously active session. Edited April 19, 2013 by seandisanti Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425814 Share on other sites More sharing options...
davidannis Posted April 19, 2013 Share Posted April 19, 2013 someone with an active flag for example that hasn't loaded any page but login in the last hour is probable safe to start a new session for. I think that the OP wanted to start a new session any time someone logged in and simultaneously kill the old one (even if it was very recent. I do agree that there ought to be a time stamp in the sessions table and you should just go through and clear the old ones (Active or not) on a regular basis so that you don't end up with an enormous table. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425817 Share on other sites More sharing options...
ignace Posted April 19, 2013 Share Posted April 19, 2013 (edited) each of your header() redirect statements need an exit statement after it to prevent the rest of the code on the page from running.No it doesn't. When you do a header redirect, anything after it basically doesn't exist. even if you put an exit() it would never be reached. Oh yeah? header('Location: http://www.google.com'); file_put_contents('test.txt', 'Supposedly never reached...'); sleep(1000); // in this time you may want to read php.net while you wait to be redirected Run this code, then check your folder. You might wanna read up on what header() does exactly: http://php.net/manual/en/function.header.php. If output_buffering = Off then you will not have to wait 1000 seconds. Maybe even the file won't be written.. This is the reason why you should always add an exit after every header location call. Edited April 19, 2013 by ignace Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425846 Share on other sites More sharing options...
seandisanti Posted April 19, 2013 Share Posted April 19, 2013 I stand corrected, the die command is never reached in this code, and I thought that the behavior was the same regardless of the functions following the header. <?php header('Location:http://google.com'); die('die reached'); Thanks for the info! Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425852 Share on other sites More sharing options...
ajoo Posted April 22, 2013 Author Share Posted April 22, 2013 Hi all, OK here i am with the results of my experiments with the code for a login system which boots out any previous and running sessions by a given ( particular) user, thus effectively disallowing a multilogin by a single user. So anytime a user forgets to logout and logs back in again at the same or new machine, the previous sessions are to be closed and destroyed and the user gets to login from whereever he's logging in once again. At least thats what I am trying to achieve and I appreciate the help of so many senior members here. Attached please find a snapshot of my computer screen which show the above not happening. The code suggested by david works in the database all right as can be seen from the snapshot. Also you can see that I have been able to login on 3 pages on the same machine. David gave two files one for login which i renamed as status.php and one regular.php which I assumed was the page to be displayed on successful login. The regular.php is supposed to evict an already logged user if he logs in a second time from any other machine. However one look at the regular.php shows that it simply checks the status field and if its been changed to 'X' indicating a previously active session, it is supposed to simply echo that the user has been booted. This part of the code however never gets to execute and so this eviction message " you were booted" is never displayed. I think thats because the regular pages have already run their length in the previous sessions. Its here that the new active session some how has to communicate with previous sessions and trigger / refresh the page code once again and then actually destroy the old session evicting the user in the previous page and displaying the message. How is this triggering / refreshing of the browser in the previous session to be achieved. I guess the problem has still not really been solved. Or maybe I am missing something here or are too much of a newbie to get the drift of the experts. A little more help with actual code would feel great! Thanks all. Looking forward to a finally a complete solution to this one. I hope this would help other new comers like me. ( I am unable to paste the snapshot of my run of the program. If someone can tell me how i may achieve that I'll paste it the next time round ). Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425954 Share on other sites More sharing options...
davidannis Posted April 22, 2013 Share Posted April 22, 2013 If the problem is that the regular page you need to make sure that the page is not cached. http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers To see if that is really the problem, hit the refresh button and see if you get the message. Another way to do it, which would be more elegant, would be to write a routine that would periodically check the sessions database using AJAX and force the refresh only if the status had changed to X You can also put an http refresh meta tag in the regular page or force a refresh using javascript. I'm not sure why it is important to log out an already displayed page. As soon as the user goes to the next page on the site, he'll get the "you have been booted" message. Presumably he's already seen the content of the page he's on. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425966 Share on other sites More sharing options...
ajoo Posted April 22, 2013 Author Share Posted April 22, 2013 Hi david. Thanks for the revert. Though I have not tried it, but i am quite certain that a manual refresh would cause the page of the previous sessions to display the "you have been booted" message. Though I don't understand the cache bit that you mentioned. In fact the only thing that's needed in this problem is as you have suggested that there should be some routine which would periodically check the database, something like an interrupts in java or c or Ajax as you have mentioned here. Can you please elaborate on the Ajax bit. I am very new to PHP and have zero knowledge of Ajax as i have not needed it till now. So if you give me some pointers to it maybe then i'll try and implement the full logic. Maybe a tutorial on Ajax that implements these "periodic checks". And if its not too complex, a small bit of code to do just that. Again about refresh metatags or javascript I have no idea. please shed some light on their usage as well. I feel its important to log out of the previous sessions when the user attempts a fresh login. A user can forget to logout of a session and then maybe logs in at another place. He may not go back to the old machine that day and so there would be no one to refresh that page to get a final logout and so a clean up of the database where logins status is stored will not occour. I want to do a clean up of the database when i logout a user from a previous session so that this login database may not become too large. Would it be a good idea to delete the records that have been marked "X" and are therefore in the "booted" status? Since this particular logic provide the "id" as the row number, deleting rows can cause a mix up of values thereby rendering the "id" not unique. Just a thought. Looking forward to some more discussion and help. Thanks loads. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1425981 Share on other sites More sharing options...
davidannis Posted April 22, 2013 Share Posted April 22, 2013 He may not go back to the old machine that day and so there would be no one to refresh that page to get a final logout and so a clean up of the database where logins status is stored will not occour. You can timestamp the rows in the sessions database as previously suggested and have a script go through and delete all of those more than a day or two old. If you try to write the code to do that first, I will help you with any problems. Would it be a good idea to delete the records that have been marked "X" and are therefore in the "booted" status? Since this particular logic provide the "id" as the row number, deleting rows can cause a mix up of values thereby rendering the "id" not unique. Just a thought. I would not delete the records right away because then you just have a missing session record and don't know that they have been logged out when they try again from the firs computer. If you make the id column auto-increment it will not fill in ids that have been deleted. MySQL will just assign the lowest number that has never been used (though you can force it to reuse an number). Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1426005 Share on other sites More sharing options...
davidannis Posted April 22, 2013 Share Posted April 22, 2013 Though not very efficient you can easily get a message to the first computer by adding this between the head and /head tags: <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> <meta http-equiv="refresh" content="30"> It may cause other problems if you have a user filling out a long form, etc. Not sure what you are trying to accomplish by booting users before they leave the current page if they log in elsewhere. As discussed above, this is not a solution to keeping the sessions table clean, but a solution to not seeing a message right away in the first browser when somebody logs in a second place. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1426007 Share on other sites More sharing options...
ajoo Posted April 23, 2013 Author Share Posted April 23, 2013 Hi, Thanks david for the response. I am going to try first the meta tags in the header and will revert. Wish you had given me something on Ajax for the refreshing of the page and I would have checked that one out as well but I'll search it on google and revert. Once this is done I'd like to discuss some more regarding the cleaning up of the database. Thanks. Quote Link to comment https://forums.phpfreaks.com/topic/276820-a-twister-unable-to-prevent-a-second-login-by-the-same-member/#findComment-1426039 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.