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();