I am building a login/logout system using sessions, and running into an issue with the user-end wrap-up for the logout/timeout functions. This is due to the way I have constructed the page these functions operate on.
The page is constructed from a central iFrame for the actual pages, surrounded by a top navbar and two sidebars for navigation. The sidebars consist of several PHP elements each that check whether or not a $_SESSION[“idUser”] is set, and a jQuery function refreshes the elements that are sensitive to login status (menus and logged-in-only content) when specific elements are clicked. The reason I built it this way, is because the page handles a browser game and I want the user to stay on a single URL (no permalinks to any of the in-game content).
The login/logout buttons are handled by jQuery, which sends an AJAX request to the PHP file that handles all user validation and refreshes the sidebar elements. When the user logs in the handler regenerates the session id (because the page is not refreshed the session id would otherwise not change if the user logged out and logged back in in the same sitting, from my experience so far). That way, no matter what happens, when you log in the old session id is lost. On logout, the PHP handler unsets the $_SESSION variables, and then destroys the session.
What I want to do is display a notification after logout/timeout showing whether the user logged out themselves or whether the session timed out. I can do that with the Javascript that handles the button – since the page itself does not refresh, the function continues running and I can simply have it put a bit of text somewhere. I really really want to put the notification inside the login form, right above the login button, because that’s where someone would look when checking things regarding their login status.
The problem is that the login form is one of the sidebar elements that gets reloaded by the jQuery script on the button. The jQuery script first sends the AJAX request to the PHP handler, then orders the reload of the sidebar elements. However, jQuery doesn’t wait for the content to reload if I append a .done() after the .load() part, which means I can’t use the same jQuery function to put some text in the login form, because jQuery will attempt to add the text before the form has even loaded onto the page.
The only solution I have come up with so far is to not destroy the session, and instead set $_SESSION[“response”]=”logged out”, then have the login form echo that value.
My question is: a) given the construction method of the page, is there any way to achieve this effect without retaining the PHP session? b) if not, is it safe to not destroy a session on logout, but only regenerate the session id on login?
jQuery code:
$(".column").on("click", "#login, #logout", function () { //This handles the login/logout buttons var formData = $(event.target).parent().parent().serialize(); //put the form data in a string if (formData !== "") { formData += "&"; } formData += event.target.id + "=" + event.target.id; $.post("/backend/validateUser.php", formData) //post the login/logout data to the handler file .done(function() { //refesh navbar and all sidebars $(".navbar, #sidebartopl, #sidebartopr, #sidebarbottoml, #sidebarbottomr").each(function(){ $(this).load("/layout/"+$(this).attr("phpsource")+".php"); }); }) if ($(this).attr("id") === "login") { $(".navbar").removeClass("collapsed"); } else if ($(this).attr("id") === "logout") { $(".navbar").addClass("collapsed"); } });
PHP handler:
<?php declare(strict_types=1); session_start(); include(database connection php); $userName = $userPass = $userPass_1 = $userPass_2 = $email = $password = $errUser = $errEmail = $errPass_1 = $errPass_2 = $errTOS = ""; $TOS = false; $timestamp = date("Y-m-d H:i:s", time()); if ($_SERVER["REQUEST_METHOD"] == "POST") { if (isset($_POST["login"])) { //LOGIN CODE session_regenerate_id(); //check whether the user has filled in username and password, md5 the password, check the user's data in the database, then return their user ID and a whole bunch of variables which are saved to $_SESSION[]: session_regenerate_id(); if (empty($_POST["username"])) { $_SESSION["response"] = "ENTER USERNAME"; } elseif (empty($_POST["password"])) { $_SESSION["response"] = "ENTER PASSWORD"; } else { //everything filled in, consult the database: $userPass = test_input($_POST["password"]); $userName = test_input($_POST["username"]); $password = md5($userPass); $logincheck = $conn->prepare("SELECT * FROM users WHERE userName=?"); $logincheck->bind_param("s", $userName); $logincheck->execute(); $result = $logincheck->get_result(); $user = $result->fetch_assoc(); if (!$user) { $_SESSION["response"] = "INVALID USERNAME"; } elseif ($user["userPass"] !== $password) { $_SESSION["response"] = "INVALID PASSWORD"; } else { //login is correct, store data into the session and log the session to the DB: $_SESSION["idUser"] = $user["idUsers"]; $_SESSION["response"] = "You have successfully logged in!"; $_SESSION["session"] = session_id(); $newsession = $conn->prepare("INSERT INTO sessions (idUser, idSession, startStamp) VALUES (?, ?, ?)"); $newsession->bind_param("sss", $_SESSION["idUser"], $_SESSION["session"], $timestamp); $newsession->execute(); } } } elseif (isset($_POST["logout"])) { $endsession = $conn->prepare("UPDATE sessions SET lastGalaxy=?, endStamp=? WHERE idSession=?"); $endsession->bind_param("iss", $_SESSION["idGalaxy"], $timestamp, $_SESSION["session"]); $endsession->execute(); session_unset(); session_destroy(); } elseif (isset($_POST["register"])) { /*This handles registration, not relevant*/ }
When the user is not filling in the login form with the correct user info, the session gets a value $_SESSION[“response”] which is echoed into the displayed login form.
Advertisement
Answer
I have found a solution to my problem… I can have my PHP handler simply echo some json back. This way I can avoid the entire timing issue because the jQuery script only executes its next action after it receives the response from the PHP handler.
The AJAX statement now read as follows:
$.post("/backend/validateUser.php", formData, function(data) { switch(data.result) { //case for each possible result from the handler (login/logout/timeout/register) }, "json")
The PHP handler simply echoes a tiny JSON snippet when it successfully completes all the actions in a particular process:
echo json_encode(["result"=>"login"]);