I'm using several technologies for a web application:
nodejs for socket.io and request
nginx / PHP
server sent event
session store in a mongodb collection.
- node/socketio/request: acts as a middleware, in place of the "old" ajax way. adding "set-cookie" in the posted header makes things work really fast, keeping session data across navigation.
- Sessions are stored in a mongodb base, using a session_save_handler.
- A server sent event connection is made, and here is the strange behavior:
if I don't put 'session_write_close' in top of the called file of sse, then session is lost on page refresh.
If I put it, ok seems fine, but I can't monitor any changes of the session object, which does not vary, even on user login/logout.
Here is my session Class file:
class Session {
protected $dbSession;
protected $maxTime;
public function __construct() {
$this->conn = new Mongo('mongodb://user:passwd@hostip');
$sitebase_app = 'base_for_coll';
$this->dbSession = $this->conn->$sitebase_app->session;
$this->maxTime = get_cfg_var("session.gc_maxlifetime");
register_shutdown_function('session_write_close');
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
}
public function open() { return true; }
public function close() { return true; }
public function read($id) {
$doc = $this->dbSession->findOne(array("_id" => $id), array("sessionData" => 1));
return $doc['sessionData'];
}
public function write($id,$data) {
//
$this->dbSession->save(array("_id" => $id, "sessionData" => $data, "timeStamp" => time()));
return true;
}
public function destroy($id) {
$this->dbSession->remove(array("_id" => $id));
return true;
}
public function gc() {
$agedTime = time() - $this->maxTime;
$this->dbSession->remove(array("timeStamp" => array('$lt' => $agedTime)));
}
}
ini_set('session.save_handler' , 'user');
$session = new Session();
And voila my SSE php file:
include_once($_SERVER['CONF_INC']);
$APP = new App();
$APPCACHE = $APP->plug('sitebase_sockets','data_activity');
$APPCACHE->ensureIndex(['timeData_activity'=>1]);
$APPCACHE->ensureIndex(['codeData_activity'=>1]);
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Content-Encoding: none;');
session_write_close();
flush();
ob_end_flush();
//
$time = time();
$lastmodif = filemtime(ACTIVEMODULEFILE);
function sendMsg($id , $msg) {
ini_set('implicit_flush', true);
ob_implicit_flush(true);
$sessid = session_id();
echo "id: ".uniqid() . PHP_EOL;
echo "event: $id" . PHP_EOL;
echo "data: {\n";
echo "data: \"msg\": $msg \n";
echo "data: }\n";
echo PHP_EOL;
ob_flush();
flush();
}
$notify = 1;
$startedAt = time();
do {
$TEST = $APPCACHE->find(['timeData_activity'=>['$gte'=>$startedAt]]);
if($TEST->count()!=0){
// event : act_upd_data
// data : json
$startedAt = time();
while($ARR = $TEST->getNext()){
unset($ARR['_id']);
$json = json_encode($ARR,JSON_FORCE_OBJECT);
sendMsg($ARR['eventData_activity'] ,$json);
}
sleep(1);
}
if ((time() - $startedAt) > 360) {
skelMdl::send_cmd('act_notify',['options'=>['sticky'=>'true']]+ array('msg'=>'DIE FOR PERIODIC TEST RELOAD'.session_id()),session_id());
die();
}
usleep(250000); // 1/4 seconde
ob_flush();
flush();
if(empty($_SESSION['idagent'])){
$notify = 0;
skelMdl::send_cmd('act_notify', array('msg'=>' Session agent empty'.session_id()),session_id());
sleep(5);
}
} while(true);
And the start of my conf.inc.php file
header('Content-Type: text/html; charset=UTF-8');
//
ini_set('display_errors', 55);
// THE SESSION_HANDLER
include_once('appclasses/ClassSession.php');
//
if ( session_status() == PHP_SESSION_NONE ) {
session_start();
}
I cannot find any more ideas, any advice would be appreciated. Thanks
p.s.: socket.io instead of nature websocket, because of rooms and namespace... But of course, I would prefer using native websocket, avoiding the use of a middleware...