Session seems to disappear after header redirect - php

I have four pages so far:
index.php
login.php
setsessionconfig.php
account.php
The background:
When I click the login w/ facebook button from the index it takes me to login.php which if the user is already registered with the site it doesn't go through the facebook website it just continues. Login.php pulls the neccessary information for the session then header redirects to setsessionconfig.php which has the code below:
login.php has a 5 second delay for loading visual then redirects to ...
header( "refresh:5;url=".URLBASE."/setsessionconfig.php?uid=".$uid."&email=".$email );
setsessionconfig.php
$uid = isset($_GET['uid']) ? $_GET['uid'] : "";
$email = isset($_GET['email']) ? $_GET['email'] : "";
if( $uid != "" && $email != "") {
session_start();
$_SESSION[SESSION_UID] = $uid;
$_SESSION[SESSION_EMAIL] = $email;
$_SESSION[SESSION_IS_LOGGEDIN] = 1;
header("Location: account");
}
The Problem
When setsessionconfig.php redirects to account.php it checks to see if the users is logged in via the SESSION_UID global variable then displays the user information OR it displays the "you are not logged in" text. No matter what I do I think the header redirect to account.php is destroying session variables.
I even checked to see if the session was available with the following code in account.php.
function is_session_started()
{
if ( php_sapi_name() !== 'cli' ) {
if ( version_compare(phpversion(), '5.4.0', '>=') ) {
return session_status() === PHP_SESSION_ACTIVE ? TRUE : FALSE;
} else {
return session_id() === '' ? FALSE : TRUE;
}
}
return FALSE;
}
if ( is_session_started() === FALSE )
echo "<script>console.log('FALSE');</script>";
else
echo "<script>console.log('TRUE - ".session_id()."');</script>";
Unfortunately that part actually returns the TRUE and the session ID... So I am sort of stuck because I have never had this issue with sessions before...

try using exit(); after the header

Since the function is_session_started, returned TRUE and also returned the session ID, obviously the session ID is passed properly.
I hope the account.php code looks something like this
<?php
session_start();
if (! empty($_SESSION['SESSION_UID']))
{
?>
your code here
<?php
}
else
{
echo 'You are not logged in.';
}
?>
Edit :
Try
$_SESSION['SESSION_UID'] = $uid;
$_SESSION['SESSION_EMAIL'] = $email;
$_SESSION['SESSION_IS_LOGGEDIN'] = 1;

Related

implementing both session, cookie in a login form

i'm implementing session, cookie simple from with a remember me check box . i want to use the cookie so the user could see index.php(protected content) i closed the browser to end the session to check if the cookie working and i got the famous error ..redirected you too many . i searched a bit but still stuck so what should i do? and Is what is the best practice to for doing it?
authentication.php
if(mysqli_num_rows($rows) > 0){
$chck_pass = password_verify($clean_password,$user_arr["password"]);
if($chck_pass){
//log in the user
$_SESSION["id"] =$user_arr["id"];
$_SESSION["fristname"] = $user_arr["fristname"];
$_SESSION["email"] = $user_arr["email"];
$_SESSION["verified"]=$user_arr["verified"];
$_SESSION["message"]="Please verify Your Email to Complete Registration";
//make login-id cookie
if(isset($_POST["remmberme"])){
$user=$user_arr['id'];
setcookie("I_user",$user, time() + 1800);
}
header("location:index.php");
exit();
}else{
$errors["login_error"]="Wrong Password";}
}else{
$errors["login_error"]="Wrong Email";
index.php
<?php
include("Authentication.php");
if(!isset($_SESSION["id"]) || !isset($_COOKIE['I_user']) ){
header("location:login.php");
}
?>
login.php
<?php
require_once("config/db_connect.php");
require("Authentication.php");
if(isset($_COOKIE['I_user'])|| isset( $_SESSION['id'])){
header("location:index.php");}
So you login, close your browser. Then open it up again.
You go to index.php and the following line runs
if(!isset($_SESSION["id"]) || !isset($_COOKIE['I_user']) ){
$_SESSION["id"] isn't set, so you redirect to login.php.
On login.php
if(isset($_COOKIE['I_user'])|| isset( $_SESSION['id'])){
$_COOKIE['I_user'] is set, so you redirect to index.php
Repeat forever.

Session ID regeneration not working on windows

I have the following code which works fine under several linux flavors I have tried (Ubuntu, Debian 8, CentOS 7), however when I use it on windows, the regeneration fails without an error. $duration is a value in the class represented as static $duration = 60 * SESSION_TIMEOUT; where SESSION_TIMEOUT is a constant defined in a config.inc.php file (user setting).
session_start();
self::csrf(false);
if(self::verify(false) === true) {
$_SESSION['expires'] = time() + self::$duration;
}
session_regenerate_id(true);
$id = session_id();
session_write_close();
session_id($id);
session_start();
If I echo $id after the line $id = session_id(); there is a value, however if I echo session_id() after the last session_start(), it is empty. (See session_regenerate_id if you think this method is 'Dodgy' )
I do not know why this regeneration code is failing :
session_regenerate_id(true);
$id = session_id();
// one of the lines below this are causing session_id() to be blank
session_write_close();
session_id($id);
session_start();
Please assist me in identifying what is causing the new session to be blank when it should contain the new session id.
session.save_path = 2;755;d:/server/www/127.0.0.1/sessions
Update: I was able to find this in the log, however the interesting part is the session file is created with data.
PHP Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (2;755;d:/server/www/127.0.0.1/sessions) in Unknown on line 0
As requested, a sample of $id before calling session_write_close() (and subsequent code), is 9vdom0ghuqkvsdcnkjacurc6rf2n4fn1s1gvfva44okd15jdpm30
Update:
After some more testing, I have traced the problem to be a bit more complex than stated above. The problem I initially had which I believed was a session regeneration issue, is more of a problem where session variables are not being stored. I believe this is still related to session regeneration somewhat on windows, however I still am unable to pinpoint a fix, as this code works beautifully on Linux.
Here is the class (minified):
class session {
static $duration = 60 * SESSION_TIMEOUT;
public static function start() {
session_start();
self::csrf(false);
if(self::verify(false) === true) {
$_SESSION['expires'] = time() + self::$duration;
}
session_regenerate_id(true);
$id = session_id();
session_write_close();
session_id($id);
session_start();
}
public static function csrf($new = false) {
if(!isset($_SESSION['csrf']) || $new === true) {
$_SESSION['csrf'] = sha1(openssl_random_pseudo_bytes(mt_rand(16,32)));
}
return $_SESSION['csrf'];
}
}
The code used to call it, is rather complex (when it comes to determining when to generate a new csrf token), but below is my attempt to extract a chunk from my overall project to demonstrate the usage. The login code behind should suffice I believe to view the logic:
if( session::verify() === true ) {
redirect();
} else {
$error = '';
$token = $_SESSION['csrf'];
if ( !empty($_POST) ) {
if ( isset($_POST['csrf']) ) {
// check CSRF token and if match ti token stored in session
$csrf = trim(filter_input(INPUT_POST, 'csrf', FILTER_SANITIZE_SPECIAL_CHARS, array('flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH)));
if($csrf != $_SESSION['csrf']) { session::destroy(); $error = 'CSRF Attack Detected'; }
if( isset($_POST['username']) && isset($_POST['password']) && empty($error) ) {
// login validation code
if($auth) {
// regenerate csrf token
$token = session::csrf(true);
session::create( $username );
// redirect back to application root
redirect();
}
$error = 'Invalid credentials';
} else {
if(empty($error)) { $error = 'Invalid credentials'; }
}
// user was not authenticated, regenerate csrf token to prevent form spam
$token = session::csrf(true);
} else {
// CSRF token did not match stored token in session
$error = 'CSRF Attack Detected';
}
}
}
The additional methods for my session class as used in the login code are as follows :
Update session data with user information.
public static function create($user) {
$_SESSION['nonce'] = sha1(microtime(true));
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['agent'] = sha1($_SERVER['HTTP_USER_AGENT']);
$_SESSION['expires'] = time() + self::$duration;
$_SESSION['user'] = $user;
session_regenerate_id(true);
$id = session_id();
session_write_close();
session_id($id);
session_start();
}
Verify posted information matches server session
public static function verify($destroy = false) {
$valid = true;
try {
if( !isset($_SESSION['nonce']) ) { $valid = false; }
if( !isset($_SESSION['user']) ) { $valid = false; }
if( isset($_SESSION['ip']) ) { if($_SESSION['ip'] != $_SERVER['REMOTE_ADDR']) { $valid = false; } } else { $valid = false; }
if( isset($_SESSION['agent']) ) { if($_SESSION['agent'] != sha1($_SERVER['HTTP_USER_AGENT']) ) { $valid = false; } } else { $valid = false; }
if( isset($_SESSION['expires']) ) { if($_SESSION['expires'] <= time()) { $valid = false; } } else { $valid = false; }
} catch (Exception $e) {
$valid = false;
}
if($valid === false) {
if(isset($_SESSION['nonce'])) { unset($_SESSION['nonce']); }
if(isset($_SESSION['ip'])) { unset($_SESSION['ip']); }
if(isset($_SESSION['agent'])) { unset($_SESSION['agent']); }
if(isset($_SESSION['expires'])) { unset($_SESSION['expires']); }
if(isset($_SESSION['user'])) { unset($_SESSION['user']); }
if($destroy === true) {
session_unset();
session_destroy();
}
}
return $valid;
}
Update:
Narrowed this down by running a simple test :
// ensure sessions are writeable
if(!is_writable(session_save_path())) {
// try alternate session path
$_session_save_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'sessions';
if(!is_writable($_session_save_path)) {
echo "Can't write sessions"; exit;
} else {
session_save_path(
$_session_save_path
);
}
}
Which echo's the result 'Can't write sessions' meaning it failed all methods to try and write data.
What is interesting here, is that no matter what I do (even setting the root of the drive to 'Everyone' with 'Full' permissions, all subfolders and files seem to have a permanent semi-shaded 'Read Only' checkbox. Beyond this, file_put_contents("hello.txt", "hello"); exit(); works in the root folder of my local site, but not from any subfolder below 2 directories deep -- even after assigning (and checking) permissions. (e.g. d:\server\websites\127.0.0.1\htdocs\ works, but not d:\server\websites\127.0.0.1\htdocs\path1\path2\
Update:
Did some more troubleshooting, and the rabbit hole gets deeper. Ran a script to find what user PHP is running under to better assist in checking permissions:
echo 'Current script owner: ' . get_current_user();
which echo's 'Current script owner SYSTEM'
I followed up with this code :
$new = false;
session_start();
if(!isset($_SESSION['csrf']) || $new === true) {
$_SESSION['csrf'] = sha1(openssl_random_pseudo_bytes(mt_rand(16,32)));
}
session_regenerate_id(true);
$id = session_id();
session_write_close();
session_id($id);
session_start();
Which still failed. I did try something which finally worked, but I really don't feel comfortable with it as it involves not setting the security bits as documented in the php.ini file.
I changed :
session.save_path = "2;755;d:/server/www/127.0.0.1/sessions"
To
session.save_path = "d:/server/www/127.0.0.1/sessions"
And this works, however all the session files are now world accessible.
(Server is the same version of apache and php on all platforms configured with identical php.ini files, and server configuration files as close as possible)

PHP - Cannot change session variable in an "if" statement

Trying to make a page redirect if not logged in. I'll try to show what I mean.
In the index.php:
<?php
// initialization of login system and generation code
$oSimpleLoginSystem = new SimpleLoginSystem();
echo $oSimpleLoginSystem->getLoginBox();
session_start();
$_SESSION["loggedin"] = False;
// class SimpleLoginSystem
class SimpleLoginSystem {
// variables
var $aExistedMembers; // Existed members array
// constructor
function SimpleLoginSystem() {
$this->aExistedMembers = array(
'test' => MD5('test'), //Sample: MD5('qwerty')
);
}
function getLoginBox() {
ob_start();
require_once('login_form.html');
$sLoginForm = ob_get_clean();
$sLogoutForm = 'logout';
if ((int)$_REQUEST['logout'] == 1) {
if (isset($_COOKIE['member_name']) && isset($_COOKIE['member_pass']))
$this->simple_logout();
}
if ($_REQUEST['username'] && $_REQUEST['password']) {
if ($this->check_login($_REQUEST['username'], MD5($_REQUEST['password'])))
{
$_SESSION["loggedin"] = True;
$this->simple_login($_REQUEST['username'], $_REQUEST['password']);
header( 'Location: /site.html' );
}
else {
return 'Username or Password is incorrect' . $sLoginForm;
}
} else {
if ($_COOKIE['member_name'] && $_COOKIE['member_pass']) {
if ($this->check_login($_COOKIE['member_name'], $_COOKIE['member_pass'])) {
header( 'Location: /site.html' );
}
}
return $sLoginForm;
}
}
In the site.php:
<?php
session_start();
if ($_SESSION["loggedin"] == 0)
{
header( 'Location: http://test-weeabear.c9users.io/' );
}
else
{
return "It worked!"
}
?>
Why is it when I open site.html, it redirects me back to index.html, even after logging in?
NOTE: Some things I changed, like links and names of files. For privacy.
You need session_start() at the start of your site.php
change the file extension from .html to .php
You are calling getLoginBox and then changing the loggedin back to false. You need to include an exit after the header redirect.
Like this:
header( 'Location: /site.php' );//changed to file extension as .php
exit;

Detect if cookies are enabled in PHP

I am trying to detect if a user on my page has cookies enabled or not. The following code performs the check, but, I have no idea on how to redirect the user to the page they came from.
The script starts a session and checks if it has already checked for cookies. If not, it redirects the user to a test page, and since I had called session_start() in the first page, I should see the PHPSESSID cookie if the user agent has cookies enabled.
The problem is, ths script might be called from any page of my site, and I will have to redirect them back to their selected page, say index.php?page=news&postid=4.
session_start();
// Check if client accepts cookies //
if (!isset($_SESSION['cookies_ok'])) {
if (isset($_GET['cookie_test'])) {
if (!isset($_COOKIE['PHPSESSID'])) {
die('Cookies are disabled');
} else {
$_SESSION['cookies_ok'] = true;
header(-------- - ? ? ? ? ? -------- -);
exit();
}
}
if (!isset($_COOKIE['PHPSESSID'])) {
header('Location: index.php?cookie_test=1');
exit();
}
}
I think its better to make one file set cookie and redirect to another file. Then the next file can check the value and determine if cookie is enabled. See the example.
Create two files, cookiechecker.php and stat.php
// cookiechecker.php
// save the referrer in session. if cookie works we can get back to it later.
session_start();
$_SESSION['page'] = $_SERVER['HTTP_REFERER'];
// setting cookie to test
setcookie('foo', 'bar', time()+3600);
header("location: stat.php");
and
stat.php
<?php if(isset($_COOKIE['foo']) && $_COOKIE['foo']=='bar'):
// cookie is working
session_start();
// get back to our old page
header("location: {$_SESSION['page']}");
else: // show the message ?>
cookie is not working
<? endif; ?>
Load cookiechecker.php in browser it'll tell cookie is working. Call it with command line like curl. It'll say, cookie is not working
Update
Here is a single file solution.
session_start();
if (isset($_GET['check']) && $_GET['check'] == true) {
if (isset($_COOKIE['foo']) && $_COOKIE['foo'] == 'bar') {
// cookie is working
// get back to our old page
header("location: {$_SESSION['page']}");
} else {
// show the message "cookie is not working"
}
} else {
// save the referrer in session. if cookie works we can get back to it later.
$_SESSION['page'] = $_SERVER['HTTP_REFERER'];
// set a cookie to test
setcookie('foo', 'bar', time() + 3600);
// redirecting to the same page to check
header("location: {$_SERVER['PHP_SELF']}?check=true");
}
HTTP_REFERER did not work for me, seems like REQUEST_URI is what I need.
Here is the code I finally used:
session_start();
// ------------------------------- //
// Check if client accepts cookies //
// ------------------------------- //
if( !isset( $_SESSION['cookies_ok'] ) ) {
if( isset( $_GET['cookie_test'] ) ) {
if( !isset( $_COOKIE['PHPSESSID'] ) ) {
die('Cookies are disabled');
}
else {
$_SESSION['cookies_ok'] = true;
$go_to = $_SESSION['cookie_test_caller'];
unset( $_SESSION['cookie_test_caller'] );
header("Location: $go_to");
exit();
}
}
if( !isset( $_COOKIE['PHPSESSID'] ) ){
$_SESSION['cookie_test_caller'] = $_SERVER['REQUEST_URI'];
header('Location: index.php?cookie_test=1');
exit();
}
}
// ------------------------------- //
There's no need to save the original URL and redirect to it afterwards. You can perform a transparent redirect via AJAX which doesn't trigger a page reload. It's very simple to implement. You can check my post here: https://stackoverflow.com/a/18832817/2784322
I think this is easiest solution. Doesn't require separate files and allows you to proceed with script if cookies are enabled:
$cookiesEnabled = true;
if (!isset($_COOKIE['mycookie'])) {
$cookiesEnabled = false;
if (!isset($_GET['cookie_test'])) {
setcookie('mycookie', 1, 0, '/');
#ob_end_clean();
$_SESSION['original_url'] = $_SERVER['REQUEST_URI'];
$uri = $_SERVER['REQUEST_URI'];
$uri = explode('?', $uri);
$q = (isset($uri[1]) && $uri[1])?explode('&', $uri[1]):array();
$q[] = 'cookie_test=1';
$uri[1] = implode('&', $q);
$uri = implode('?', $uri);
header('Location: '.$uri);
die;
}
} else if (isset($_GET['cookie_test'])) {
#ob_end_clean();
$uri = $_SESSION['original_url'];
unset($_SESSION['original_url']);
header('Location: '.$uri);
die;
}
// if (!$cookiesEnabled) ... do what you want if cookies are disabled

Redirecting cookieless sessions in PHP without clicking a link

I've been fighting with the cookieless sessions solution. Of course cookieless sessions solution is amazing. I have a trouble in implementing it because I can't read the session information after redirecting to another page.
Here's my test code in testcode.php
<?php
ini_set('session.use_trans_sid', '1');
session_start();
if (isset($_GET['pagecode'])) {
session_id($_GET['pagecode']);
print_r($_SESSION); // **cannot read session information here**
exit();
}
if (isset($_SESSION['cookieconfirmed']) && $_SESSION['cookieconfirmed'] == 1) {
} else {
/** Checks if the user's browser is cookie-enabled **/
if (isset($_GET['redirected'])) { // if the page has gotten redirected
$_SESSION['cookieconfirmed'] = 1; // confirmed the cookie-disability
if (isset($_COOKIE['testcookie'])) {
header ('location: testcode.php');
} else {
header('location: testcode.php?pagecode=' . session_id());
}
} else {
setcookie('testcookie', 'OK'); //sets a test cookie.
header('location: testcode.php?redirected=1'); // redirects the page to check cookie-disability
}
exit(0);
}
?>
As you can see this code doesn't work. but if i redirect to another page by clicking a link it works well. Here's the code in testcode.php:
<?php
ini_set('session.use_trans_sid', '1');
session_start();
if (isset($_GET['pagecode'])) {
session_id($_GET['pagecode']);
print_r($_SESSION); // **able to read session information here**
exit();
}
if (isset($_SESSION['cookieconfirmed']) && $_SESSION['cookieconfirmed'] == 1) {
} else {
/** Checks if the user's browser is cookie-enabled **/
if (isset($_GET['redirected'])) { // if the page has gotten redirected
$_SESSION['cookieconfirmed'] = 1; // confirmed the cookie-disability
if (isset($_COOKIE['testcookie'])) {
header ('location: testcode.php');
} else {
echo 'Click here to continue';
}
} else {
setcookie('testcookie', 'OK'); //sets a test cookie.
header('location: testcode.php?redirected=1'); // redirects the page to check cookie-disability
}
exit(0);
}
?>
How can I get this to work without clicking a link?
ini_set('session.use_trans_sid', '1');
You have to have this on every single one of your PHP pages - you can't do it just within the session handling script. If it's not on when PHP generates a page, it won't insert the session ID into forms and urls on that page. As such, it'd be better if you put this into your php.ini, or at least httpd.conf/.htaccess (as a php_value) to make it a global option for all scripts.
PHP function for this is :
function append_sid($link) {
if(session_id() !== NULL && !isset($_COOKIE['PHPSESSID'])) {
if(strpos($link, "?") === FALSE) {
return $link . "?PHPSESSID=" . session_id();
} else {
return $link . "&PHPSESSID=" . session_id();
}
} else {
return $link;
}
}
Javascript Function for this is:
function append_sid(link) {
<?php if(session_id() !== NULL && !isset($_COOKIE['PHPSESSID'])) { ?>
var session_id = '<?php echo session_id ?>';
if(link.indexOf('?') == -1) {
return link + '?PHPSESSID=' + session_id;
} else {
return link + '&PHPSESSID=' + session_id;
}
<?php } else { ?>
return link;
<?php } ?>
}
A caveat – passing session id by URL requires the session.session.use_trans_sid tio be set to 1.
php_value session.use_trans_sid = 1 in the .htaccess file. You can also try the function:
ini_set('session.use_trans_sid', '1')

Categories