unsetting a $_SESSION variable after echoing it alters the view

564 Views Asked by At

I'm using the $_SESSION to store messages to display to the user.

$_SESSION['message']['error']=" an error appear",
$_SESSION['message']['warning']="not good !"

my HTML page is generated by including some HTML views and and generating variables.

This is done between ob_start and ob_get_clean()

Then i'm echoing the result to the user.

After that i unset $_SESSION['message'] to left a clean situation for the next pages.

it seems that the unsetting is parallelised with the ob_start()

When i comment the unset, i've got the right messages displayed. But when I uncomment it the messages are displayed empty.

I've tried to unset the $_SESSION['message'] at different position in my code. I have tried setting it to an empty array.

It seems that the PHP core is doing some optimisation and interpreting my code in an inappropriate order.

It Looks kinda like this:

ob_start();

$ctrl = new $classeControleur();
$ctrl->$action();

$contenu = ob_get_clean();

include CHEMIN_VUE.'header.view.php';

require('aside.php');
echo '<div id="portail_application_centre">';
echo $contenu;
echo '<div>';

// HTML END

unset($_SESSION['message']);
2

There are 2 best solutions below

2
Kuba Paczyński On

Please remember that sessions in PHP are blocking and only one process can access given session file at a time - any other process trying to access the same session will sit and wait for its turn. Once you open session and it will block forever until you either close it or program finish by itself and exit.

$_SESSION superglobal holds key/value pairs that belong to last open session, but this variable is not session itself. It allows you to modify open session and it remembers data from previously opened session, nothing more.

You have to start session manually (unless configured otherwise in php.ini - don't do it) before you can write to it. What you need to do is to open session, make changes, then close it right away. You can reopen it later if needed.

Always close session as soon as you are done writing to it, so other process can access it and save their changes. If you leave it open no one will be able to save any changes.

Here I made a little example how to access session data couple times during one run of the script.

<?php

// we check if session is already open or not
// in another included file for example
if (!session_id()) {
  // now we create new session if it doesn't exists
  // or reopen and continue previous one
  session_start();
}

// session is now open so we can we can save a value inside
$_SESSION['last_seen'] = time();

// we can also remove existing values
unset($_SESSION['user_favourite_color']);

// we can read saved values if they exists
if (isset($_SESSION['username'])) {
  echo 'Hello '. $_SESSION['username'] .'!'. PHP_EOL;
  echo 'Yes I REMEMBER YOU!' . PHP_EOL;
} else {
  echo 'I DONT KNOW YOU! I see you for the first time.'. PHP_EOL;
  $_SESSION['username'] = 'Mr USERNAME';
  echo 'Now I noted your name, I will remember you.'. PHP_EOL;
}

// now we close session to not block it any longer
// maybe some other process is waiting to use it
session_write_close();

// here you do some other stuff
// lets sleep for example
sleep(2);

// you can reopen the same session
// but remember something might have changed
// since you had it open last time (before sleep)
// like maybe in different browser tab, just keep that in mind
session_start();
$_SESSION['visit'] += 1;
unset($_SESSION['something']);

// and we should close it again to make sure our changes are saved
session_write_close();

Let me know if that's any help.

0
procrasteBZH On

We found the solution with a senior DEV at the office.

Some more explanations:

I use MVC with a frontend controller.The code i presented is a portion of the frontend controller.

We get $action from $_GET['action'] and $ctrl from $_GET['ctrl']. Then we execute the method action() from the controller ctrl(). The method does some logic and update $_SESSION['message'] if i need to inform the user. Then,$_SESSION['message'] is stored in $message and subsequently there's a echo $message; in the appropriate VIEW. finally the buffer is flushed to $contenu which is send to the user by the echo $contenu; line. Then i thought it was secure to unset the $_SESSION['message'] because it has already been send. But surpisingly, it is empty. It is not if i comment the unset line but then i sent unsolicited message to the user throughout the other pages of the program ...

I also use the Post-Redirect-Get Pattern in the action() method with a redirection to the same page (to avoid to submit twice the data ) . The problem lies there ! I redirect via a header('location'). I thought the header() ended the script immediatly but in fact (because of the buffering !!) it continues to the end and then php send the headers ...

I put a die() after the header('location') and after that everything went fine.

I've learned something new / That's nice !