| re: session does not propagate after header("Location: page.php")
here is the session.php class:
[PHP]class Session
{
const LEVEL_ADMIN = 1;
const LEVEL_S_USER = 2;
const LEVEL_G_USER = 8;
const LEVEL_GUEST = 9;
public $logged_in; //TRUE if user has given a good PHPSESSID and this SESSID comes from the same IP that athenticated
public $user_name;
public $user_IP;
public $user_level;
public $error;
function __construct(){
if(!isset($_SESSION))
{
session_start();
}
$this->logged_in = $this->check_session();
}
function starter($username, $level){//this method is called from session_auth
global $database, $calendar_auto_updater;
/**
* Session Start - sets a session cookie
*
*
* 1. First time user opens the page (there is no file in the server)
*
* -PHP generates a random value which is used to
* -give value to PHPSESSID: cookie that he sends to Client'sBrowser
* -Client's Browser keeps it for an undefined period of time
* -give name to a File in the Server
*
*
* 2. n>1 Time user opens the page (there is a file in the server)
*
* -Client's Browser Sends an HTTP Header with the PHPSESSID cookie
* -PHP gets PHPSESSID cookie value with session_start()
* -Looks for a file named like the value contained in the cookie (assumming he finds it)
* -Reads its content and creates an array $_SESSION containing the pairs key values
* -At the end of the script if there are $_SESSION[''] attributions:
* -Write into the server file
*/
session_regenerate_id();
$this->user_name = $_SESSION['user_name'] = $username;
$this->user_IP = $_SESSION['user_IP'] = $_SERVER['REMOTE_ADDR'];
$this->user_level = $_SESSION['user_level'] = $level;
if($calendar_auto_updater->auto() == true){
if($database->DB_add_active_user($this->user_name, $this->user_IP, $this->user_level, session_id()) == true){
/**
* we have to recall check session to set logged in = true because at object instace calling,
* the constructor checks logged in before starting a new session
* with $this->starter.
* this is: firts logged_in == false and once starter called logged_in should be true, but check_session is not called again.
* this is why logged_in has to be set to logged_in from starter method
*/
$this->logged_in = true;
return true;
}
else{
$this->error = "could not insert active user into db";
return false;
}
}
else{
print_r($calendar_auto_updater->error);
}
}
function check_session(){
global $database;
/**
* if the user has been authenticated, the script has sotred his name on session file
* so if the user gives a SESSID which refers to a file with no name on it, this mean
* it is a malicious user.
* if the user gives a SESSID which refers to a file with a name on it, check if the
* SESSID comes from the same IP the first user authenticated from.
*/
if(isset($_SESSION['user_name']) && isset($_SESSION['user_IP'])){//there is a value in file with key user_name
if($_SERVER['REMOTE_ADDR'] == $_SESSION['user_IP']){// if the client IP corresponds to the first (authenticated) client IP
/* Check if the user is logged in, if yes, store session variables, else log him totally out */
if($database->DB_check_active_user($this->user_name, $this->user_IP) == true){
$this->user_name = $_SESSION['user_name'];
$this->user_IP = $_SESSION['user_IP'];
$this->user_level = $_SESSION['user_level'];
return true;
}
else{
$this->unset_session();
return false;
}
}
else{//there is a fraud, report it to DB
$database->DB_report_fraud($_SESSION['user_name'], $_SERVER['REMOTE_ADDR']);
return false;
}
}
else{// the user is not authenticated
return false;
}
}
public function add_session_vars($obj ,$key, $value){
$_SESSION[$obj][$key] = $value;
if($_SESSION[$obj][$key] == true){
return true;
}
else{
return false;
}
}
function unset_session(){
global $database;
// Unset all of the session variables.
$_SESSION = array();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (isset($_COOKIE['PHPSESSID'])) {
setcookie('PHPSESSID', '', time()-42000, '/');
}
// Finally, destroy the session.
session_destroy();
if($database->DB_set_unactive_user($this->user_name, $this->user_IP)){
return true;
}
else{
print_r($database->error);
}
}
}
?>[/PHP]
then here is the session_auth.php class, it is used to check the posted user credentials consistency:
[PHP]class Session_auth extends Session
{
const MAX_PASS_ERR = 3; //number of times a user is allowed to fail submiting password
private $secured = "jo2lDly5ju_m66FDperIs%";
public $errors = false;
private $DB_response; //stores the result of DB class query
public $pre_user; //username with stripslashes for DB checking
private $pre_pass; //password with stripslashes + md5 for DB checking
public $pre_mail;
/* Basic form submitted data checking */
function login($sub_user, $sub_pass){
global $database, $session, $account_manager, $pre_session; //+$mail
$this->pre_user = $sub_user;
/* -USERNAME- */
/* Check it the username is long enough getting rid of spaces */
if(!$sub_user || strlen($sub_user) < 8){
$this->errors['sub_user']['char'] = "Need Username, minimum length is 8";
}
/* Check if username is not alphanumeric */
else if(!eregi("^([0-9a-z])*$", $sub_user)){
$this->errors['sub_user']['char'] = "Username not alphanumeric";
}
/* Store sub_user on a momentanious var $pre_user */
else{
$this->errors['sub_user'] == false; //no errors
}
/* -PASSWORD- */
/* Check it the password is long enough getting rid of spaces */
if(!$sub_pass || strlen($sub_pass) < 8){
$this->errors['sub_pass']['char'] = "Need Password, minimum length is 8";
}
/* Store sub_pass on a momentanious var $pre_pass with md5 */
else{
$this->pre_pass = md5($sub_pass);
$this->errors['sub_pass'] == false; //no errors
}
/* CHECK AGAINST DB and do... */
if($this->errors['sub_user']['char'] == false && $this->errors['sub_pass']['char'] == false){//if no character errors
$this->DB_response = $database->DB_login_credentials($this->pre_user, $this->pre_pass);
/* User and Pass match in DB */
if($this->DB_response == true){
unset($this->errors); // delete error content for next try
if($database->DB_check_unactive_user($this->pre_user, "all") == true){//check if the user is not logged in from elswhere
if($database->DB_isnot_quarantine_user($this->pre_user) == true){//check if the user is in quarantine
/* The user seems has the rights to log in */
if($session->starter($this->pre_user, $database->response_level) == true){
return true;
}
else{
$this->errors['general']['auth'] = "Sorry, the system was unable to log you in, there was a Server error";
return false;
}
}
else{
$session->starter($this->pre_user, 8); //start a session with reduced powers, to make availible user_name to quarantine to resend a mail
$this->errors['general']['auth'] = "You were put in quarantine at last login attempt, please check your mail box, an e-mail should have been sent. Click here to be sent another one. <a href=quarantine.php?mail=resend>Resend em@il</a>";
return false;
//$database->error['log']['user'] is the real error
}
}
else{ //the user has logged in from a different ip
//as the user has given the right credentials, but he has to logout before relogging in...
//so create a pre session that will only allow him to loggin after having done what we asked him
$pre_session->pre_starter($this->pre_user, $database->response_level);
$this->errors['session_auth'] = $database->error['log']['user'];
$database->DB_report_fraud($this->pre_user, $_SERVER['REMOTE_ADDR']);
return false;
}
}
/* DB returns Error */
else{
if($database->error['log']['user'] == true){//user does not exist in db
$this->errors['sub_user']['DB'] = $database->error['log']['user'] ;
return false;
}
else if($database->error['log']['pass'] == true){//the client has submited wrong password
if($database->DB_isnot_quarantine_user($this->pre_user)){//the user is not in quarantine, so lets see how many tries he has left and put him in quarantine if necessary
if($database->DB_report_wrong_pass($this->pre_user, $this->pre_pass.$sub_pass, $_SERVER['REMOTE_ADDR']) == true){
//calculate the number of tries left
$max_tries = Session_auth::MAX_PASS_ERR;
$actual_tries = $database->response;
$left_tries = $max_tries - $actual_tries;
if($left_tries < 1){//the user has reached his maximum attempts Put him in quarantine with a brand new generated md5 password to validate via url in mail
//first get user e-mail
$database->DB_get_mail($this->pre_user);//stores mail into a variable of database class
if($account_manager->credentials_refactor($this->pre_user, $database->mail, $this->secured) == true){ //create a new password for the account
/**
* $account_manager will create a new password, and will insert the user_name user_ip and user_new_pass into table quarantine
* and will send the user a url with the password
* when quarantine.php recives the right password, it calls again account manager to
* delete the user from quarantine table and asks him for a new password
* when POST new password is true, it calls again account manager to update the data into users table
*/
$this->errors['general']['auth'] = "You reached the maximum wrong password submitting attempts, an e-mail has been sent to your box with a link and all the instructions to follow up.";//store error, auth will send this to client_side
return false;
}
else{
$this->errors['internal']['account_manager'] = "Problem while creating new credentials for account, ".$account_manager->error;
return false;
}
}
else{
$this->errors['sub_pass']['auth'] = "You entered a wrong password, ".$left_tries." tries left.";// make a system where
return false;
}
}
else{
$this->errors['internal']['mysql'] = $database->error['req']['mysql'];
return false;
}
}
else{//the user is already in quarantine and has submited wrong credentials, take his ip and bann him
$this->errors['general']['auth'] = "You were put in quarantine at last login attempt, please check your mail box, an e-mail should have been sent.";
return false;
}
}
else{
$this->errors['internal']['mysql'] = $database->error['req']['mysql'];
return false;
}
}
}
else{//if character errors
return false;
}
}
}
?>
[/PHP]
then, here is the lowest page auth.php, which receives all data and transmits it to session_auth :
[PHP]<?php
include_once("includings/inc.php");
/**
* User wants to login: submitted SUPERGLOBALS
*/
if(isset($_POST['user_name']) || isset($_POST['user_pass'])){
if($session->logged_in != true){
/*Store values*/
$posted_u_n = substr(trim(htmlentities($_POST['user_name'])), 0, 20);
$posted_u_n = preg_replace('/[^\w\.\-\& ]/', '', $posted_u_n);
$posted_u_p = substr(trim(htmlentities($_POST['user_pass'])), 0, 20);
$posted_u_p = preg_replace('/[^\w\.\-\&]/', '', $posted_u_p);
/*Check login succeed*/
if ($session_auth->login($posted_u_n, $posted_u_p) == true){
//redirect to logged in section
header("Location: calendar.php");
}
else{//login failed or the user logged in but is still in quarantine
$client_side->HTML_login_form($session->user_name, $session_auth->errors);
}
}
else{
$error['logout']['can'] = 'log yourself out';
$client_side->HTML_login_form($session->user_name, $error);//can logout
}
}
/**
* User wants to logout: submited SUBERGLOBALS
*/
else if($_GET['logout'] == 'true'){
/*Check if logged in*/
if($session->logged_in == true){
/*Log him out*/
if($session->unset_session() == true){
//logout succeed
$error['logout'] = 'logged out';
$client_side->HTML_login_form("Guest", $error);//message: you have logout + login form
}
else{
//unable to log you out
$error['logout'] = 'could not logout';
$client_side->HTML_login_form($session->user_name, $error); //message: unable to logout
}
}
else{
if($pre_session->pre_logged_in == true){ // the user was logged in from another ip, and wants to logout and relogin from this ip. Already gave good credentials
/* Set all the records on whose is said: active = 1 to 0 */
/* Now when the user, that had logged in from the other ip checks if he is active, he wond find a record with IP active = 1 */
if($database->DB_set_unactive_user($pre_session->pre_user_name, "all") == true){
/* Start a normal session which gives him his normal powers */
if($session->starter($pre_session->pre_user_name, $pre_session->pre_user_level) == true){ if($session->logged_in == true){//------------------AT THIS POINT SESSION IS STARTED OK
header("Location: page.php");//---------------------HERE IS THE PROBLEM
}
else{
print "not logged in";
}
}
else{
//unable to log you out
$error['login'] = 'could not login';
$client_side->HTML_login_form($session->user_name, $error);
}
}
else{
//unable to log you out
$error['logout'] = 'could not logout';
$client_side->HTML_login_form($session->user_name, $error); //message: unable to logout
}
}
else{
//you are not logged in
$error['logout']['can'] = 'not logged in';
$client_side->HTML_login_form("Guest", $error); //message: not logged in cant logout...
}
}
}
/**
* User can login: requested Blank page
*/
else{//user requests this page from elsewhere than a form
//show the first login fosrm
if($session->logged_in == false){
$error['first'] = '1';
$client_side->HTML_login_form('Guest',$error);//can login_form + register_link
}
else{
$error['logout']['can'] = 'log yourself out';
$client_side->HTML_login_form($session->user_name, $error);//can logout
}
}
?>[/PHP]
when the parser goes to where i wrote ----------HERE IS THE PROBLEM (above), the session is started ok, but when it redirects to the script: page.php, it calls $session->logged_in and it returns false, the user is no longer logged in
here is the code of page.php:
[PHP]
class page_class
{
private $data_array = array();
private $formatted_array = array();
public $error = false;
public function __construct(){
global $session, $client_side, $database;
/* Check Session - Only make calendar actions if user logged in */
if($session->logged_in == true){
print "you are logged in";
}
}
[/PHP]
all these files are correctly included in inc.php which is itself included in auth.php
from the client side, it looks as if the script regenerated a new PHPSESSID when going to the other script and that should be the reason why $session->logged_in returns false...
but i don't know where i tell PHP to create a new session id at each time a new page is sent...
with firefox i can see that the request header sends PHPSESSID: XXX and the response header returns another PHPSESSID: YYY
i cant understand why the session is lost.
from the server side, i can see in /temp that all the sessions are still there and that they were not removed by session.max_liftime
do you see a reason why php would generate a new session id at each time?
Firstly i thought that this might be because of the session_regenerate_id() when i start the session, but this is done only once... when $session->starter() is called. but when $session::__construct calls $session->check_session() to determine whether logged_in is true or not it never regenerates_id.
Please if you have any suggestion let me know
Thankyou very much for your time
bilibytes
|