webmaster@1
|
1 <?php |
webmaster@17
|
2 // $Id: session.inc,v 1.44.2.6 2008/12/11 00:29:34 goba Exp $ |
webmaster@1
|
3 |
webmaster@1
|
4 /** |
webmaster@1
|
5 * @file |
webmaster@1
|
6 * User session handling functions. |
webmaster@1
|
7 */ |
webmaster@1
|
8 |
webmaster@1
|
9 function sess_open($save_path, $session_name) { |
webmaster@1
|
10 return TRUE; |
webmaster@1
|
11 } |
webmaster@1
|
12 |
webmaster@1
|
13 function sess_close() { |
webmaster@1
|
14 return TRUE; |
webmaster@1
|
15 } |
webmaster@1
|
16 |
webmaster@1
|
17 function sess_read($key) { |
webmaster@1
|
18 global $user; |
webmaster@1
|
19 |
webmaster@1
|
20 // Write and Close handlers are called after destructing objects since PHP 5.0.5 |
webmaster@1
|
21 // Thus destructors can use sessions but session handler can't use objects. |
webmaster@1
|
22 // So we are moving session closure before destructing objects. |
webmaster@1
|
23 register_shutdown_function('session_write_close'); |
webmaster@1
|
24 |
webmaster@1
|
25 // Handle the case of first time visitors and clients that don't store cookies (eg. web crawlers). |
webmaster@1
|
26 if (!isset($_COOKIE[session_name()])) { |
webmaster@1
|
27 $user = drupal_anonymous_user(); |
webmaster@1
|
28 return ''; |
webmaster@1
|
29 } |
webmaster@1
|
30 |
webmaster@1
|
31 // Otherwise, if the session is still active, we have a record of the client's session in the database. |
webmaster@1
|
32 $user = db_fetch_object(db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '%s'", $key)); |
webmaster@1
|
33 |
webmaster@1
|
34 // We found the client's session record and they are an authenticated user |
webmaster@1
|
35 if ($user && $user->uid > 0) { |
webmaster@1
|
36 // This is done to unserialize the data member of $user |
webmaster@1
|
37 $user = drupal_unpack($user); |
webmaster@1
|
38 |
webmaster@1
|
39 // Add roles element to $user |
webmaster@1
|
40 $user->roles = array(); |
webmaster@1
|
41 $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; |
webmaster@1
|
42 $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); |
webmaster@1
|
43 while ($role = db_fetch_object($result)) { |
webmaster@1
|
44 $user->roles[$role->rid] = $role->name; |
webmaster@1
|
45 } |
webmaster@1
|
46 } |
webmaster@1
|
47 // We didn't find the client's record (session has expired), or they are an anonymous user. |
webmaster@1
|
48 else { |
webmaster@1
|
49 $session = isset($user->session) ? $user->session : ''; |
webmaster@1
|
50 $user = drupal_anonymous_user($session); |
webmaster@1
|
51 } |
webmaster@1
|
52 |
webmaster@1
|
53 return $user->session; |
webmaster@1
|
54 } |
webmaster@1
|
55 |
webmaster@1
|
56 function sess_write($key, $value) { |
webmaster@1
|
57 global $user; |
webmaster@1
|
58 |
webmaster@1
|
59 // If saving of session data is disabled or if the client doesn't have a session, |
webmaster@11
|
60 // and one isn't being created ($value), do nothing. This keeps crawlers out of |
webmaster@11
|
61 // the session table. This reduces memory and server load, and gives more useful |
webmaster@11
|
62 // statistics. We can't eliminate anonymous session table rows without breaking |
webmaster@11
|
63 // the throttle module and the "Who's Online" block. |
webmaster@13
|
64 if (!session_save_session() || ($user->uid == 0 && empty($_COOKIE[session_name()]) && empty($value))) { |
webmaster@1
|
65 return TRUE; |
webmaster@1
|
66 } |
webmaster@1
|
67 |
webmaster@11
|
68 db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time(), $key); |
webmaster@11
|
69 if (db_affected_rows()) { |
webmaster@1
|
70 // Last access time is updated no more frequently than once every 180 seconds. |
webmaster@1
|
71 // This reduces contention in the users table. |
webmaster@1
|
72 if ($user->uid && time() - $user->access > variable_get('session_write_interval', 180)) { |
webmaster@1
|
73 db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid); |
webmaster@1
|
74 } |
webmaster@1
|
75 } |
webmaster@11
|
76 else { |
webmaster@11
|
77 // If this query fails, another parallel request probably got here first. |
webmaster@11
|
78 // In that case, any session data generated in this request is discarded. |
webmaster@11
|
79 @db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time()); |
webmaster@11
|
80 } |
webmaster@1
|
81 |
webmaster@1
|
82 return TRUE; |
webmaster@1
|
83 } |
webmaster@1
|
84 |
webmaster@1
|
85 /** |
webmaster@1
|
86 * Called when an anonymous user becomes authenticated or vice-versa. |
webmaster@1
|
87 */ |
webmaster@1
|
88 function sess_regenerate() { |
webmaster@1
|
89 $old_session_id = session_id(); |
webmaster@1
|
90 |
webmaster@1
|
91 // We code around http://bugs.php.net/bug.php?id=32802 by destroying |
webmaster@1
|
92 // the session cookie by setting expiration in the past (a negative |
webmaster@1
|
93 // value). This issue only arises in PHP versions before 4.4.0, |
webmaster@1
|
94 // regardless of the Drupal configuration. |
webmaster@1
|
95 // TODO: remove this when we require at least PHP 4.4.0 |
webmaster@1
|
96 if (isset($_COOKIE[session_name()])) { |
webmaster@1
|
97 setcookie(session_name(), '', time() - 42000, '/'); |
webmaster@1
|
98 } |
webmaster@1
|
99 |
webmaster@1
|
100 session_regenerate_id(); |
webmaster@1
|
101 |
webmaster@1
|
102 db_query("UPDATE {sessions} SET sid = '%s' WHERE sid = '%s'", session_id(), $old_session_id); |
webmaster@1
|
103 } |
webmaster@1
|
104 |
webmaster@1
|
105 /** |
webmaster@9
|
106 * Counts how many users have sessions. Can count either anonymous sessions or authenticated sessions. |
webmaster@1
|
107 * |
webmaster@1
|
108 * @param int $timestamp |
webmaster@1
|
109 * A Unix timestamp representing a point of time in the past. |
webmaster@1
|
110 * The default is 0, which counts all existing sessions. |
webmaster@9
|
111 * @param boolean $anonymous |
webmaster@1
|
112 * TRUE counts only anonymous users. |
webmaster@1
|
113 * FALSE counts only authenticated users. |
webmaster@1
|
114 * @return int |
webmaster@1
|
115 * The number of users with sessions. |
webmaster@1
|
116 */ |
webmaster@1
|
117 function sess_count($timestamp = 0, $anonymous = true) { |
webmaster@1
|
118 $query = $anonymous ? ' AND uid = 0' : ' AND uid > 0'; |
webmaster@1
|
119 return db_result(db_query('SELECT COUNT(sid) AS count FROM {sessions} WHERE timestamp >= %d'. $query, $timestamp)); |
webmaster@1
|
120 } |
webmaster@1
|
121 |
webmaster@1
|
122 /** |
webmaster@1
|
123 * Called by PHP session handling with the PHP session ID to end a user's session. |
webmaster@1
|
124 * |
webmaster@1
|
125 * @param string $sid |
webmaster@1
|
126 * the session id |
webmaster@1
|
127 */ |
webmaster@1
|
128 function sess_destroy_sid($sid) { |
webmaster@1
|
129 db_query("DELETE FROM {sessions} WHERE sid = '%s'", $sid); |
webmaster@1
|
130 } |
webmaster@1
|
131 |
webmaster@1
|
132 /** |
webmaster@1
|
133 * End a specific user's session |
webmaster@1
|
134 * |
webmaster@1
|
135 * @param string $uid |
webmaster@1
|
136 * the user id |
webmaster@1
|
137 */ |
webmaster@1
|
138 function sess_destroy_uid($uid) { |
webmaster@1
|
139 db_query('DELETE FROM {sessions} WHERE uid = %d', $uid); |
webmaster@1
|
140 } |
webmaster@1
|
141 |
webmaster@1
|
142 function sess_gc($lifetime) { |
webmaster@1
|
143 // Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough |
webmaster@1
|
144 // value. For example, if you want user sessions to stay in your database |
webmaster@1
|
145 // for three weeks before deleting them, you need to set gc_maxlifetime |
webmaster@1
|
146 // to '1814400'. At that value, only after a user doesn't log in after |
webmaster@1
|
147 // three weeks (1814400 seconds) will his/her session be removed. |
webmaster@1
|
148 db_query("DELETE FROM {sessions} WHERE timestamp < %d", time() - $lifetime); |
webmaster@1
|
149 |
webmaster@1
|
150 return TRUE; |
webmaster@1
|
151 } |
webmaster@1
|
152 |
webmaster@1
|
153 /** |
webmaster@1
|
154 * Determine whether to save session data of the current request. |
webmaster@1
|
155 * |
webmaster@1
|
156 * This function allows the caller to temporarily disable writing of session data, |
webmaster@1
|
157 * should the request end while performing potentially dangerous operations, such as |
webmaster@1
|
158 * manipulating the global $user object. See http://drupal.org/node/218104 for usage |
webmaster@1
|
159 * |
webmaster@1
|
160 * @param $status |
webmaster@1
|
161 * Disables writing of session data when FALSE, (re-)enables writing when TRUE. |
webmaster@1
|
162 * @return |
webmaster@1
|
163 * FALSE if writing session data has been disabled. Otherwise, TRUE. |
webmaster@1
|
164 */ |
webmaster@1
|
165 function session_save_session($status = NULL) { |
webmaster@1
|
166 static $save_session = TRUE; |
webmaster@1
|
167 if (isset($status)) { |
webmaster@1
|
168 $save_session = $status; |
webmaster@1
|
169 } |
webmaster@1
|
170 return ($save_session); |
webmaster@1
|
171 } |