Skip to content
Advertisement

php 7.3 can not open hidden session (session_id() fails to set id)

I have a php application that opens a session and sends the appropriate cookie to the browser like normal.

Somewhere in the script I want to close the current session, silently open a new one in the background, get some values from this “background session”, close it again and resume the main session (the one the user got cookies for).

In Debian Stretch having PHP 7.0 the following minimal example worked like a charm but now in PHP 7.3 (Debian Buster) I get several warnings and the example ceases to work.

Expected output (as in PHP 7.0):

Main session closed now...<br>
Read data '10' and closed hidden session again...<br>
Main session resumed...<br>

Actual output (as in PHP 7.3):

Main session closed now...<br>
Warning: session_id(): Cannot change session id when headers already sent
Warning: session_start(): Cannot start session when headers already sent
Read data '' and closed hidden session again...<br>
Warning: session_id(): Cannot change session id when headers already sent
Warning: session_start(): Cannot start session when headers already sent
Main session resumed...<br>

Minimal (not-) working example:

$options=array('use_cookies'=>false, 'cache_limiter'=>'');
session_start();
$main_id=session_id();
$_SESSION["value"] = "xxx";
session_write_close();
echo "Main session closed now...<br>n";
flush();

session_id("IdOfHiddenSession");
session_start($options);
$count=$_SESSION['count']++;
session_write_close();
echo "Read data '$count' and closed hidden session again...<br>n";
flush();

session_id($main_id);
session_start($options);
echo "Main session resumed...<br>n";
flush();

How can I fix this?

Advertisement

Answer

The solution is to disable session cookies for all sessions on script start instead of allowing cookies for the first session_start() and disabling them for subsequent session_start() calls.

You have to send the cookie for the main session yourself in this case!

So on script start do:

ini_set("session.use_cookies", 0);
ini_set("session.use_only_cookies", 1);

And set the cookie yourself, if needed:

header("Set-Cookie: {$name}={$id}; path=/; secure; HttpOnly; SameSite=Strict");

The example code of the question thus becomes this:

//do this *only* on script start before headers are sent
if(!headers_sent())
{
    session_cache_limiter('');
    ini_set("session.use_cookies", 0);
    ini_set("session.use_only_cookies", 1);
}

session_start();
$main_id=session_id();
//send cookie
header("Set-Cookie: PHPSESSID={$main_id}; path=/; secure; HttpOnly; SameSite=Strict");
$_SESSION["value"] = "xxx";
session_write_close();
echo "Main session closed now...<br>n";
flush();

session_id("IdOfHiddenSession");
session_start();
$count=$_SESSION['count']++;
session_write_close();
echo "Read data '$count' and closed hidden session again...<br>n";
flush();

session_id($main_id);
session_start();
echo "Main session resumed...<br>n";
flush();
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement