diff --git mongodb_session/mongodb_session.inc mongodb_session/mongodb_session.inc index 3895a96..d764435 100644 --- mongodb_session/mongodb_session.inc +++ mongodb_session/mongodb_session.inc @@ -30,9 +30,7 @@ include_once dirname(__FILE__) . '/../mongodb.module'; * @return * This function will always return TRUE. */ -function _drupal_session_open() { - return TRUE; -} +function sess_open($save_path, $session_name) {return TRUE;} /** * Session handler assigned by session_set_save_handler(). @@ -46,8 +44,73 @@ function _drupal_session_open() { * @return * This function will always return TRUE. */ -function _drupal_session_close() { - return TRUE; +function sess_close() {return TRUE;} + +/** + * Called when an anonymous user becomes authenticated or vice-versa. + */ +function sess_regenerate() { + $old_session_id = session_id(); + + // We code around http://bugs.php.net/bug.php?id=32802 by destroying + // the session cookie by setting expiration in the past (a negative + // value). This issue only arises in PHP versions before 4.4.0, + // regardless of the Drupal configuration. + // TODO: remove this when we require at least PHP 4.4.0 + if (isset($_COOKIE[session_name()])) { + setcookie(session_name(), '', REQUEST_TIME - 42000, '/'); + } + + session_regenerate_id(); + + mongodb_collection('session') + ->update(array('sid' => $old_session_id), array('$set' => array('sid' => session_id()))); +} + +/** + * Counts how many users have sessions. Can count either anonymous sessions or authenticated sessions. + * + * @param int $timestamp + * A Unix timestamp representing a point of time in the past. + * The default is 0, which counts all existing sessions. + * @param boolean $anonymous + * TRUE counts only anonymous users. + * FALSE counts only authenticated users. + * @return int + * The number of users with sessions. + */ +function sess_count($timestamp = 0, $anonymous = true) { + $collection = mongodb_collection('session'); + $conditions = array( + 'timestamp' => array('$gte' => $timestamp), + ); + if ($anonymous) { + $conditions['uid'] = 0; + } + else { + $conditions['uid'] = array('$gt' => 0); + } + return $collection->find($conditions)->count(); +} + +/** + * Determine whether to save session data of the current request. + * + * This function allows the caller to temporarily disable writing of session data, + * should the request end while performing potentially dangerous operations, such as + * manipulating the global $user object. See http://drupal.org/node/218104 for usage + * + * @param $status + * Disables writing of session data when FALSE, (re-)enables writing when TRUE. + * @return + * FALSE if writing session data has been disabled. Otherwise, TRUE. + */ +function session_save_session($status = NULL) { + static $save_session = TRUE; + if (isset($status)) { + $save_session = $status; + } + return ($save_session); } /** @@ -66,8 +129,8 @@ function _drupal_session_close() { * Either an array of the session data, or an empty string, if no data * was found or the user is anonymous. */ -function _drupal_session_read($sid) { - global $user, $is_https; +function sess_read($sid) { + global $user; // Write and Close handlers are called after destructing objects // since PHP 5.0.5. @@ -77,43 +140,33 @@ function _drupal_session_read($sid) { // Handle the case of first time visitors and clients that don't store // cookies (eg. web crawlers). - $insecure_session_name = substr(session_name(), 1); - if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) { + if (!isset($_COOKIE[session_name()])) { $user = drupal_anonymous_user(); return ''; } - // Otherwise, if the session is still active, we have a record of the - // client's session in the database. If it's HTTPS then we are either have - // a HTTPS session or we are about to log in so we check the sessions table - // for an anonymous session wth the non-HTTPS-only cookie. + // Otherwise, if the session is still active, we have a record of the client's session in the database. $collection = mongodb_collection('session'); - if ($is_https) { - $user = (object)$collection->findOne(array('ssid' => $sid)); - if (!$user) { - if (isset($_COOKIE[$insecure_session_name])) { - $user = (object)$collection->findOne(array('sid' => $_COOKIE[$insecure_session_name], 'uid' => 0)); - } - } - } - else { - $r = $collection->find(array('sid' => $sid)); - foreach ($r as $user); - $user = (object)$user; - } - - // We found the client's session record and they are an authenticated user. - if ($user && !empty($user->uid)) { - // This is done to unserialize the data member of $user. + $r = $collection->find(array('sid' => $sid)); + foreach ($r as $user); + $user = (object)$user; + + // We found the client's session record and they are an authenticated, + // active user. + if ($user && $user->uid > 0 && $user->status == 1) { + // This is done to unserialize the data member of $user $user = drupal_unpack($user); - // Add roles element to $user. + // Add roles element to $user $user->roles = array(); $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - $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); + $result = db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d", $user->uid); + while ($role = db_fetch_object($result)) { + $user->roles[$role->rid] = $role->name; + } } - // We didn't find the client's record (session has expired), or they - // are an anonymous user. + // We didn't find the client's record (session has expired), or they are + // blocked, or they are an anonymous user. else { $session = isset($user->session) ? $user->session : ''; $user = drupal_anonymous_user($session); @@ -138,10 +191,10 @@ function _drupal_session_read($sid) { * @return * This function will always return TRUE. */ -function _drupal_session_write($sid, $value) { - global $user, $is_https; +function sess_write($sid, $value) { + global $user; - if (!drupal_save_session()) { + if (!session_save_session()) { // We don't have anything to do if we are not allowed to save the session. return; } @@ -154,16 +207,6 @@ function _drupal_session_write($sid, $value) { 'timestamp' => REQUEST_TIME, ); $key = array('sid' => $sid); - if ($is_https) { - $key['ssid'] = $sid; - $insecure_session_name = substr(session_name(), 1); - // The "secure pages" setting allows a site to simultaneously use both - // secure and insecure session cookies. If enabled, use the insecure session - // identifier as the sid. - if (variable_get('https', FALSE) && isset($_COOKIE[$insecure_session_name])) { - $key['sid'] = $_COOKIE[$insecure_session_name]; - } - } $collection = mongodb_collection('session'); $collection @@ -172,143 +215,13 @@ function _drupal_session_write($sid, $value) { // 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)) { - db_update('users') - ->fields(array( - 'access' => REQUEST_TIME - )) - ->condition('uid', $user->uid) - ->execute(); + db_query("UPDATE {users} SET access = %d WHERE uid = %d", REQUEST_TIME, $user->uid); } return TRUE; } /** - * Initialize the session handler, starting a session if needed. - */ -function drupal_session_initialize() { - global $user; - - session_set_save_handler('_drupal_session_open', '_drupal_session_close', '_drupal_session_read', '_drupal_session_write', '_drupal_session_destroy', '_drupal_session_garbage_collection'); - - 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))); - } -} - -/** - * Forcefully start a session, preserving already set session data. - * - * @ingroup php_wrappers - */ -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; - } - } -} - -/** - * Commit the current session, if necessary. - * - * If an anonymous user already have an empty session, destroy it. - */ -function drupal_session_commit() { - global $user; - - if (!drupal_save_session()) { - // We don't have anything to do if we are not allowed to save the session. - return; - } - - if (empty($user->uid) && empty($_SESSION)) { - // There is no session data to store, destroy the session if it was - // previously started. - if (drupal_session_started()) { - session_destroy(); - } - } - else { - // There is session data to store. Start the session if it is not already - // started. - if (!drupal_session_started()) { - drupal_session_start(); - } - // Write the session data. - session_write_close(); - } -} - -/** - * Return whether a session has been started. - */ -function drupal_session_started($set = NULL) { - static $session_started = FALSE; - if (isset($set)) { - $session_started = $set; - } - return $session_started && session_id(); -} - -/** - * Called when an anonymous user becomes authenticated or vice-versa. - * - * @ingroup php_wrappers - */ -function drupal_session_regenerate() { - global $user, $is_https; - if ($is_https && variable_get('https', FALSE)) { - $insecure_session_name = substr(session_name(), 1); - $params = session_get_cookie_params(); - $session_id = md5(uniqid(mt_rand(), TRUE)); - setcookie($insecure_session_name, $session_id, REQUEST_TIME + $params['lifetime'], $params['path'], $params['domain'], FALSE, $params['httponly']); - $_COOKIE[$insecure_session_name] = $session_id; - } - - 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 _drupal_session_read. - $account = $user; - drupal_session_start(); - $user = $account; - } - - if (isset($old_session_id)) { - $field = $is_https ? 'ssid' : 'sid'; - mongodb_collection('session') - ->update(array('sid' => $old_session_id), array('$set' => array($field => session_id()))); - } -} - -/** * Session handler assigned by session_set_save_handler(). * * Cleanup a specific session. @@ -316,39 +229,9 @@ function drupal_session_regenerate() { * @param string $sid * Session ID. */ -function _drupal_session_destroy($sid) { - global $user, $is_https; - - $field = $is_https ? 'ssid' : 'sid'; +function sess_destroy_sid($sid) { mongodb_collection('session') - ->remove(array($field => $sid)); - - // Reset $_SESSION and $user to prevent a new session from being started - // in drupal_session_commit(). - $_SESSION = array(); - $user = drupal_anonymous_user(); - - // Unset the session cookies. - _drupal_session_delete_cookie(session_name()); - if ($is_https) { - _drupal_session_delete_cookie(substr(session_name(), 1), TRUE); - } -} - -/** - * Deletes the session cookie. - * - * @param $name - * Name of session cookie to delete. - * @param $force_insecure - * Fornce cookie to be insecure. - */ -function _drupal_session_delete_cookie($name, $force_insecure = FALSE) { - if (isset($_COOKIE[$name])) { - $params = session_get_cookie_params(); - setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], !$force_insecure && $params['secure'], $params['httponly']); - unset($_COOKIE[$name]); - } + ->remove(array('sid' => $sid)); } /** @@ -357,7 +240,7 @@ function _drupal_session_delete_cookie($name, $force_insecure = FALSE) { * @param string $uid * User ID. */ -function drupal_session_destroy_uid($uid) { +function sess_destroy_uid($uid) { mongodb_collection('session') ->remove(array('uid' => $uid)); } @@ -371,7 +254,7 @@ function drupal_session_destroy_uid($uid) { * The value of session.gc_maxlifetime, passed by PHP. * Sessions not updated for more than $lifetime seconds will be removed. */ -function _drupal_session_garbage_collection($lifetime) { +function sess_gc($lifetime) { // Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough // value. For example, if you want user sessions to stay in your database // for three weeks before deleting them, you need to set gc_maxlifetime @@ -381,25 +264,3 @@ function _drupal_session_garbage_collection($lifetime) { ->remove(array('timestamp' => array('$lt' => REQUEST_TIME - $lifetime))); return TRUE; } - -/** - * Determine whether to save session data of the current request. - * - * This function allows the caller to temporarily disable writing of - * session data, should the request end while performing potentially - * dangerous operations, such as manipulating the global $user object. - * See http://drupal.org/node/218104 for usage. - * - * @param $status - * Disables writing of session data when FALSE, (re-)enables - * writing when TRUE. - * @return - * FALSE if writing session data has been disabled. Otherwise, TRUE. - */ -function drupal_save_session($status = NULL) { - $save_session = &drupal_static(__FUNCTION__, TRUE); - if (isset($status)) { - $save_session = $status; - } - return $save_session; -} diff --git mongodb_session/mongodb_session.info mongodb_session/mongodb_session.info index 58ef7b9..2bed6ca 100644 --- mongodb_session/mongodb_session.info +++ mongodb_session/mongodb_session.info @@ -2,7 +2,5 @@ name = MongoDB Session description = Store session information in MongoDB package = MongoDB -core = 7.x -files[] = mongodb_session.module -files[] = mongodb_session.inc -files[] = mongodb_session.test +core = 6.x +dependencies[] = mongodb diff --git mongodb_session/mongodb_session.module mongodb_session/mongodb_session.module index a095077..ab9fd82 100644 --- mongodb_session/mongodb_session.module +++ mongodb_session/mongodb_session.module @@ -11,9 +11,6 @@ function mongodb_session_simpletest_alter(&$groups) { // An alternative session handler module would not want to run the original // Session https handling test because it checks the sessions table in the // database. - $groups['MongoDB']['SessionTestCase'] = $groups['Session']['SessionTestCase']; - $groups['MongoDB']['SessionTestCase']['name'] .= ' (MongoDB)'; - unset($groups['Session']); }