diff --git a/ChangeLog b/ChangeLog index 00962b10419..f6fe916c13b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -133,7 +133,7 @@ NEW: printFieldListFrom hook call on several lists NEW: Use lang selector when using a field key 'lang' in modulebuilder NEW: we need to be able to put more filters on deleteByParentField() function NEW: make it easier to set the `keyword`, `keywords` and `description` attributes of an ecm file object - +NEW: Experimental feature to manage user sessions in database Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example index 7bb58d6b701..6bf2873b50c 100644 --- a/htdocs/conf/conf.php.example +++ b/htdocs/conf/conf.php.example @@ -282,18 +282,21 @@ $dolibarr_nocsrfcheck='0'; // If set to 1, you will be able to define some command line in the internale Job scheduler module. // Default value: '0' // Examples: '1' +// $dolibarr_cron_allow_cli='0'; // dolibarr_mailing_limit_sendbyweb -// Can set a limit for mailing send by web. This overwrite database value. Can be used to restrict on OS level. +// Can set a limit for mailing send by web. This overwrite database value. Can be used to restrict on system level. // Default value: '25' // Examples: '-1' (sending by web is forbidden) +// // $dolibarr_mailing_limit_sendbyweb='25'; // dolibarr_mailing_limit_sendbycli -// Can set a limit for mailing send by cli. This overwrite database value. Can be used to restrict on OS level. +// Can set a limit for mailing send by cli. This overwrite database value. Can be used to restrict on system level. // Default value: '0' (no hard limit, use soft database value if exists) // Examples: '-1' (sending by cli is forbidden) +// // $dolibarr_mailing_limit_sendbycli='0'; // MAIN_ANTIVIRUS_COMMAND (as a constant) @@ -308,6 +311,17 @@ $dolibarr_cron_allow_cli='0'; // Example: '--fdpass'; // define('MAIN_ANTIVIRUS_PARAM', '--fdpass'); +// php_session_save_handler +// Try to use the Dolibarr internal session handler that uses a database instead of the PHP handler (experimental). +// If you enable this feature to 'db', you may also want to enable the following constants: +// $dolibarr_session_db_type, $dolibarr_session_db_host, $dolibarr_session_db_user, $dolibarr_session_db_pass +// $dolibarr_session_db_pass, $dolibarr_session_db_name, $dolibarr_session_db_type = $dolibarr_main_db_port +// Default value: '' +// Example: 'db'; +// +// $php_session_save_handler=''; + + //################## // Other diff --git a/htdocs/core/lib/phpsessionindb.lib.php b/htdocs/core/lib/phpsessionindb.lib.php index 132036ba23d..71711eb6ba6 100644 --- a/htdocs/core/lib/phpsessionindb.lib.php +++ b/htdocs/core/lib/phpsessionindb.lib.php @@ -29,15 +29,29 @@ /** * The session open handler called by PHP whenever a session is initialized. * - * @param string $database_name Database NamedConstraint - * @param string $table_name Table name + * @param string $save_path Value of session.save_path into php.ini + * @param string $session_name Session name (Example: 'DOLSESSID_xxxxxx') * @return boolean Always true */ -function dolSessionOpen($database_name, $table_name) +function dolSessionOpen($save_path, $session_name) { - global $conf, $dbsession; + global $dbsession; - $dbsession = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, $conf->db->port); + global $dolibarr_main_db_type, $dolibarr_main_db_host; + global $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name, $dolibarr_main_db_port; + + global $dolibarr_session_db_type, $dolibarr_session_db_host; + global $dolibarr_session_db_user, $dolibarr_session_db_pass, $dolibarr_session_db_name, $dolibarr_session_db_port; + + if (empty($dolibarr_session_db_type)) { $dolibarr_session_db_type = $dolibarr_main_db_type; } + if (empty($dolibarr_session_db_host)) { $dolibarr_session_db_host = $dolibarr_main_db_host; } + if (empty($dolibarr_session_db_user)) { $dolibarr_session_db_user = $dolibarr_main_db_user; } + if (empty($dolibarr_session_db_pass)) { $dolibarr_session_db_pass = $dolibarr_main_db_pass; } + if (empty($dolibarr_session_db_name)) { $dolibarr_session_db_name = $dolibarr_main_db_name; } + if (empty($dolibarr_session_db_port)) { $dolibarr_session_db_port = $dolibarr_main_db_port; } + //var_dump('open '.$database_name.' '.$table_name); + + $dbsession = getDoliDBInstance($dolibarr_session_db_type, $dolibarr_session_db_host, $dolibarr_session_db_user, $dolibarr_session_db_pass, $dolibarr_session_db_name, $dolibarr_session_db_port); return true; } @@ -51,8 +65,10 @@ function dolSessionOpen($database_name, $table_name) function dolSessionRead($sess_id) { global $dbsession; + global $sessionlastvalueread; + global $sessionidfound; - $sql = "SELECT session_variable FROM ".MAIN_DB_PREFIX."session"; + $sql = "SELECT session_id, session_variable FROM ".MAIN_DB_PREFIX."session"; $sql .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; // Execute the query @@ -60,10 +76,16 @@ function dolSessionRead($sess_id) $num_rows = $dbsession->num_rows($resql); if ($num_rows == 0) { // No session found - return an empty string + $sessionlastvalueread = ''; + $sessionidfound = ''; return ''; } else { // Found a session - return the serialized string $obj = $dbsession->fetch_object($resql); + $sessionlastvalueread = $obj->session_variable; + $sessionidfound = $obj->session_id; + //var_dump($sessionlastvalueread); + //var_dump($sessionidfound); return $obj->session_variable; } } @@ -79,42 +101,84 @@ function dolSessionRead($sess_id) function dolSessionWrite($sess_id, $val) { global $dbsession; + global $sessionlastvalueread; + global $sessionidfound; - $time_stamp = dol_now(); + /*var_dump('write '.$sess_id); + var_dump($val); + var_dump('sessionlastvalueread='.$sessionlastvalueread.' sessionidfound='.$sessionidfound); + */ - $sql = "SELECT session_id FROM ".MAIN_DB_PREFIX."session"; - $sql .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; + //$sessionlastvalueread=''; + if ($sessionlastvalueread != $val) { + $time_stamp = dol_now(); - // Execute the query - $resql = $dbsession->query($sql); - $num_rows = $dbsession->num_rows($resql); - if ($num_rows == 0) { - // No session found, insert a new one - $insert_query = "INSERT INTO ".MAIN_DB_PREFIX."session"; - $insert_query .= "(session_id, session_variable, last_accessed)"; - $insert_query .= " VALUES ('".$dbsession->escape($sess_id)."', '".$dbsession->escape($val)."', '".$dbsession->idate($time_stamp)."')"; - $dbsession->query($insert_query); - } else { - // Existing session found - Update the session variables - $update_query = "UPDATE ".MAIN_DB_PREFIX."session"; - $update_query .= "SET session_variable = '".$dbsession->escape($val)."',"; - $update_query .= " last_accessed = '".$dbsession->idate($time_stamp)."'"; - $update_query .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; - $dbsession->query($update_query); + if (empty($sessionidfound)) { + // No session found, insert a new one + $insert_query = "INSERT INTO ".MAIN_DB_PREFIX."session"; + $insert_query .= "(session_id, session_variable, last_accessed, fk_user, remote_ip, user_agent)"; + $insert_query .= " VALUES ('".$dbsession->escape($sess_id)."', '".$dbsession->escape($val)."', '".$dbsession->idate($time_stamp)."', 0, '".$dbsession->escape(getUserRemoteIP())."', '".$dbsession->escape($_SERVER['HTTP_USER_AGENT'])."')"; + + $result = $dbsession->query($insert_query); + if (!$result) { + dol_print_error($dbsession); + return false; + } + } else { + if ($sessionidfound != $sess_id) { + // oops. How can this happen ? + dol_print_error($dbsession, 'Oops sess_id received in dolSessionWrite differs from the cache value $sessionidfound. How can this happen ?'); + return false; + } + /*$sql = "SELECT session_id, session_variable FROM ".MAIN_DB_PREFIX."session"; + $sql .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; + + // Execute the query + $resql = $dbsession->query($sql); + $num_rows = $dbsession->num_rows($resql); + if ($num_rows == 0) { + // No session found, insert a new one + $insert_query = "INSERT INTO ".MAIN_DB_PREFIX."session"; + $insert_query .= "(session_id, session_variable, last_accessed, fk_user, remote_ip, user_agent)"; + $insert_query .= " VALUES ('".$dbsession->escape($sess_id)."', '".$dbsession->escape($val)."', '".$dbsession->idate($time_stamp)."', 0, '".$dbsession->escape(getUserRemoteIP())."', '".$dbsession->escape($_SERVER['HTTP_USER_AGENT'])."')"; + var_dump($insert_query); + $result = $dbsession->query($insert_query); + if (!$result) { + dol_print_error($dbsession); + return false; + } + } else { + */ + // Existing session found - Update the session variables + $update_query = "UPDATE ".MAIN_DB_PREFIX."session"; + $update_query .= " SET session_variable = '".$dbsession->escape($val)."',"; + $update_query .= " last_accessed = '".$dbsession->idate($time_stamp)."',"; + $update_query .= " remote_ip = '".$dbsession->escape(getUserRemoteIP())."',"; + $update_query .= " user_agent = '".$dbsession->escape($_SERVER['HTTP_USER_AGENT'])."'"; + $update_query .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; + + $result = $dbsession->query($update_query); + if (!$result) { + dol_print_error($dbsession); + return false; + } + } } + return true; } /** * This function is executed on shutdown of the session. * - * @param string $sess_id Session ID * @return boolean Always returns true. */ -function dolSessionClose($sess_id) +function dolSessionClose() { global $dbsession; + //var_dump('close'); + $dbsession->close(); return true; @@ -130,6 +194,8 @@ function dolSessionDestroy($sess_id) { global $dbsession; + //var_dump('destroy'); + $delete_query = "DELETE FROM ".MAIN_DB_PREFIX."session"; $delete_query .= " WHERE session_id = '".$dbsession->escape($sess_id)."'"; $dbsession->query($delete_query); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index a15b17b8566..a1bc165ee49 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -272,10 +272,10 @@ if (!empty($_POST["DOL_AUTOSET_COOKIE"])) { } } - // Set the handler of session -if (ini_get('session.save_handler') == 'user') { - require_once 'core/lib/phpsessionindb.lib.php'; +// if (ini_get('session.save_handler') == 'user') +if ($php_session_save_handler == 'db') { + require_once 'core/lib/phpsessionin'.$php_session_save_handler.'.lib.php'; } // Init session. Name of session is specific to Dolibarr instance. @@ -294,7 +294,8 @@ if (!empty($_COOKIE[$sessiontimeout])) { if (!defined('NOSESSION')) { session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie (same as setting session.cookie_httponly into php.ini). Must be called before the session_start. session_name($sessionname); - session_start(); + session_start(); // This call the open and read of session handler + //exit; // this exist generates a call to write and close } diff --git a/htdocs/master.inc.php b/htdocs/master.inc.php index e04adb4ee86..7a92402224b 100644 --- a/htdocs/master.inc.php +++ b/htdocs/master.inc.php @@ -161,9 +161,10 @@ if (!defined('NOREQUIREDB')) { } // Now database connexion is known, so we can forget password -//unset($dolibarr_main_db_pass); // We comment this because this constant is used in a lot of pages +//unset($dolibarr_main_db_pass); // We comment this because this constant is used in some other pages unset($conf->db->pass); // This is to avoid password to be shown in memory/swap dump + /* * Object $user */ @@ -171,9 +172,9 @@ if (!defined('NOREQUIREUSER')) { $user = new User($db); } + /* * Load object $conf - * After this, all parameters conf->global->CONSTANTS are loaded */ // By default conf->entity is 1, but we change this if we ask another value. @@ -190,15 +191,12 @@ if (session_id() && !empty($_SESSION["dol_entity"])) { // For public page with MultiCompany module $conf->entity = constant('DOLENTITY'); } - // Sanitize entity if (!is_numeric($conf->entity)) { $conf->entity = 1; } - -//print "We work with data into entity instance number '".$conf->entity."'"; - // Here we read database (llx_const table) and define $conf->global->XXX var. +//print "We work with data into entity instance number '".$conf->entity."'"; $conf->setValues($db); // Create object $mysoc (A thirdparty object that contains properties of companies managed by Dolibarr.