Need help with sessions

I am having a tough time implementing sessions over 3 pages

test.php - this page will display the selected table from the dropdown box. .Each cell also has an action where if you click in it, something happens and then updates the table in the DB and in turn gets updated here via test_checksum.php

test_checksum.php sole purpose is to get all data from the table and store an MD5 in a session every second.

load_table.php will create the table based on the drop down selection on test.php and also after it gets updated via test_checksum.php

I can flip flop between tables just fine. I can click on any cell in any table just fine and the table updates properly.

Problem - in load_table.php, I can not do
unset($_SESSION[“group_pairing_name_video”])
becuase it seems to be doing nothing

I am stuck doing
session_unset($_SESSION[“group_pairing_name_video”])
Since I need to replicate these 3 pages 7 more times (under different var and session names), all other sessions die when I use that

test.php

<script>
    function refresh_div() {
        jQuery.ajax({
            url:'test_checksum.php',
            type:'POST',
            success:function(results) {
                jQuery(".result").html(results);
				if (results != "no change")
					{
						$("#screen_video").load('load_table.php?lang=<?php echo $lng;?>');
					}
            }
        });
    }
    t = setInterval(refresh_div,1000);
</script>
<!--<div class="result"></div>-->

<script>
function showUser(str) {
  if (str=="") {
    document.getElementById("txtHint").innerHTML="";
    return;
  }
  var xmlhttp=new XMLHttpRequest();
  xmlhttp.onreadystatechange=function() {
    if (this.readyState==4 && this.status==200) {
      document.getElementById("txtHint").innerHTML=this.responseText;
    }
  }
  xmlhttp.open("GET","load_table.php?lang=<?php echo $lng;?>&video="+str,true);
  xmlhttp.send();
}
</script>

<select name = 'video_group' class = "rounded"  onchange='showUser(this.value)'>
<option>All</option>
<option>test</option>
</select>


<div id="screen_video"><div id='txtHint'></div>
    <div id="content"></div>
    <img src="loading.gif" id="loading" alt="loading" style="display:none;" />
	</div>
</div>

load_table.php

session_start();

$group_pairing_name_video = $_GET['video'];

if($group_pairing_name_video)
	{
		if($group_pairing_name_video !== $_SESSION["group_pairing_name_video"])
			{
				session_unset($_SESSION["group_pairing_name_video"]);
				$_SESSION["group_pairing_name_video"] = $group_pairing_name_video;
				$_SESSION["group_pairing_name_video_previous"] = 
                                $group_pairing_name_video;
			}
		else
			{
				$_SESSION["group_pairing_name_video"]  = $group_pairing_name_video;
			}
	}
else
	{
		$group_pairing_name_video = $_SESSION["group_pairing_name_video_previous"];
	}

test_checksum.php

<?php 
session_start();

$_SESSION["my_checksum_video_grid"] = $my_checksum_video_grid;

if($_SESSION["my_checksum_video_grid"] == $_SESSION['my_previous_checksum_video_grid'])
	{
		//do nothing
		echo "no change";
		mysqli_close($con);	
	}
else 
	{
		unset($_SESSION["my_previous_checksum_video_grid"]);
		$_SESSION['my_previous_checksum_video_grid'] = $my_checksum_video_grid;
		//Execute script
		echo $my_checksum_video_grid;
		mysqli_close($con);	
	}
 ?>

If test.php is called first then I would try the following:

test.php

<?php 
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'true');
if( isset($_SESSION) ):
  // prevent warnings
else:
  session_start();
endif;
//

load_table.php

<?php 
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'true');
if( isset($_SESSION) ):
  // prevent warnings
else:
  session_start();
endif;
//

test_checksum.php

<?php 
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'true');
if( isset($_SESSION) ):
  // prevent warnings
else:
  session_start();
endif;
//

Edit:

Please note that PHP function session_unset(); does not accept any parameters and removes all session variables.

https://www.php.net/manual/en/function.session-unset.php

To remove a variable try:

echo $_SESSION['group_pairing_name_video'];
unset( $_SESSION['group_pairing_name_video']);
if ( isset($_SESSION['group_pairing_name_video']) ) :
  echo 'STILL SET???';
else:
  echo 'GONE';
endif;
echo '<pre>'; print_r($_SESSION); echo '</pre>';
die; 

Thanks. Yes test.php is the only page that people will go to, select a table from the dropdown and then gets displayed via load_table.php and updated via test_checksum.php. I will try this tomorrow and let you know how it goes

1 Like
if( isset($_SESSION) ):
  // prevent warnings
else:
  session_start();
endif;

This is pretty old-school. New-school is:

if (session_status() !== PHP_SESSION_ACTIVE) {
  session_start();
}

See https://www.php.net/manual/en/function.session-status.php

4 Likes

surely you meant PHP_SESSION_DISABLED there?

No, I meant PHP_SESSION_ACTIVE. I’ve never come across a system where sessions are actually disabled. But indeed, for completeness sake one could also do:

if (session_status() === PHP_SESSION_DISABLED) {
  exit('Oh noes, this PHP installation does not support sessions. Unable to continue :(');
}

if (session_status() === PHP_SESSION_NONE) {
  session_start();
}

I’m confused then.

Why would you care about calling session_start if the session is active? session_start doesnt generate warnings to resume a session if one is already running, unless it’s being called twice within the same execution…the three php pages are in separate contexts (AJAX calls), so… i don’t see how the session_starts would collide.

In these actual scripts I wouldn’t. Generally I would, to prevent having it called twice after headers were already sent for example. Better safe than sorry.

It might be a better idea to refactor, and replace duplication by having one-location handling this, instead of seven.

Back on subject, in the event, the additional pages are on a different domain/subdomain, it could be CORS issues, or cookie setting issues (i.e. session id is not propagated).

With that out of the way, try removing your automatic refresh every second from the page, could be that you have a race condition happening, where the automatic refresh is setting the value again, right after you deleted it.

It could also be a good idea, if you do not already do it, to initiate the session on the main page as well, ensuring there won’t be a session race condition if you potentially do multiple calls on the same page, that could execute at the same time.

Thanks to all of you. I have all the session issues sorted out now.

RedDevil - I can’t remove the 1s refresh because that updates the table. Basically, the checksum page gets the data from a DB and creates a checksum every second. If the checksum’s match, then the refresh does not occur. This prevents having to get refreshes when there are no updates to the table.

1 Like

Can you share the solution for the benefit of others with similar problems.

Sorry bout that. The application is to display a table based on the dropdown selection and update it when there is a change. Table can be any size and all info is stored in a DB. Table can go up to a few hundred rows and columns.

On top of every page, I have

declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'false');
if (session_status() !== PHP_SESSION_ACTIVE) {
  session_start();
}

errors are turned off after I verified that the sesion vars are what they are supposed to be

test.php is the main page where you select the table, perform the updates, and see the changes display without any flicker

<script>
    function refresh_div() {
        jQuery.ajax({
            url:'video_grid_checksum.php',
            type:'POST',
            success:function(results) {
                jQuery(".result").html(results);
				if (results != "no change")
					{
						$("#txtHint").load('video_grid_table.php?lang=<?php echo $lng;?>');
					}
            }
        });
    }
    t = setInterval(refresh_div,1000);
</script>
<!--<div class="result"></div>-->


<script>
function showUser(str) {
  if (str=="") {
    document.getElementById("txtHint").innerHTML="";
    return;
  }
  var xmlhttp=new XMLHttpRequest();
  xmlhttp.onreadystatechange=function() {
    if (this.readyState==4 && this.status==200) {
      document.getElementById("txtHint").innerHTML=this.responseText;
    }
  }
  xmlhttp.open("GET","video_grid_table.php?lang=<?php echo $lng;?>&video="+str,true);
  xmlhttp.send();
}
</script>

<select name = 'video_group' class = "rounded"  onchange='showUser(this.value)'>
<!--display all table groups from DB-->
</select>

	
<div id='txtHint'></div>
    <div id="content"></div>
    <img src="loading.gif" id="loading" alt="loading" style="display:none;" />

video_grid_table.php takes the value from the selected table group and displays them

$group_pairing_name_video = $_GET['video'];

if($group_pairing_name_video)
	{
		if($group_pairing_name_video !== $_SESSION["group_pairing_name_video"])
			{
				//unset( $_SESSION['group_pairing_name_video']);
				$_SESSION["group_pairing_name_video"] = $group_pairing_name_video;
				$_SESSION["group_pairing_name_video_previous"] = $group_pairing_name_video;
			}
		else
			{
				$_SESSION["group_pairing_name_video"]  = $group_pairing_name_video;
			}
	}
else
	{
		
		unset($_SESSION['group_pairing_name_video']);
		$_SESSION["group_pairing_name_video"] = $_SESSION["group_pairing_name_video_previous"];
		$group_pairing_name_video = $_SESSION["group_pairing_name_video_previous"];
		//echo '<pre>'; print_r($_SESSION); echo '</pre>';
	}
//Build table grid

video_grid_checksum.php checks the db, creates a checksum, compares it with the previous checksum and if there is a change, return anything but “no change” in order to update the table

$_SESSION["my_checksum_video_grid"] = $my_checksum_video_grid;

if($_SESSION["my_checksum_video_grid"] == $_SESSION['my_previous_checksum_video_grid'])
	{
		//do nothing
		echo "no change";
		mysqli_close($con);	
	}
else 
	{
		unset($_SESSION["my_previous_checksum_video_grid"]);
		$_SESSION['my_previous_checksum_video_grid'] = $my_checksum_video_grid;
		//Execute script
		echo $my_checksum_video_grid;
		mysqli_close($con);	
	}

This is all working perfectly where I can flip flop between tables, update any table and the login session is not getting lost

I did a quick test with 3 incognito windows and can alter any table in any browser window without affecting its other windows. Do you guys think this is a good enough test? Also, these pages are all on 1 domain.

The problem with this approach is that every user that uses the system, will send a background request to the checksum page every second. This can amount up to a lot of requests in a short amount of time if there is more than one user on the site. Even if there is only one user, utilizing the system, it still accounts for 60 page loads per minute.

Looking aside from the resource drain it is, it is also a potential location for a race condition, since the request you make is asynchronous. This means that you do not control the order the requests will return to you.

With network lag, process lag on the server, it is possible that a set of processes you initiate over three seconds like 1,2,3 return as 2,3,1 or in any other order. If this happens, it would potentially trigger updating the records with incorrect data, depending on the rest of your code.

While a refactoring of the system would be the best approach, you can also solve this by increasing the interval time, to at least 5-10 seconds. In most cases, for what you do here, even 30 seconds might be acceptable polling.

Thanks. If 100 users are looking at the page and not making any changes, there won’t be any refresh but there will be a load of background checks going on so I understand the concern here…

For the checksum page, would I be saving anything if I moved away from sessions and did a row count instead? I already capture the timestamp each time the table is updated and instead of doing a checksum and storing it in a session, I can compare the timestamp of the table to the current timestamp and if there is a different of say 10s, I update the table. I would check the DB every 10s

This would save 2 session vars per user per table (I will have 8 tables in total) while the DB hit stays the same.

This depends, if you are thinking to only run an update against the table on each change, then yes this would be a better approach.

If you intend to poll the table for if its changed every X time, similar to how the checksum works, then it is a bad idea. Since the database calls are more expensive to do, than running PHP code.

Thank you

A better alternative to polling is using a web socket.

With a websocket you can send a message to the client from the server and have the client react to that message. Rather than relying on legacy techniques like long polling.

I am able to create a websocket and capture a table change event. I have this in an endless loop just running in the background waiting until the event TABLE_CHANGED occurs and then issue a ws.send(“change”)

But what do I do in the main page that displays the table? I run an endless loop waiting for a response and if it received :change:, I update the table?

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.