? d7_memcache.patch ? d7_review.txt ? memcache.module ? memcache.test ? sess.d7.patch Index: memcache-session.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache-session.inc,v retrieving revision 1.4.2.1 diff -u -p -r1.4.2.1 memcache-session.inc --- memcache-session.inc 5 Dec 2009 00:26:30 -0000 1.4.2.1 +++ memcache-session.inc 11 Dec 2009 00:34:13 -0000 @@ -10,15 +10,15 @@ require_once dirname(__FILE__) . '/dmemc * An alternative to includes/session.inc. */ -function sess_open($save_path, $session_name) { +function _drupal_session_open() { return TRUE; } -function sess_close() { +function _drupal_session_close() { return TRUE; } -function sess_read($key) { +function _drupal_session_read($key) { global $user; // Write and Close handlers are called after destructing objects since PHP 5.0.5 @@ -26,20 +26,20 @@ function sess_read($key) { // So we are moving session closure before destructing objects. register_shutdown_function('session_write_close'); - // Handle the case of first time visitors and clients that don't store + // Handle the case of first time visitors and clients that don't store // cookies (eg. web crawlers). if (!isset($_COOKIE[session_name()])) { $user = drupal_anonymous_user(); return ''; } - // Otherwise, if the session is still active, we have a record of the + // Otherwise, if the session is still active, we have a record of the // client's session in memcache. $session = dmemcache_get($key, 'session'); - - $user = sess_user_load($session); - // Record whether this session contains data so that in sess_write() it can + $user = _memcache_session_user_load($session); + + // Record whether this session contains data so that in sess_write() it can // be determined whether to skip a write. $user->session_data_present_at_load = !empty($session->session); @@ -70,7 +70,7 @@ function sess_read($key) { * @return * TRUE. */ -function sess_write($key, $value) { +function _drupal_session_write($key, $value) { global $user; // If the client doesn't have a session, and one isn't being created ($value), @@ -90,10 +90,10 @@ function sess_write($key, $value) { $session->timestamp = time(); // If this is an authenticated user, or there is something to save in the - // session, or this is an anonymous user who currently has nothing in the + // session, or this is an anonymous user who currently has nothing in the // session but did have something in session storage, write it to memcache. // If $user->session_data_present_at_load is not set, the current user - // was created during this request and it's safest to do a write. + // was created during this request and it's safest to do a write. // Cases 1b, 1d, 2a, and 2b are covered here. if ($user->uid || !empty($value) || empty($value) && (!isset($user->session_data_present_at_load) || $user->session_data_present_at_load)) { dmemcache_set($key, $session, ini_get('session.gc_maxlifetime'), 'session'); @@ -109,23 +109,64 @@ function sess_write($key, $value) { unset($user->session_data_present_at_load); // Store the session id so we can locate the session with the user id. $user->sid = $key; - + dmemcache_set($user->uid, $user, ini_get('session.gc_maxlifetime'), 'users'); } return TRUE; } -function sess_regenerate() { - // 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 + +/** + * Called by PHP session handling with the PHP session ID to end a user's session. + * + * @param string $sid + * the session id + */ +function _drupal_session_destroy($sid) { + dmemcache_delete($sid, 'session'); +} + +function _drupal_session_garbage_collection($lifetime) { + // Automatic with memcached. + // 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 + // to '1814400'. At that value, only after a user doesn't log in after + // three weeks (1814400 seconds) will his/her session be removed. + 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()])) { - setcookie(session_name(), '', time() - 42000, '/'); + // 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))); + } +} + +function sess_regenerate() { // Store the current (anonymous) session id. $old_session_id = session_id(); @@ -151,23 +192,102 @@ function sess_regenerate() { * Would be insane slow with memcached as we would need to retrieve at least the stats of all object. * Not implemented. */ -function sess_count($timestamp = 0, $anonymous = true) { +function drupal_session_count($timestamp = 0, $anonymous = true) { } /** - * Called by PHP session handling with the PHP session ID to end a user's session. + * Forcefully start a session, preserving already set session data. * - * @param string $sid - * the session id + * @ingroup php_wrappers */ -function sess_destroy_sid($sid) { - dmemcache_delete($sid, 'session'); +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; + 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)) { + $session = dmemcache_get($old_session_id, 'session'); + dmemcache_set($sesion_id, $session, ini_get('session.gc_maxlifetime'), 'session'); + } +} + + +/** * End a specific user's session. */ -function sess_destroy_uid($uid) { +function drupal_session_destroy_uid($uid) { $user = dmemcache_get($uid, 'users'); if (is_object($user) && isset($user->sid)) { dmemcache_delete($user->sid, 'session'); @@ -175,15 +295,6 @@ function sess_destroy_uid($uid) { dmemcache_delete($uid, 'users'); } -function sess_gc($lifetime) { - // Automatic with memcached. - // 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 - // to '1814400'. At that value, only after a user doesn't log in after - // three weeks (1814400 seconds) will his/her session be removed. - return TRUE; -} /** * Determine whether to save session data of the current request. @@ -197,8 +308,8 @@ function sess_gc($lifetime) { * @return * FALSE if writing session data has been disabled. Otherwise, TRUE. */ -function session_save_session($status = NULL) { - static $save_session = TRUE; +function drupal_save_session($status = NULL) { + $save_session = &drupal_static(__FUNCTION__, TRUE); if (isset($status)) { $save_session = $status; } @@ -213,7 +324,7 @@ function session_save_session($status = * @return $user * The user object. */ -function sess_user_load($session) { +function _memcache_session_user_load($session) { // We found the client's session record and they are an authenticated user. if ($session && $session->uid != 0) { $user = dmemcache_get($session->uid, 'users'); Index: memcache.info =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache.info,v retrieving revision 1.2.2.1 diff -u -p -r1.2.2.1 memcache.info --- memcache.info 5 Dec 2009 00:26:30 -0000 1.2.2.1 +++ memcache.info 11 Dec 2009 00:34:13 -0000 @@ -2,3 +2,7 @@ name = Memcache description = High performance integration with memcache. package = Caching +core = 7.x +files[] = memcache.inc +files[] = memcache.module +files[] = memcache.test