0
I am using an Handler for php session in which you save the session data in Mongodb. However, while reloading the page at short intervals, it throws an error: "Failed to write Session data (user)" and recommends checking the "Session.save_path" setting. This error also occurs after using "header('Location: page-any.php')". Although this error does not prejudge current data in the global "$_SESSION" prevent new data from being entered in the database (or updated). As I use sessions to save tokens used in the validation of forms and some requests this disturbs... I searched references to this error, unsuccessful since the php manual only refers to this error in handling record sessions on disk on the server which is not my case as I am saving for Mongodb.
In "php.ini" "Session.save_habdler" and "Session.save_path" omitted (commented).
Mongodb version: 3.0.12
PHP version: 7.0.8
Version of mongodb extension: 1.1.8
Thanks in advance for references, content for reading or exclamations.
Mongocrud.php
// define default content and charset (text/html and UTF-8)
header("Content-type: text/html; charset=UTF-8");
/**
* More info in:
* http://docs.php.net/set.mongodb
* http://mongodb.github.io/mongo-php-driver
*/
class MongoCRUD
{
// defaults
private $url = '127.0.0.1';
private $port = '27017';
private $base = 'local';
private $errors;
/**
* Private function for display errors (matchs in tray|catch blocks)
*
* Private variable "errors" define if this function retur errors (defaut - development)
*/
private function __ERRORSTRYCATCH__($e)
{
// check status code
if($this->errors == true){
$filename = basename(__FILE__);
echo "<br><br>Exception: " . $e->getMessage() . "<br>";
echo "In File: " . $e->getFile() . "<br>";
echo "In Line: " . $e->getLine() . "<br>";
}
}
private function wc()
{
// Construct a write concern
return new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY,100);
}
private function rp()
{
// Construct a read preference
return new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY_PREFERRED,[]);
}
private function open()
{
return new MongoDB\Driver\Manager("mongodb://" . $this->url . ":" . $this->port . "/" . $this->base);
}
private function bulk()
{
return new MongoDB\Driver\BulkWrite;
}
private function query($filter = false)
{
if($filter){
return new MongoDB\Driver\Query($filter);
}else{
return new MongoDB\Driver\Query([]);
}
}
/**
* $database {string} set database for operation
* $options {array} set options.
*/
function __construct($database = false, $options = false)
{
// set default variables
$this->errors = $options['err'] ?? true;
// check if have database
if(!$database){
return false;
}else{
// define data base
$this->base = $database;
}
}
public function create($collection, $document)
{
// open manager
$manager = self::open();
// open bulk
$bulk = self::bulk(['ordered' => true]);
// bulk insert
$bulk->insert($document);
//
try{
// grab result
$result = $manager->executeBulkWrite($this->base . '.' . $collection, $bulk, self::wc());
// check
if($result->getInsertedCount() === 1){
return true;
}else{
return false;
}
}catch(MongoDB\Driver\Exception\Exception $e){
// shutdown error
self::__ERRORSTRYCATCH__($e);
return false;
}
}
public function reader($collection, $document = false, $filter = false)
{
// define document
$document = $document ? $document : [];
// define query
$query = self::query($filter) ?? self::query();
// open manager
$manager = self::open();
//
try{
// cursor
$cursor = $manager->executeQuery($this->base . '.' . $collection, $query, self::rp());
// store
$multiples = [];
// loop
foreach($cursor as $document){
array_push($multiples, $document);
}
// check if have result
if(count($multiples) == 0){
return false;
}else{
return $multiples;
}
}catch(MongoDB\Driver\Exception\Exception $e){
// shutdown error
self::__ERRORSTRYCATCH__($e);
return false;
}
}
public function update($collection, $filter, $newObj, $options = false)
{
// define options
if($options != false && is_array($options)){
$options = array_merge(["multi" => false, "upsert" => false], $options);
}else{
$options = ["multi" => false, "upsert" => false];
}
// open manager
$manager = self::open();
// open bulk
$bulk = self::bulk();
// bulk update
$bulk->update($filter, $newObj, $options);
//
try{
// grab result
$result = $manager->executeBulkWrite($this->base . '.' . $collection, $bulk, self::wc());
// check
if($result->getModifiedCount() >= 1){
return true;
}else{
return false;
}
}catch(Exception $e){
// shutdown error
self::__ERRORSTRYCATCH__($e);
return false;
}
}
public function delete($collection, $filter, $limit = false)
{
/**
* WARNING! $limit zero "0" delete all matches in collection! RISK ATENTION HERE!
* Default param is 0...
*/
$limit = (is_bool($limit) && $limit == true) ? ["limit" => 1] : ["limit" => 0];
// open manager
$manager = self::open();
// open bulk
$bulk = self::bulk();
// bulk delete
$bulk->delete($filter, $limit);
//
try{
// grab result
$result = $manager->executeBulkWrite($this->base . '.' . $collection, $bulk, self::wc());
// check
if($result->getDeletedCount() >= 1){
return true;
}else{
return false;
}
}catch(MongoDB\Driver\Exception\Exception $e){
// shutdown error
self::__ERRORSTRYCATCH__($e);
return false;
}
}
}
Mongohandlersession.php
class HandlerSessionManager
{
private $dbCollection;
private $dbSession;
private $expire;
private $token;
private $clean;
public function __construct($options = false) {
// define name of colection (set session_name() or default session_name())
$this->dbCollection = $options['collection'] ?? session_name();
// define database for connection in MongoDB (if no have.. create.)
$this->dbSession = new MongoCRUD( ( $options[ 'databasename' ] ?? 'SessionManager' ) );
// define expiration time session (get default or choose (options or default 1 hour))
$this->expire = get_cfg_var( "session.gc_maxlifetime" ) ?? ( $options['expire'] ?? 3600 );
// define token (for request session values in another fonts e.g: in nodejs)
$this->token = $options[ 'token' ] ?? false;
// define if use auto_garbage function for clean old sessions (default false)
$this->clean = $options[ 'force_garbage' ] ? true : false;
// define name of session
session_name($this->dbCollection);
// set save handler
session_set_save_handler(
[ $this, 'open' ],
[ $this, 'close' ],
[ $this, 'read' ],
[ $this, 'write' ],
[ $this, 'destroy' ],
[ $this, 'gc' ]
);
// check if session already started
if(!isset($_SESSION)){
session_start();
}
// shutdown
@register_shutdown_function('session_write_close');
// auto call
self::auto_garbage();
}
public function open()
{
if($this->dbSession){
return true;
}else{
return false;
}
}
public function close()
{
$this->dbSession = null;
return true;
}
public function read($id)
{
$doc = $this->dbSession->reader( $this->dbCollection, ["_id" => $id] );
if(is_array($doc)){
return $doc[0]->sessionData;
}else{
return "";
}
}
public function write($id, $data)
{
$create = $this->dbSession->update( $this->dbCollection, ["_id" => $id], ['$set' => ["_id" => $id, "token" => $this->token, "sessionData" => $data, "expire" => ( time() + $this->expire )] ], ["upsert" => true] );
return $create;
}
public function destroy($id)
{
$result = $this->dbSession->delete( $this->dbCollection, ["_id" => $id] );
return $result;
}
public function gc()
{
$result = $this->dbSession->delete( $this->dbCollection, false, ["expire" => ['$lt' => time()]] );
return $result;
}
public function auto_garbage()
{
if($this->clean){
$this->dbSession->delete( $this->dbCollection, ["expire" => ['$lt' => time()]] );
}
}
public function __destruct()
{
@session_write_close();
}
}
index php.
require 'mongodb_/MongoCRUD.php';
require 'mongodb_/MongoHandlerSession.php';
$options = [
'databasename' => 'SessionManager',
'collection' => 'PHPSESSID',
'expire' => 1440, // it's don't is majority set. It is optional case php.ini no have value set
'token' => false, // 'YOUR_SUPER_ENCRYPTED_TOKEN'
'force_garbage' => true
];
// init class
new HandlerSessionManager($options);
// Usage
$_SESSION['foo'] = 'bar';
You can post the save Handler you are using ?
– gmsantos
posted Handler and crud
– Lauro Moraes