| 1 |
<?php
|
| 2 |
// $Id: memcache-session.inc,v 1.3 2008/11/11 03:05:10 jeremy Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* User session handling functions.
|
| 7 |
*/
|
| 8 |
|
| 9 |
function sess_open($save_path, $session_name) {
|
| 10 |
return TRUE;
|
| 11 |
}
|
| 12 |
|
| 13 |
function sess_close() {
|
| 14 |
return TRUE;
|
| 15 |
}
|
| 16 |
|
| 17 |
function sess_read($key) {
|
| 18 |
global $user;
|
| 19 |
|
| 20 |
// Write and Close handlers are called after destructing objects since PHP 5.0.5
|
| 21 |
// Thus destructors can use sessions but session handler can't use objects.
|
| 22 |
// So we are moving session closure before destructing objects.
|
| 23 |
register_shutdown_function('session_write_close');
|
| 24 |
|
| 25 |
// Handle the case of first time visitors and clients that don't store cookies (eg. web crawlers).
|
| 26 |
if (!isset($_COOKIE[session_name()])) {
|
| 27 |
$user = drupal_anonymous_user();
|
| 28 |
return '';
|
| 29 |
}
|
| 30 |
|
| 31 |
// Otherwise, if the session is still active, we have a record of the client's session in memcache.
|
| 32 |
$session = dmemcache_get($key, 'session');
|
| 33 |
|
| 34 |
$user = sess_user_load($session);
|
| 35 |
|
| 36 |
return $user->session;
|
| 37 |
}
|
| 38 |
|
| 39 |
function sess_write($key, $value) {
|
| 40 |
global $user;
|
| 41 |
|
| 42 |
// If the client doesn't have a session, and one isn't being created ($value), do nothing.
|
| 43 |
if (empty($_COOKIE[session_name()]) && empty($value)) {
|
| 44 |
return TRUE;
|
| 45 |
}
|
| 46 |
|
| 47 |
// Prepare the information to be saved
|
| 48 |
$session = new stdClass;
|
| 49 |
$session->sid = $key;
|
| 50 |
$session->uid = $user->uid;
|
| 51 |
$session->cache = $user->cache;
|
| 52 |
$session->hostname = $_SERVER["REMOTE_ADDR"];
|
| 53 |
$session->session = $value;
|
| 54 |
$session->timestamp = time();
|
| 55 |
|
| 56 |
if ($user->uid || $value) {
|
| 57 |
dmemcache_set($key, $session, ini_get('session.gc_maxlifetime'), 'session');
|
| 58 |
dmemcache_set($user->uid, $user, ini_get('session.gc_maxlifetime'), 'users');
|
| 59 |
if ($user->uid && $user->access < time() - 300) {
|
| 60 |
db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid);
|
| 61 |
}
|
| 62 |
}
|
| 63 |
|
| 64 |
return TRUE;
|
| 65 |
}
|
| 66 |
|
| 67 |
function sess_regenerate() {
|
| 68 |
// We code around http://bugs.php.net/bug.php?id=32802 by destroying
|
| 69 |
// the session cookie by setting expiration in the past (a negative
|
| 70 |
// value). This issue only arises in PHP versions before 4.4.0,
|
| 71 |
// regardless of the Drupal configuration.
|
| 72 |
// TODO: remove this when we require at least PHP 4.4.0
|
| 73 |
if (isset($_COOKIE[session_name()])) {
|
| 74 |
setcookie(session_name(), '', time() - 42000, '/');
|
| 75 |
}
|
| 76 |
|
| 77 |
// Store the current (anonymous) session id.
|
| 78 |
$old_session_id = session_id();
|
| 79 |
|
| 80 |
// Generate the new (authenticated) session id.
|
| 81 |
session_regenerate_id();
|
| 82 |
$key = session_id();
|
| 83 |
|
| 84 |
// Grab the user's information that is cached with the anonymous key
|
| 85 |
$info = dmemcache_get($old_session_id, 'session');
|
| 86 |
|
| 87 |
// Update it.
|
| 88 |
$info->sid = $key;
|
| 89 |
|
| 90 |
// Store it with the new key.
|
| 91 |
dmemcache_set($key, $info, ini_get('session.gc_maxlifetime'), 'session');
|
| 92 |
|
| 93 |
// Clear the old data from the cache.
|
| 94 |
dmemcache_delete($old_session_id, 'session');
|
| 95 |
}
|
| 96 |
|
| 97 |
/**
|
| 98 |
* Counts how many users have sessions. Can count either anonymous sessions, authenticated sessions, or both.
|
| 99 |
* Would be insane slow with memcached as we would need to retrieve at least the stats of all object.
|
| 100 |
* Not implemented.
|
| 101 |
*/
|
| 102 |
function sess_count($timestamp = 0, $anonymous = true) {
|
| 103 |
}
|
| 104 |
|
| 105 |
/**
|
| 106 |
* Called by PHP session handling with the PHP session ID to end a user's session.
|
| 107 |
*
|
| 108 |
* @param string $sid
|
| 109 |
* the session id
|
| 110 |
*/
|
| 111 |
function sess_destroy_sid($sid) {
|
| 112 |
dmemcache_delete($sid, 'session');
|
| 113 |
}
|
| 114 |
|
| 115 |
/**
|
| 116 |
* End a specific user's session. Not implemented.
|
| 117 |
*/
|
| 118 |
function sess_destroy_uid($uid) {
|
| 119 |
}
|
| 120 |
|
| 121 |
function sess_gc($lifetime) {
|
| 122 |
// Automatic with memcached.
|
| 123 |
// Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
|
| 124 |
// value. For example, if you want user sessions to stay in your database
|
| 125 |
// for three weeks before deleting them, you need to set gc_maxlifetime
|
| 126 |
// to '1814400'. At that value, only after a user doesn't log in after
|
| 127 |
// three weeks (1814400 seconds) will his/her session be removed.
|
| 128 |
return TRUE;
|
| 129 |
}
|
| 130 |
|
| 131 |
function sess_user_load($session) {
|
| 132 |
$user = new stdClass;
|
| 133 |
// We found the client's session record and they are an authenticated user
|
| 134 |
if ($session && $session->uid > 0) {
|
| 135 |
$user = dmemcache_get($session->uid, 'users');
|
| 136 |
if (!$user->uid && $user->uid != 0) {
|
| 137 |
$user = db_fetch_object(db_query("SELECT u.* FROM {users} u WHERE u.uid = %d", $session->uid));
|
| 138 |
$user = drupal_unpack($user);
|
| 139 |
$user->session = empty($session->session) ? '' : $session->session;
|
| 140 |
|
| 141 |
// Add roles element to $user
|
| 142 |
$user->roles = array();
|
| 143 |
$user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
|
| 144 |
$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);
|
| 145 |
while ($role = db_fetch_object($result)) {
|
| 146 |
$user->roles[$role->rid] = $role->name;
|
| 147 |
}
|
| 148 |
}
|
| 149 |
else if ($user->uid) {
|
| 150 |
$user->from_cache = TRUE;
|
| 151 |
$user->session = empty($session->session) ? '' : $session->session;
|
| 152 |
}
|
| 153 |
else {
|
| 154 |
// This is a rare case that we have a session cached, but no session user object cached.
|
| 155 |
// This usually only happens if you kill memcached and restart it.
|
| 156 |
$user = drupal_anonymous_user($session->session);
|
| 157 |
}
|
| 158 |
}
|
| 159 |
// We didn't find the client's record (session has expired), or they are an anonymous user.
|
| 160 |
else {
|
| 161 |
$session = isset($session->session) ? $session->session : '';
|
| 162 |
$user = drupal_anonymous_user($session);
|
| 163 |
}
|
| 164 |
|
| 165 |
return $user;
|
| 166 |
}
|