I have spent a couple of months developing an application on a domain of mine. It's overall a simple concept. During development I hosted it myself on my own domain, but recently pushed it to our actual one. The problem is that sessions aren't created or kept between pages, and I can't for the life of me figure out why.
Apologize for the wall of code below, but I prefer it over a theoretical explanation.
Lets start with how I start my session at the top of every page:
function sec_session_start() {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
And then how I check if the user is logged in. I added return x;
instead of false
for debugging. I append this to the redirect URL.
function login_check($mysqli) {
if(isset($_SESSION['id'], $_SESSION['login_string'], $_SESSION['type'])) {
$id = $_SESSION['id'];
$login_string = $_SESSION['login_string'];
$user_browser = $_SERVER['HTTP_USER_AGENT'];
if($_SESSION['type'] == 1 || $_SESSION['type'] == 2) // Admin user
{
if ($stmt = $mysqli->prepare("SELECT `password` FROM `users` WHERE `id` = ? LIMIT 1")) {
$stmt->bind_param('s', $id);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows == 1) {
$stmt->bind_result($password);
$stmt->fetch();
$login_check = hash('sha512', $password.$user_browser);
if($login_check == $login_string) {
return true;
} else {
return 1;
}
} else {
return 2;
}
} else {
return 3;
}
} else if($_SESSION['type'] == 3) { // Standard user
if($stmt=$mysqli->prepare("SELECT `password` FROM `proj` WHERE `id` = ? LIMIT 1"))
{
$stmt->bind_param("s", $_SESSION['id']);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows == 1)
{
$stmt->bind_result($db_key);
$stmt->fetch();
$login_check = hash('sha512', $db_key.$user_browser);
if($login_check == $login_string) {
return true;
} else {
return 4;
}
}
}
} else {
return 5;
}
} else {
return 6;
}
}
I have two login pages, one for admins and one for users.
Admin:
<?php
ini_set('display_errors','On');
error_reporting(E_ALL);
include_once "../functions.php";
include_once "../db_connect.php";
sec_session_start();
if(login_check($mysqli) === true) {
header('Location: ../index.php');
}
else
{
// Login form
}
Users:
<?php
ini_set('display_errors','On');
error_reporting(E_ALL);
include_once "../functions.php";
include_once "../db_connect.php";
sec_session_start();
if(login_check($mysqli) === true) {
header('Location: ../index.php');
}
else
{
// Login form
}
Quite identical, apart from the file sources as the admin login.php
is located in /admin
. Despite this, the first one displays the login form correctly while the second redirects you to index.php
(even when in incognito, a mystery to me), causing a redirect loop (as index.php
sends it back for nog being logged in).
In addition to this, when I login with proper credentials, it does direct me to index.php
only to redirect me back to login.php
with error code 6
.
Please do comment if you want more information or code examples, I feel lost in my own project right now.
Any help is appreciated, Thank you
UPDATE 17 dec:
After a few hours of debug, we've concluded that the issue is not with the code but with the server configuration. A simple example:
<?php
session_start();
echo session_id();
?>
If you open this file on the production server, and refresh the page, it displays a new session id with every request. I currently have no clue why. I have confirmed the session file is created as well as the cookie. It contains the proper information and can be accessed by SSH with server permissions. Truly some strange behavior.
Any clues?
Sessions use cookies to identify remote clients. That means that Sessions won't work if the client's web browser doesn't accept cookies. PHP keeps Sessions' data inside files.
Yes, the session data is on the server only.
It must be on every page you intend to use. The variables contained in the session—such as username and favorite color—are set with $_SESSION, a global variable. In this example, the session_start function is positioned after a non-printing comment but before any HTML.
And, variable names are case-sensitive in PHP, unlike function names.
I have gone through your code and I didn't find any thing unusal except only 1 thing.
You should never use ==
for string comparison ===
is OK.
$something = 0;
echo ('password123' == $something) ? 'true' : 'false';
Run the above code and you will find the reason of your session lost. In your function login_check you are using ==
for comparing two string
if($login_check == $login_string)
replace it with:
if($login_check === $login_string)
Else every thing is absolutly fine. If changing this little thing doesn't resolve your problem then just let me know.
You are connecting to DB before session start. I would recommend you to import your function then start your session and then connect to your database.
include_once "../functions.php";
sec_session_start();
include_once "../db_connect.php";
Check if the session has already started and ensure it is only done once:
With PHP >= 5.4:
function sec_session_start() {
if (session_status() == PHP_SESSION_NONE) {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
}
Prior to PHP 5.4:
function sec_session_start() {
if (session_id() == '') {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
}
Additionally, why does the session have to be regenerated everytime?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With