2003-11-18 19:44:36 +00:00
< ? php
2003-12-13 13:00:47 +00:00
// $Id$
2003-11-18 19:44:36 +00:00
2004-08-21 06:42:38 +00:00
/**
* @ file
* User session handling functions .
2008-09-08 21:08:24 +00:00
*
* The user - level session storage handlers :
* - _sess_open ()
* - _sess_close ()
* - _sess_read ()
* - _sess_write ()
2008-09-27 20:37:01 +00:00
* - _sess_destroy_sid ()
* - _sess_gc ()
2008-09-15 20:48:10 +00:00
* are assigned by session_set_save_handler () in bootstrap . inc and are called
* automatically by PHP . These functions should not be called directly . Session
2008-09-08 21:08:24 +00:00
* data should instead be accessed via the $_SESSION superglobal .
2004-08-21 06:42:38 +00:00
*/
2008-09-08 21:08:24 +00:00
/**
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
* This function is used to handle any initialization , such as file paths or
* database connections , that is needed before accessing session data . Drupal
2008-09-08 21:08:24 +00:00
* does not need to initialize anything in this function .
*
* This function should not be called directly .
*
* @ return
* This function will always return TRUE .
2008-09-15 20:48:10 +00:00
*/
2008-09-08 21:08:24 +00:00
function _sess_open () {
2006-02-10 05:42:11 +00:00
return TRUE ;
2003-11-18 19:44:36 +00:00
}
2008-09-08 21:08:24 +00:00
/**
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
* This function is used to close the current session . Because Drupal stores
* session data in the database immediately on write , this function does
2008-09-08 21:08:24 +00:00
* not need to do anything .
*
* This function should not be called directly .
*
* @ return
* This function will always return TRUE .
2008-09-15 20:48:10 +00:00
*/
2008-09-08 21:08:24 +00:00
function _sess_close () {
2006-02-10 05:42:11 +00:00
return TRUE ;
2003-11-18 19:44:36 +00:00
}
2008-09-08 21:08:24 +00:00
/**
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
* This function will be called by PHP to retrieve the current user ' s
* session data , which is stored in the database . It also loads the
2008-09-08 21:08:24 +00:00
* current user ' s appropriate roles into the user object .
*
2008-09-15 20:48:10 +00:00
* This function should not be called directly . Session data should
2008-09-08 21:08:24 +00:00
* instead be accessed via the $_SESSION superglobal .
*
* @ param $key
2008-09-27 20:37:01 +00:00
* Session ID .
2008-09-08 21:08:24 +00:00
* @ return
2008-09-15 20:48:10 +00:00
* Either an array of the session data , or an empty string , if no data
2008-09-08 21:08:24 +00:00
* was found or the user is anonymous .
2008-09-15 15:18:59 +00:00
*/
2008-09-08 21:08:24 +00:00
function _sess_read ( $key ) {
2003-11-18 19:44:36 +00:00
global $user ;
2005-03-01 20:15:10 +00:00
2008-09-15 20:48:10 +00:00
// Write and Close handlers are called after destructing objects
2008-09-08 21:08:24 +00:00
// since PHP 5.0.5.
2006-11-11 22:41:20 +00:00
// Thus destructors can use sessions but session handler can't use objects.
// So we are moving session closure before destructing objects.
register_shutdown_function ( 'session_write_close' );
2008-09-08 21:08:24 +00:00
// Handle the case of first time visitors and clients that don't store
// cookies (eg. web crawlers).
2006-08-16 13:13:34 +00:00
if ( ! isset ( $_COOKIE [ session_name ()])) {
$user = drupal_anonymous_user ();
return '' ;
2006-02-10 05:42:11 +00:00
}
2003-11-18 23:37:48 +00:00
2008-09-15 20:48:10 +00:00
// Otherwise, if the session is still active, we have a record of the
2008-09-08 21:08:24 +00:00
// client's session in the database.
2009-02-26 07:30:29 +00:00
$user = db_query ( " SELECT u.*, s.* FROM { users} u INNER JOIN { sessions} s ON u.uid = s.uid WHERE s.sid = :sid " , array ( ':sid' => $key )) -> fetchObject ();
2004-05-10 20:34:25 +00:00
2008-09-27 20:37:01 +00:00
// We found the client's session record and they are an authenticated user.
2006-08-21 06:25:49 +00:00
if ( $user && $user -> uid > 0 ) {
2008-09-27 20:37:01 +00:00
// This is done to unserialize the data member of $user.
2006-08-16 13:13:34 +00:00
$user = drupal_unpack ( $user );
2006-02-10 05:42:11 +00:00
2008-09-27 20:37:01 +00:00
// Add roles element to $user.
2006-08-16 13:13:34 +00:00
$user -> roles = array ();
$user -> roles [ DRUPAL_AUTHENTICATED_RID ] = 'authenticated user' ;
2009-02-26 07:30:29 +00:00
$user -> roles += db_query ( " SELECT r.rid, r.name FROM { role} r INNER JOIN { users_roles} ur ON ur.rid = r.rid WHERE ur.uid = :uid " , array ( ':uid' => $user -> uid )) -> fetchAllKeyed ( 0 , 1 );
2006-01-21 08:28:55 +00:00
}
2008-09-15 20:48:10 +00:00
// We didn't find the client's record (session has expired), or they
2008-09-08 21:08:24 +00:00
// are an anonymous user.
2007-12-22 23:24:26 +00:00
else {
2006-11-07 06:18:35 +00:00
$session = isset ( $user -> session ) ? $user -> session : '' ;
$user = drupal_anonymous_user ( $session );
2006-01-21 08:28:55 +00:00
}
2003-11-18 19:44:36 +00:00
2006-08-16 13:13:34 +00:00
return $user -> session ;
2003-11-18 19:44:36 +00:00
}
2008-09-08 21:08:24 +00:00
/**
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
* This function will be called by PHP to store the current user ' s
2008-09-08 21:08:24 +00:00
* session , which Drupal saves to the database .
*
2008-09-15 20:48:10 +00:00
* This function should not be called directly . Session data should
2008-09-08 21:08:24 +00:00
* instead be accessed via the $_SESSION superglobal .
*
* @ param $key
2008-09-27 20:37:01 +00:00
* Session ID .
2008-09-08 21:08:24 +00:00
* @ param $value
* Serialized array of the session data .
* @ return
* This function will always return TRUE .
2008-09-15 15:18:59 +00:00
*/
2008-09-08 21:08:24 +00:00
function _sess_write ( $key , $value ) {
2003-11-18 19:44:36 +00:00
global $user ;
2009-01-19 10:46:52 +00:00
// If saving of session data is disabled, or if a new empty anonymous session
// has been started, do nothing. This keeps anonymous users, including
// crawlers, out of the session table, unless they actually have something
// stored in $_SESSION.
2009-06-02 06:58:17 +00:00
if ( ! drupal_save_session () || empty ( $user ) || ( empty ( $user -> uid ) && empty ( $_COOKIE [ session_name ()]) && empty ( $value ))) {
2006-08-16 13:13:34 +00:00
return TRUE ;
}
2008-11-01 21:27:38 +00:00
db_merge ( 'sessions' )
-> key ( array ( 'sid' => $key ))
-> fields ( array (
'uid' => $user -> uid ,
'cache' => isset ( $user -> cache ) ? $user -> cache : 0 ,
'hostname' => ip_address (),
'session' => $value ,
'timestamp' => REQUEST_TIME ,
))
-> execute ();
2008-08-21 19:36:39 +00:00
2008-11-01 21:27:38 +00:00
// Last access time is updated no more frequently than once every 180 seconds.
// This reduces contention in the users table.
if ( $user -> uid && REQUEST_TIME - $user -> access > variable_get ( 'session_write_interval' , 180 )) {
2009-02-26 07:30:29 +00:00
db_update ( 'users' )
2008-11-01 21:27:38 +00:00
-> fields ( array (
'access' => REQUEST_TIME
))
-> condition ( 'uid' , $user -> uid )
-> execute ();
2008-07-11 10:14:27 +00:00
}
2006-02-10 05:42:11 +00:00
return TRUE ;
2003-11-18 19:44:36 +00:00
}
2009-01-19 10:46:52 +00:00
/**
2009-06-02 06:58:17 +00:00
* Initialize the session handler , starting a session if needed .
2009-01-19 10:46:52 +00:00
*/
2009-06-02 06:58:17 +00:00
function drupal_session_initialize () {
global $user ;
session_set_save_handler ( '_sess_open' , '_sess_close' , '_sess_read' , '_sess_write' , '_sess_destroy_sid' , '_sess_gc' );
if ( isset ( $_COOKIE [ session_name ()])) {
// If a session cookie exists, initialize the session. Otherwise the
// session is only started on demand in drupal_session_commit(), making
// anonymous users not use a session cookie unless something is stored in
// $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
drupal_session_start ();
if ( ! empty ( $user -> uid ) || ! empty ( $_SESSION )) {
drupal_page_is_cacheable ( FALSE );
}
}
else {
// Set a session identifier for this request. This is necessary because
// we lazyly start sessions at the end of this request, and some
// processes (like drupal_get_token()) needs to know the future
// session ID in advance.
$user = drupal_anonymous_user ();
session_id ( md5 ( uniqid ( '' , TRUE )));
2009-01-19 10:46:52 +00:00
}
}
/**
2009-06-02 06:58:17 +00:00
* Forcefully start a session , preserving already set session data .
2009-01-19 10:46:52 +00:00
*/
2009-06-02 06:58:17 +00:00
function drupal_session_start () {
if ( ! drupal_session_started ()) {
// Save current session data before starting it, as PHP will destroy it.
$session_data = isset ( $_SESSION ) ? $_SESSION : NULL ;
session_start ();
drupal_session_started ( TRUE );
// Restore session data.
if ( ! empty ( $session_data )) {
$_SESSION += $session_data ;
}
}
2009-01-19 10:46:52 +00:00
}
/**
2009-06-02 06:58:17 +00:00
* Commit the current session , if necessary .
2009-01-19 10:46:52 +00:00
*
2009-06-02 06:58:17 +00:00
* If an anonymous user already have an empty session , destroy it .
2009-01-19 10:46:52 +00:00
*/
2009-06-02 06:58:17 +00:00
function drupal_session_commit () {
global $user ;
if ( empty ( $user -> uid ) && empty ( $_SESSION )) {
if ( drupal_session_started ()) {
// Destroy empty anonymous sessions.
session_destroy ();
}
2009-01-19 10:46:52 +00:00
}
else {
2009-06-02 06:58:17 +00:00
if ( ! drupal_session_started ()) {
drupal_session_start ();
}
// Write the session data.
session_write_close ();
2009-01-19 10:46:52 +00:00
}
}
/**
2009-06-02 06:58:17 +00:00
* Return whether a session has been started .
2009-01-19 10:46:52 +00:00
*/
2009-06-02 06:58:17 +00:00
function drupal_session_started ( $set = NULL ) {
static $session_started = FALSE ;
if ( isset ( $set )) {
$session_started = $set ;
}
return $session_started && session_id ();
2009-01-19 10:46:52 +00:00
}
2006-08-31 19:52:39 +00:00
/**
* Called when an anonymous user becomes authenticated or vice - versa .
*/
2008-09-15 15:18:59 +00:00
function drupal_session_regenerate () {
2009-06-02 06:58:17 +00:00
global $user ;
// Set the session cookie "httponly" flag to reduce the risk of session
// stealing via XSS.
2008-11-24 06:12:46 +00:00
extract ( session_get_cookie_params ());
session_set_cookie_params ( $lifetime , $path , $domain , $secure , TRUE );
2009-06-02 06:58:17 +00:00
if ( drupal_session_started ()) {
$old_session_id = session_id ();
session_regenerate_id ();
}
else {
// Start the session when it doesn't exist yet.
// Preserve the logged in user, as it will be reset to anonymous
// by _sess_read.
$account = $user ;
drupal_session_start ();
$user = $account ;
}
if ( isset ( $old_session_id )) {
db_update ( 'sessions' )
-> fields ( array (
'sid' => session_id ()
))
-> condition ( 'sid' , $old_session_id )
-> execute ();
}
2006-08-31 19:52:39 +00:00
}
/**
2008-09-27 20:37:01 +00:00
* Counts how many users are active on the site .
2006-08-31 19:52:39 +00:00
*
2008-09-27 20:37:01 +00:00
* Counts how many users have sessions which have been active since the
* specified time . Can count either anonymous sessions or
* authenticated sessions .
*
* @ param int $timestamp .
* A Unix timestamp . Users who have been active since this time will be
* counted . The default is 0 , which counts all existing sessions .
2008-08-12 10:28:33 +00:00
* @ param boolean $anonymous
2006-08-31 19:52:39 +00:00
* TRUE counts only anonymous users .
* FALSE counts only authenticated users .
2008-09-27 20:37:01 +00:00
* @ return int
2006-08-31 19:52:39 +00:00
* The number of users with sessions .
*/
2008-09-19 07:53:59 +00:00
function drupal_session_count ( $timestamp = 0 , $anonymous = TRUE ) {
2008-11-01 21:27:38 +00:00
$query = db_select ( 'sessions' );
$query -> addExpression ( 'COUNT(sid)' , 'count' );
$query -> condition ( 'timestamp' , $timestamp , '>=' );
$query -> condition ( 'uid' , 0 , $anonymous ? '=' : '>' );
return $query -> execute () -> fetchField ();
2006-08-31 19:52:39 +00:00
}
/**
2008-09-15 15:18:59 +00:00
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
2008-09-15 15:18:59 +00:00
* Cleanup a specific session .
2006-12-04 10:41:20 +00:00
*
2008-09-27 20:37:01 +00:00
* @ param string $sid
* Session ID .
2006-12-04 10:41:20 +00:00
*/
2008-09-15 15:18:59 +00:00
function _sess_destroy_sid ( $sid ) {
2008-11-01 21:27:38 +00:00
db_delete ( 'sessions' )
-> condition ( 'sid' , $sid )
-> execute ();
2009-01-19 10:46:52 +00:00
// Unset cookie.
extract ( session_get_cookie_params ());
setcookie ( session_name (), '' , time () - 3600 , $path , $domain , $secure , $httponly );
2006-12-04 10:41:20 +00:00
}
/**
2008-09-27 20:37:01 +00:00
* End a specific user ' s session ( s ) .
2006-08-31 19:52:39 +00:00
*
2008-09-27 20:37:01 +00:00
* @ param string $uid
* User ID .
2006-08-31 19:52:39 +00:00
*/
2008-09-15 15:18:59 +00:00
function drupal_session_destroy_uid ( $uid ) {
2008-11-01 21:27:38 +00:00
db_delete ( 'sessions' )
-> condition ( 'uid' , $uid )
-> execute ();
2003-11-18 19:44:36 +00:00
}
2008-09-15 15:18:59 +00:00
/**
* Session handler assigned by session_set_save_handler () .
2008-09-15 20:48:10 +00:00
*
2008-09-15 15:18:59 +00:00
* Cleanup stalled sessions .
2008-09-27 20:37:01 +00:00
*
* @ param int $lifetime
* The value of session . gc_maxlifetime , passed by PHP .
2008-11-11 16:49:38 +00:00
* Sessions not updated for more than $lifetime seconds will be removed .
2008-09-15 15:18:59 +00:00
*/
function _sess_gc ( $lifetime ) {
2006-02-10 05:42:11 +00:00
// Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
2006-05-07 00:08:36 +00:00
// value. For example, if you want user sessions to stay in your database
2006-02-10 05:42:11 +00:00
// for three weeks before deleting them, you need to set gc_maxlifetime
2006-05-07 00:08:36 +00:00
// to '1814400'. At that value, only after a user doesn't log in after
2006-02-10 05:42:11 +00:00
// three weeks (1814400 seconds) will his/her session be removed.
2008-11-01 21:27:38 +00:00
db_delete ( 'sessions' )
-> condition ( 'timestamp' , REQUEST_TIME - $lifetime , '<' )
-> execute ();
2006-02-10 05:42:11 +00:00
return TRUE ;
2006-10-24 15:31:35 +00:00
}
2007-12-05 19:12:59 +00:00
/**
* Determine whether to save session data of the current request .
*
2008-09-15 20:48:10 +00:00
* This function allows the caller to temporarily disable writing of
* session data , should the request end while performing potentially
2008-09-08 21:08:24 +00:00
* dangerous operations , such as manipulating the global $user object .
2008-09-27 20:37:01 +00:00
* See http :// drupal . org / node / 218104 for usage .
2007-12-05 19:12:59 +00:00
*
* @ param $status
2008-09-15 20:48:10 +00:00
* Disables writing of session data when FALSE , ( re - ) enables
2008-09-08 21:08:24 +00:00
* writing when TRUE .
2007-12-05 19:12:59 +00:00
* @ return
* FALSE if writing session data has been disabled . Otherwise , TRUE .
*/
2008-09-15 15:18:59 +00:00
function drupal_save_session ( $status = NULL ) {
2009-04-03 17:41:32 +00:00
$save_session = & drupal_static ( __FUNCTION__ , TRUE );
2007-12-05 19:12:59 +00:00
if ( isset ( $status )) {
$save_session = $status ;
}
2008-11-01 21:27:38 +00:00
return $save_session ;
2007-12-05 19:12:59 +00:00
}