For heavily loaded projects, the use of files to store session files becomes invalid.
In this article, we'll look at the use of the MySql database for storing session data .
- all session settings are made before the start of the session, so you need to cancel the autostart sessions:
ini_set ('session.auto_start', '0');
- As standard, PHP stores sessions in files to define its own session handlers:
ini_set ('session.save_handler', 'user');
'session.save_handler' can have three values:- files is the default value, PHP uses standard session processing functions, sessions are stored in files, it is necessary to define ini_set ('session.save_path', path); space for storing session files;
- mm - PHP uses standard session processing functions, sessions are stored in memory;
- user - allows you to override the standard functions of processing sessions, and accordingly in these functions indicate where we will store the session and how we will process them.
- now define the functions of processing sessions:
session_set_save_handler ( "sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
consider each:- sess_open - opens the session. The function creates a unique session ID. Requires for its work two parameters 'session.save_path' and 'session.name'. Because we store sessions in the database, then we do not need 'session.save_path', but 'session.name' can be defined instead of the standard one - 'PHPSESSID'. So we add to the configuration:
ini_set ('session.name', 'SID');
- sess_close - closes session (without destroying session variables).
- sess_read - reads data from temporary storage, in our case from the database. Requires a session ID, which from the session table must be read and written to the session from the session table.
- sess_write - writes data to temporary storage. Requires session ID, and writes everything from session to database.
- sess_destroy destroys the session. Requires session ID. To delete the information, the following function exists.
- sess_gc is just a garbage collector. Requires a retention period of sessions in temporary storage in seconds specified in the 'session.gc_maxlifetime' parameter (30 minutes by default). Define it, and determine the lifetime of the session cookie:
ini_set ('session.gc_maxlifetime', XXX); ini_set ('session.cookie_lifetime', YYY);
'sess_gc' is not always called when the session is initialized, there is one more setting that controls this parameter - 'session.gc_probability'. This parameter determines the probability of starting 'sess_gc' in percent, respectively, valid values of 1-100. The default value is 1%. Those. this means that with a probability of 1%, when you open a new page of the site, the session table will be cleaned, in my experience the optimal value is 5-10. We add to the configuration:ini_set ('session.gc_probability', 5);
- sess_open - opens the session. The function creates a unique session ID. Requires for its work two parameters 'session.save_path' and 'session.name'. Because we store sessions in the database, then we do not need 'session.save_path', but 'session.name' can be defined instead of the standard one - 'PHPSESSID'. So we add to the configuration:
Table structure:
CREATE TABLE "session" ( session_id character varying (32) NOT NULL, session_user_id integer DEFAULT 0 NOT NULL, session_counter integer DEFAULT 0 NOT NULL, session_ip character varying (16), session_agent character varying (255), session_last integer DEFAULT 0 NOT NULL, session_created integer DEFAULT 0 NOT NULL, session_data text );
CREATE TABLE "user" ( user_id character varying (32) NOT NULL, user_ip character varying (16), user_agent character varying (255), / * there may be other fields * / );
session.php - Storage of session data in the MySQL table and the function of working with sessions in PHP.
A global $ user [] array is used with fields from the database tables session, user.
It is assumed that the connection with MySQL is already installed and defined in the global variable $ db.
The current information is stored in the global variable $ session.
It is assumed that the connection with MySQL is already installed and defined in the global variable $ db.
The current information is stored in the global variable $ session.
<?
$SERVER_NAME=$_SERVER['HTTP_HOST'];
$SERVER_NAME=preg_replace('/^http:\/\//', '', $SERVER_NAME);
$SERVER_NAME=preg_replace('/^www\./', '', $SERVER_NAME);
define("CookiePath","/");
define("CookieDomain",$SERVER_NAME); //".".$SERVER_NAME
define("live_sess_time","1000");
ini_set('session.auto_start', '0');
ini_set('session.use_cookies', '1');
ini_set('session.use_trans_sid', '0');
ini_set('session.save_handler', 'user');
ini_set('session.name', 'SID');
ini_set('session.gc_maxlifetime', '1800');
//ini_set ('session.cookie_lifetime', '2000');
session_set_cookie_params (0, CookiePath, CookieDomain, false);
ini_set('session.gc_probability', 10);
function sess_open ($save_path, $session_name) {return true;}
function sess_close () {return true;}
function sess_read ($session_id) {
global $db, $user, $session;
if (strlen ($session_id) != 32) {
error_log ("sess_read(): Invalid SessionID = ".$session_id);
return '';
}
$sql = "SELECT `session_id`, `session_user_id`, `session_counter`, `session_ip`, `session_agent`, `session_data`
FROM `session`
WHERE `session_id` = '".$db->sql_escape($session_id)."' AND `session_last` > '".(time() - live_sess_time)."'";
$result = $db->sql_query ($sql);
if ($db->sql_numrows ($result) == 1) {
$session = $db->sql_fetchrow ($result);
if ($session AND $session['session_ip'] == $user['user_ip'] AND $session['session_agent'] == $user['user_agent']) {
$sql = "SELECT * FROM `user`
WHERE `user_id` = '".$db->sql_escape($session['session_user_id'])."' LIMIT 1";
$result = $db->sql_query ($sql);
if(!$result) {
$result = $db->sql_error ($result);
error_log ('sess_read(): Failed to read user info - '.$result['message']);
return '';
}
else {
$user_data = $db->sql_fetchrow ($result);
$user = array_merge ($user, $user_data, $session);
unset($user['session_data']);
return $session['session_data'];
}
} else {
if (isset($_REQUEST[session_name()])) sess_destroy($_REQUEST[session_name()]);
return '';
}
} elseif (!$result) {
$result = $db->sql_error ($result);
error_log ('sess_read(): Failed to read sessions - '.$result['message']);
return '';
} else {
$session = NULL;
if (isset($_REQUEST[session_name()])) sess_destroy($_REQUEST[session_name()]);
return '';
}
}
function sess_write ($session_id, $session_data) {
global $db, $user, $session;
if (strlen ($session_id) != 32) {
error_log ('sess_write(): Invalid Session ID = '.$session_id);
return false;
}
if (4294967295 < strlen($session_data)) {
error_log ('sess_write(): Session data too large. '.$session_id.'(max. 4294967295) -> '.strlen($session_data));
if (isset($_REQUEST[session_name()])) sess_destroy($_REQUEST[session_name()]);
return false;
}
if ($session AND $session['session_ip'] != $user['user_ip']){
if (isset($_REQUEST[session_name()])) sess_destroy($_REQUEST[session_name()]);
return false;
}
if ($session) {
$sql = "UPDATE `session`
SET `session_user_id` = '".intval ($session['session_user_id'])."',
`session_last` = '".time ()."',
`session_counter` = '".intval(++$session['session_counter'])."',
`session_data` = '".$db->sql_escape($session_data)."'
WHERE `session_id` = '".$db->sql_escape($session_id)."' LIMIT 1";
} else {
$sql = "INSERT INTO `session` (`session_id`, `session_created`, `session_last`,
`session_ip`, `session_agent`, `session_data`)
VALUES ('".$db->sql_escape ($session_id)."', ".time().", ".time().",
'".$db->sql_escape ($user['user_ip'])."',
'".$db->sql_escape ($user['user_agent'])."',
'".$db->sql_escape ($session_data)."')";
}
$result = $db->sql_query ($sql);
if (!$result) {
$result = $db->sql_error ($result);
error_log ('sess_write(): Failed to INSERT/UPDATE session. '.$result['message']."<br> Query: ".$sql);
return false;
}
return true;
}
function sess_destroy ($session_id) {
global $db;
$sql = "DELETE FROM `session`
WHERE `session_id` = '".$db->sql_escape ($session_id)."'";
$result = $db->sql_query ($sql);
if (!$result) {
$result = $db->sql_error ($result);
error_log ('sess_destory(): Failed to DELETE session. '.$result['message']);
return false;
}
return true;
}
function sess_gc ($sess_gc_maxlifetime) {
global $db;
$sql = "DELETE FROM `session` WHERE `session_last` < '".(time () - $sess_gc_maxlifetime)."'";
$result = $db->sql_query ($sql);
if (!$result) {
$result = $db->sql_error ($result);
error_log ('sess_gc(): Failed to DELETE old sessions.'.$result['message']);
return false;
}
$sql = "OPTIMIZE TABLE `session` ";
$result = $db->sql_query ($sql);
if (!$result) {
$result = $db->sql_error ($result);
error_log ('sess_gc(): Failed to OPTIMIZE sessionstable.'.$result['message']);
return false;
}
return true;
}
session_set_save_handler ("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
register_shutdown_function ('session_write_close');
session_start ();
?>
At the same time in the database there are only entries about those sessions that are now active, expired sessions are deleted, changing the value of 'session.gc_probability' you can find the one that fits your website. Thus, adjust the size of the table of sessions.
0 comments:
Post a Comment