Can't access session data session_write_close - php

I was having issues with the session file being locked, so I added session_write_close() once I was done with the session. The script worked properly before that, however, once I leave the sign-in page now, the session is blank.
Session is started at the top of index.php which includes the sign in page:
$result = 'token_valid';
$_SESSION['user'] = $email;
print_r($_SESSION);
session_write_close();
print_r($_SESSION);
The session data is returned properly both times on the sign-in page.
Array ( [user] => abc#gmail.com ) Array ( [user] => abc#gmail.com )
A link returns to the home page, which calls a function to check if logged in...
function user_is_signed_in() {
print_r($_SESSION);
session_write_close();
if($user == '') {
return False;
}
else {
return True;
}
}
The session no longer has any data.
Full index.php
<?php
session_start();
include_once('fnc/database.php');
include_once('fnc/user.php');
if(!user_is_signed_in()) {
include('sign-in.php');
}
else {
$url = parse_url($_SERVER['REQUEST_URI']);
if(!$url['query'])
{
include('home.php');
}
else {
if(isset($_GET['media']))
{
include($_GET['media'].'.php');
}
if(isset($_GET['user']))
{
include($_GET['user'].'.php');
}
}
}
.
.
Workaround (probably filthy)
Issue seems to be caused by the reading/writing of the actual session file. Used the session_id generated by PHP and just created a secondary session file. Do not save in same folder (or if you do, change the filename) - session_start seems to delete and regenerate the session file PHP manages and you'll lose any data written there.
session_start();
$sess = array();
$sess = $_SESSION;
$sess["id"] = session_id();
//print_r($sess);
session_write_close();
Create session_data in session folder
$session_details = "user|".$email;
$session_file = "/Programs/XAMPP/tmp/session_data/sess_".$sess["id"];
//echo $session_details;
$fh = fopen($session_file, 'w+');
fwrite($fh, $session_details);
fclose($fh);
Read session data from this file instead of the session
$session_path = "/Programs/XAMPP/tmp/session_data/sess_".$sess["id"];
$fh = fopen($session_path, 'r');
$session_file = fread($fh, filesize($session_path));
$exploded_session = explode("\n", $session_file);
$session_data = array();
foreach($exploded_session as $line)
{
$tmp = explode("|", $line);
$session_data[$tmp[0]] = $tmp[1];
}
return $session_data["user"];
fclose($fh);

Related

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 $_SESSION var cannot saved in mobile

I'm develop a hybrid application and it will using PHP sessions to save user information. In my case, I tried to used php sessions to save the data, but it doesn't save. And then, to testing in web, the result var is show saved.
Here is my example:
<?php
session_start();
if(isset($_POST["Token"])){
$token = $_POST["Token"];
if (isset($_SESSION['device_token']) && $_SESSION['device_token']) {
$token = $_SESSION['device_token'];
} else {
$_SESSION['device_token'] = "notoken";
}
}
?>
Here is my PHP info:
My php Info 1
My php Info 2
Edit:
<?php
ini_set('session.save_path',$_SERVER['DOCUMENT_ROOT'] .'/phpVar');
session_start();
if(isset($_POST["Token"])){
$token = $_POST["Token"];
$_SESSION['device_token'] = $token;
}
if(isset($_GET['ID'])){
$token = $_SESSION['device_token'];
$member_id = $_GET['ID'];
$_SESSION['ID'] = $member_id;
echo $_SESSION['device_token'] ;
echo $_SESSION['ID'] ;
}
?>
because you missed the }
so, instead of:
if(isset($_POST["Token"])){
$token = $_POST["Token"];
should be:
if(isset($_POST["Token"])){
$token = $_POST["Token"];
}
EDIT
Ok, then try to see whether you session directory is writable:
if (!is_writable(session_save_path())) {
echo "No, it's not. Path:".session_save_path();
}
else{
echo "yes, it's writable";
}
EDIT
when path is not set, you might set it manually just before session_start
ini_set('session.save_path',getcwd(). '/tmp');
and afterwards you need to create tmp folder and give it right permission

Can I open/close a session in PHP multiple times (and if so what is going wrong)?

So this is how my login process works:
authenticate.php
sessionStart();
if (isset($_SESSION) && !empty($_SESSION['LOCATION'])) {
$location = $_SESSION['LOCATION'];
unset($_SESSION['LOCATION']);
} else {
$location = '//' . $_SERVER['SERVER_NAME'];
}
session_write_close();
sessionStart();
$userIsOnline = isset($_SESSION['ID']);
session_write_close();
sessionStart();
if (!$userIsOnline) {
// Get the user from the database
// Validate the user's password
$_SESSION['ID'] = $user->id;
$_SESSION['UN'] = $user->un;
// ... more information
}
session_write_close();
header($location);
exit();
The contents of the sessionStart function:
if (session_id() == '') {
session_name('MyWebsite');
session_set_cookie_params(86400, '/', $_SERVER['SERVER_NAME'], true, true);
session_start();
$_SESSION['LAST_ACTIVITY'] = time();
$_SESSION['CREATED'] = time();
}
Then on the top of every page on my website:
sessionStart();
print_r($_SESSION);
$_SESSION['LOCATION'] = $_SERVER['REQUEST_URI'];
session_write_close();
Prints an empty array. So for some reason, it is wiping my session array during the redirect? Anyone have any ideas?
Also, the values of CREATED and LAST_ACTIVITY are from this question.
If it is not the issue that HTTPS is not used, but the session cookie is set to Secure then my other thought is to change
if (session_id() == '') {
session_name('MyWebsite');
session_set_cookie_params(86400, '/', $_SERVER['SERVER_NAME'], true, true);
to
if (session_name('MyWebsite') != 'MyWebsite') {
session_set_cookie_params(86400, '/', $_SERVER['SERVER_NAME'], true, true);
I wonder if it is giving you a Session ID under a different name, which is why print_r($_SESSION); is coming up empty. If not, I'm out of ideas!

preventing multi refresh to count on stats script

i am working on a project which one of our web application would be somehow JavaScript code to gather statistical information about visitors but as far as i know on server side PHP application i should somehow handle the code in a way that multi refresh doesn't count and counting on IP based is not a good idea since many users may have the same IP , cookie or session are also vulnerable to this issue because cookie manager can just wipe out all the cookie related to the site so PHP won't recognize the user and count it new,timeframe jobs and all other way to get-around of this issue are also as far as i know based on cookie or session or ip or a mixture of ip/referrer and all other available data from header, how can i handle it and get more reliable data from users and don't permit them to create fake stats. as i believe there must be a way (i hope so)...!?
I think cookies would be ideal for this kind of problem, but if you do not want to use that then you've got yourself a tough cookie. Unfortunately you don't have many other options since HTTP is stateless.
I would use session vars in this case since the user cannot meddle with the data saved there. There is however the risk of session hijacking, but if your site is open to that vulnerability you need to look at securing the site on a more global level that just the hit counter. The session variable is bound to your site since the data in it is saved on the server rather than in the users browser. And is bound to your user since it saves a cookie with a key in the users browser to request the data from the server.
Here is an example on how you can implement this and not worry about deleting other sessions on the site.
<?php
function hit_counter() {
if(isset($_SESSION['hit_counter'])) { // Check if the user has the hit_counter session
if(isset($_SESSION['hit_counter']['time']) && isset($_SESSION['hit_counter']['page'])) { // Check if the user has the time and the page set from the last visit
$last_time = $_SESSION['hit_counter']['time'];
$last_page = $_SESSION['hit_counter']['page'];
$now = time(); // The current UNIX time stamp in seconds
$current_page = $_SERVER['REQUEST_URI']; // The page name
/*
If the users hasn't requested this page
in the last 10 seconds or if the user
comes from another page increment the
hit counter
*/
if(($now - $last_time) > 10 || $last_page != $current_page) {
/* INCREMENT YOUR HIT COUNTER HERE */
}
}
unset($_SESSION['hit_counter']); // Delete this hit counter session
}
// And create a new hit counter session
$_SESSION['hit_counter'] = array();
$_SESSION['hit_counter']['time'] = time();
$_SESSION['hit_counter']['page'] = $_SERVER['REQUEST_URI'];
}
?>
You will never touch any of the other session variables since you're only unset()ing the hit counter variable. There is no need for you to handle session_destroy(), but you need to make sure that there is a session_start() in the beginning of every page you would like to use function in.
You could edit the script to not factor in time if you'd only want to count hits if the user comes from another page on your site.
This is as far as I can see, a hit counter with a sensible level of security for most sites. Or at the very least a good start.
Some more information about PHP sessions.
I created this
<?php
namespace Codelaby\EventDateGenerator;
class CounterVisitors
{
private $filename = "counter.txt";
private $sessionId;
private $sessionStart;
public function __construct()
{
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['sessionId'])) {
$this->sessionId = md5(uniqid(rand(), true));
$_SESSION['sessionId'] = $this->sessionId;
$this->sessionStart = time();
$this->hitCounter();
} else {
$this->sessionId = $_SESSION['sessionId'];
if (!isset($_SESSION['sessionStart'])) {
$this->sessionStart = time();
} else {
$this->sessionStart = $_SESSION['sessionStart'];
}
if (time() - $this->sessionStart > 60) {
$this->sessionStart = time();
$this->hitCounter();
}
}
$_SESSION['sessionStart'] = $this->sessionStart;
}
private function saveCounter($counter = 0)
{
if (!file_exists($this->filename)) {
touch($this->filename);
}
$fp = fopen($this->filename, "w");
if (!flock($fp, LOCK_EX)) {
return;
}
fwrite($fp, $counter);
flock($fp, LOCK_UN);
fclose($fp);
}
public function readCounter()
{
if (!file_exists($this->filename)) {
touch($this->filename);
}
$fp = fopen($this->filename, "r");
if (!flock($fp, LOCK_EX)) {
return;
}
$file_size = filesize($this->filename);
if ($file_size <= 0) {
$counter = 0;
} else {
$counter = intval(fread($fp, $file_size));
}
flock($fp, LOCK_UN);
fclose($fp);
return $counter;
}
public function hitCounter()
{
$counter = $this->readCounter();
$counter++;
$this->saveCounter($counter);
return $counter;
}
public function resetCounter($counter = 0)
{
$this->saveCounter(0);
}
}
How to use
session_start() //before send headers
$counterVisitors = new CounterVisitors();
$visitors = $counterVisitors->readCounter();
echo 'visitors: ' . $visitors;
The script generate counter.txt if not exist, only increment visit if user start new session or wait 60 seconds for refresh

PHP session variables not carrying over

I have a controller/controller.php file that starts a session and sets some session variables. I then 'include' a model/model.php file and call a function to load it.
When I try and use the session variables from the controller.php file in the model.php file, I am getting many: Undefined variable: _SESSION errors.
Here is an example of setting a session variable in the controller.php file:
$_SESSION['userName'] = 'some data'
In the model.php file I am trying to retrieve it by this code:
print($_SESSION['userName']);
What am I doing wrong?
EDIT
my controller.php file code:
<?PHP
session_start();
if (isset($_POST['Login'])) {
$_SESSION['pointsForQuestion'] = '1';
$_SESSION['userName'] = $_POST['txtUsername'];
if(!is_file($_SESSION['userName'].".txt"))
{
writeUserDetails($_SESSION['userName'],"1","0");
$_SESSION['currentLevel'] = "1";
$_SESSION['score'] = "0";
} else {
readUserDetails($_SESSION['userName']);
}
print('logged in');
include('../model/model.php');
print page_load();
}
function writeUserDetails($username,$level,$score) {
$fh = fopen($username.".txt", 'w') or die("can't open file");
fwrite($fh, $level.",".$score);
fclose($fh);
}
function readUserDetails($username) {
$userDetails = explode(',', file_get_contents($username.".txt"));
$_SESSION['currentLevel'] = $userDetails[0];
$_SESSION['score'] = $userDetails[1];
}
?>
Start your session before defining the session variables on top ie session_start();
Edited
You have not set anything for these session variable that's why it is giving that error
$_SESSION['userName'];
$_SESSION['currentLevel'];
$_SESSION['score'];
You can delete these session variables if u dont want to set anything...
$_SESSION is a superglobal available in all scopes.
So, you must have forgotten session_start().

Categories