443
by dcoles
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0 |
1 |
<?php
|
2 |
/**
|
|
3 |
*
|
|
4 |
* @package phpBB3
|
|
5 |
* @version $Id: session.php,v 1.317 2007/11/04 12:07:46 acydburn Exp $
|
|
6 |
* @copyright (c) 2005 phpBB Group
|
|
7 |
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
|
8 |
*
|
|
9 |
*/
|
|
10 |
||
11 |
/**
|
|
12 |
* @ignore
|
|
13 |
*/
|
|
14 |
if (!defined('IN_PHPBB')) |
|
15 |
{
|
|
16 |
exit; |
|
17 |
}
|
|
18 |
||
19 |
/**
|
|
20 |
* Session class
|
|
21 |
* @package phpBB3
|
|
22 |
*/
|
|
23 |
class session |
|
24 |
{
|
|
25 |
var $cookie_data = array(); |
|
26 |
var $page = array(); |
|
27 |
var $data = array(); |
|
28 |
var $browser = ''; |
|
29 |
var $forwarded_for = ''; |
|
30 |
var $host = ''; |
|
31 |
var $session_id = ''; |
|
32 |
var $ip = ''; |
|
33 |
var $load = 0; |
|
34 |
var $time_now = 0; |
|
35 |
var $update_session_page = true; |
|
36 |
||
37 |
/**
|
|
38 |
* Extract current session page
|
|
39 |
*
|
|
40 |
* @param string $root_path current root path (phpbb_root_path)
|
|
41 |
*/
|
|
42 |
function extract_current_page($root_path) |
|
43 |
{
|
|
44 |
$page_array = array(); |
|
45 |
||
46 |
// First of all, get the request uri...
|
|
47 |
$script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF'); |
|
48 |
$args = (!empty($_SERVER['QUERY_STRING'])) ? explode('&', $_SERVER['QUERY_STRING']) : explode('&', getenv('QUERY_STRING')); |
|
49 |
||
50 |
// If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support...
|
|
51 |
if (!$script_name) |
|
52 |
{
|
|
53 |
$script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); |
|
54 |
$script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name; |
|
55 |
$page_array['failover'] = 1; |
|
56 |
}
|
|
57 |
||
58 |
// Replace backslashes and doubled slashes (could happen on some proxy setups)
|
|
59 |
$script_name = str_replace(array('\\', '//'), '/', $script_name); |
|
60 |
||
61 |
// Now, remove the sid and let us get a clean query string...
|
|
62 |
$use_args = array(); |
|
63 |
||
64 |
// Since some browser do not encode correctly we need to do this with some "special" characters...
|
|
65 |
// " -> %22, ' => %27, < -> %3C, > -> %3E
|
|
66 |
$find = array('"', "'", '<', '>'); |
|
67 |
$replace = array('%22', '%27', '%3C', '%3E'); |
|
68 |
||
69 |
foreach ($args as $key => $argument) |
|
70 |
{
|
|
71 |
if (strpos($argument, 'sid=') === 0 || strpos($argument, '_f_=') === 0) |
|
72 |
{
|
|
73 |
continue; |
|
74 |
}
|
|
75 |
||
76 |
$use_args[str_replace($find, $replace, $key)] = str_replace($find, $replace, $argument); |
|
77 |
}
|
|
78 |
unset($args); |
|
79 |
||
80 |
// The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2
|
|
81 |
||
82 |
// The current query string
|
|
83 |
$query_string = trim(implode('&', $use_args)); |
|
84 |
||
85 |
// basenamed page name (for example: index.php)
|
|
86 |
$page_name = basename($script_name); |
|
87 |
$page_name = urlencode(htmlspecialchars($page_name)); |
|
88 |
||
89 |
// current directory within the phpBB root (for example: adm)
|
|
90 |
$root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path))); |
|
91 |
$page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./'))); |
|
92 |
$intersection = array_intersect_assoc($root_dirs, $page_dirs); |
|
93 |
||
94 |
$root_dirs = array_diff_assoc($root_dirs, $intersection); |
|
95 |
$page_dirs = array_diff_assoc($page_dirs, $intersection); |
|
96 |
||
97 |
$page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs); |
|
98 |
||
99 |
if ($page_dir && substr($page_dir, -1, 1) == '/') |
|
100 |
{
|
|
101 |
$page_dir = substr($page_dir, 0, -1); |
|
102 |
}
|
|
103 |
||
104 |
// Current page from phpBB root (for example: adm/index.php?i=10&b=2)
|
|
105 |
$page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : ''); |
|
106 |
||
107 |
// The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in /
|
|
108 |
$script_path = trim(str_replace('\\', '/', dirname($script_name))); |
|
109 |
||
110 |
// The script path from the webroot to the phpBB root (for example: /phpBB3/)
|
|
111 |
$script_dirs = explode('/', $script_path); |
|
112 |
array_splice($script_dirs, -sizeof($page_dirs)); |
|
113 |
$root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : ''); |
|
114 |
||
115 |
// We are on the base level (phpBB root == webroot), lets adjust the variables a bit...
|
|
116 |
if (!$root_script_path) |
|
117 |
{
|
|
118 |
$root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path; |
|
119 |
}
|
|
120 |
||
121 |
$script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; |
|
122 |
$root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; |
|
123 |
||
124 |
$page_array += array( |
|
125 |
'page_name' => $page_name, |
|
126 |
'page_dir' => $page_dir, |
|
127 |
||
128 |
'query_string' => $query_string, |
|
129 |
'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)), |
|
130 |
'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), |
|
131 |
||
132 |
'page' => $page |
|
133 |
);
|
|
134 |
||
135 |
return $page_array; |
|
136 |
}
|
|
137 |
||
138 |
/**
|
|
139 |
* Start session management
|
|
140 |
*
|
|
141 |
* This is where all session activity begins. We gather various pieces of
|
|
142 |
* information from the client and server. We test to see if a session already
|
|
143 |
* exists. If it does, fine and dandy. If it doesn't we'll go on to create a
|
|
144 |
* new one ... pretty logical heh? We also examine the system load (if we're
|
|
145 |
* running on a system which makes such information readily available) and
|
|
146 |
* halt if it's above an admin definable limit.
|
|
147 |
*
|
|
148 |
* @param bool $update_session_page if true the session page gets updated.
|
|
149 |
* This can be set to circumvent certain scripts to update the users last visited page.
|
|
150 |
*/
|
|
151 |
function session_begin($update_session_page = true) |
|
152 |
{
|
|
153 |
global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path; |
|
154 |
||
155 |
// Give us some basic information
|
|
156 |
$this->time_now = time(); |
|
157 |
$this->cookie_data = array('u' => 0, 'k' => ''); |
|
158 |
$this->update_session_page = $update_session_page; |
|
159 |
$this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : ''; |
|
160 |
$this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? (string) $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; |
|
161 |
$this->host = (!empty($_SERVER['HTTP_HOST'])) ? (string) $_SERVER['HTTP_HOST'] : 'localhost'; |
|
162 |
$this->page = $this->extract_current_page($phpbb_root_path); |
|
163 |
||
164 |
// if the forwarded for header shall be checked we have to validate its contents
|
|
165 |
if ($config['forwarded_for_check']) |
|
166 |
{
|
|
167 |
$this->forwarded_for = preg_replace('#, +#', ', ', $this->forwarded_for); |
|
168 |
||
169 |
// split the list of IPs
|
|
170 |
$ips = explode(', ', $this->forwarded_for); |
|
171 |
foreach ($ips as $ip) |
|
172 |
{
|
|
173 |
// check IPv4 first, the IPv6 is hopefully only going to be used very seldomly
|
|
174 |
if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) |
|
175 |
{
|
|
176 |
// contains invalid data, don't use the forwarded for header
|
|
177 |
$this->forwarded_for = ''; |
|
178 |
break; |
|
179 |
}
|
|
180 |
}
|
|
181 |
}
|
|
182 |
||
183 |
// Add forum to the page for tracking online users - also adding a "x" to the end to properly identify the number
|
|
184 |
$this->page['page'] .= (isset($_REQUEST['f'])) ? ((strpos($this->page['page'], '?') !== false) ? '&' : '?') . '_f_=' . (int) $_REQUEST['f'] . 'x' : ''; |
|
185 |
||
186 |
if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u'])) |
|
187 |
{
|
|
188 |
$this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true); |
|
189 |
$this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true); |
|
190 |
$this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true); |
|
191 |
||
192 |
$SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid='; |
|
193 |
$_SID = (defined('NEED_SID')) ? $this->session_id : ''; |
|
194 |
||
195 |
if (empty($this->session_id)) |
|
196 |
{
|
|
197 |
$this->session_id = $_SID = request_var('sid', ''); |
|
198 |
$SID = '?sid=' . $this->session_id; |
|
199 |
$this->cookie_data = array('u' => 0, 'k' => ''); |
|
200 |
}
|
|
201 |
}
|
|
202 |
else
|
|
203 |
{
|
|
204 |
$this->session_id = $_SID = request_var('sid', ''); |
|
205 |
$SID = '?sid=' . $this->session_id; |
|
206 |
}
|
|
207 |
||
208 |
$_EXTRA_URL = array(); |
|
209 |
||
210 |
// Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
|
|
211 |
// it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
|
|
212 |
$this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; |
|
213 |
$this->load = false; |
|
214 |
||
215 |
// Load limit check (if applicable)
|
|
216 |
if ($config['limit_load'] || $config['limit_search_load']) |
|
217 |
{
|
|
218 |
if ($load = @file_get_contents('/proc/loadavg')) |
|
219 |
{
|
|
220 |
$this->load = array_slice(explode(' ', $load), 0, 1); |
|
221 |
$this->load = floatval($this->load[0]); |
|
222 |
}
|
|
223 |
else
|
|
224 |
{
|
|
225 |
set_config('limit_load', '0'); |
|
226 |
set_config('limit_search_load', '0'); |
|
227 |
}
|
|
228 |
}
|
|
229 |
||
230 |
// Is session_id is set or session_id is set and matches the url param if required
|
|
231 |
if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid']))) |
|
232 |
{
|
|
233 |
$sql = 'SELECT u.*, s.* |
|
234 |
FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u |
|
235 |
WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "' |
|
236 |
AND u.user_id = s.session_user_id"; |
|
237 |
$result = $db->sql_query($sql); |
|
238 |
$this->data = $db->sql_fetchrow($result); |
|
239 |
$db->sql_freeresult($result); |
|
240 |
||
241 |
// Did the session exist in the DB?
|
|
242 |
if (isset($this->data['user_id'])) |
|
243 |
{
|
|
244 |
// Validate IP length according to admin ... enforces an IP
|
|
245 |
// check on bots if admin requires this
|
|
246 |
// $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check'];
|
|
247 |
||
248 |
if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) |
|
249 |
{
|
|
250 |
$s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); |
|
251 |
$u_ip = short_ipv6($this->ip, $config['ip_check']); |
|
252 |
}
|
|
253 |
else
|
|
254 |
{
|
|
255 |
$s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); |
|
256 |
$u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); |
|
257 |
}
|
|
258 |
||
259 |
$s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : ''; |
|
260 |
$u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : ''; |
|
261 |
||
262 |
$s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; |
|
263 |
$u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; |
|
264 |
||
265 |
if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) |
|
266 |
{
|
|
267 |
$session_expired = false; |
|
268 |
||
269 |
// Check whether the session is still valid if we have one
|
|
270 |
$method = basename(trim($config['auth_method'])); |
|
271 |
include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); |
|
272 |
||
273 |
$method = 'validate_session_' . $method; |
|
274 |
if (function_exists($method)) |
|
275 |
{
|
|
276 |
if (!$method($this->data)) |
|
277 |
{
|
|
278 |
$session_expired = true; |
|
279 |
}
|
|
280 |
}
|
|
281 |
||
282 |
if (!$session_expired) |
|
283 |
{
|
|
284 |
// Check the session length timeframe if autologin is not enabled.
|
|
285 |
// Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide.
|
|
286 |
if (!$this->data['session_autologin']) |
|
287 |
{
|
|
288 |
if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60)) |
|
289 |
{
|
|
290 |
$session_expired = true; |
|
291 |
}
|
|
292 |
}
|
|
293 |
else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60)) |
|
294 |
{
|
|
295 |
$session_expired = true; |
|
296 |
}
|
|
297 |
}
|
|
298 |
||
299 |
if (!$session_expired) |
|
300 |
{
|
|
301 |
// Only update session DB a minute or so after last update or if page changes
|
|
302 |
if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) |
|
303 |
{
|
|
304 |
$sql_ary = array('session_time' => $this->time_now); |
|
305 |
||
306 |
if ($this->update_session_page) |
|
307 |
{
|
|
308 |
$sql_ary['session_page'] = substr($this->page['page'], 0, 199); |
|
309 |
}
|
|
310 |
||
311 |
$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " |
|
312 |
WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; |
|
313 |
$db->sql_query($sql); |
|
314 |
}
|
|
315 |
||
316 |
$this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; |
|
317 |
$this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; |
|
318 |
$this->data['user_lang'] = basename($this->data['user_lang']); |
|
319 |
||
320 |
return true; |
|
321 |
}
|
|
322 |
}
|
|
323 |
else
|
|
324 |
{
|
|
325 |
// Added logging temporarly to help debug bugs...
|
|
326 |
if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS) |
|
327 |
{
|
|
328 |
add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for)); |
|
329 |
}
|
|
330 |
}
|
|
331 |
}
|
|
332 |
}
|
|
333 |
||
334 |
// If we reach here then no (valid) session exists. So we'll create a new one
|
|
335 |
return $this->session_create(); |
|
336 |
}
|
|
337 |
||
338 |
/**
|
|
339 |
* Create a new session
|
|
340 |
*
|
|
341 |
* If upon trying to start a session we discover there is nothing existing we
|
|
342 |
* jump here. Additionally this method is called directly during login to regenerate
|
|
343 |
* the session for the specific user. In this method we carry out a number of tasks;
|
|
344 |
* garbage collection, (search)bot checking, banned user comparison. Basically
|
|
345 |
* though this method will result in a new session for a specific user.
|
|
346 |
*/
|
|
347 |
function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true) |
|
348 |
{
|
|
349 |
global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx; |
|
350 |
||
351 |
$this->data = array(); |
|
352 |
||
353 |
/* Garbage collection ... remove old sessions updating user information
|
|
354 |
// if necessary. It means (potentially) 11 queries but only infrequently
|
|
355 |
if ($this->time_now > $config['session_last_gc'] + $config['session_gc'])
|
|
356 |
{
|
|
357 |
$this->session_gc();
|
|
358 |
}*/
|
|
359 |
||
360 |
// Do we allow autologin on this board? No? Then override anything
|
|
361 |
// that may be requested here
|
|
362 |
if (!$config['allow_autologin']) |
|
363 |
{
|
|
364 |
$this->cookie_data['k'] = $persist_login = false; |
|
365 |
}
|
|
366 |
||
367 |
/**
|
|
368 |
* Here we do a bot check, oh er saucy! No, not that kind of bot
|
|
369 |
* check. We loop through the list of bots defined by the admin and
|
|
370 |
* see if we have any useragent and/or IP matches. If we do, this is a
|
|
371 |
* bot, act accordingly
|
|
372 |
*/
|
|
373 |
$bot = false; |
|
374 |
$active_bots = $cache->obtain_bots(); |
|
375 |
||
376 |
foreach ($active_bots as $row) |
|
377 |
{
|
|
378 |
if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser)) |
|
379 |
{
|
|
380 |
$bot = $row['user_id']; |
|
381 |
}
|
|
382 |
||
383 |
// If ip is supplied, we will make sure the ip is matching too...
|
|
384 |
if ($row['bot_ip'] && ($bot || !$row['bot_agent'])) |
|
385 |
{
|
|
386 |
// Set bot to false, then we only have to set it to true if it is matching
|
|
387 |
$bot = false; |
|
388 |
||
389 |
foreach (explode(',', $row['bot_ip']) as $bot_ip) |
|
390 |
{
|
|
391 |
if (strpos($this->ip, $bot_ip) === 0) |
|
392 |
{
|
|
393 |
$bot = (int) $row['user_id']; |
|
394 |
break; |
|
395 |
}
|
|
396 |
}
|
|
397 |
}
|
|
398 |
||
399 |
if ($bot) |
|
400 |
{
|
|
401 |
break; |
|
402 |
}
|
|
403 |
}
|
|
404 |
||
405 |
$method = basename(trim($config['auth_method'])); |
|
406 |
include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); |
|
407 |
||
408 |
$method = 'autologin_' . $method; |
|
409 |
if (function_exists($method)) |
|
410 |
{
|
|
411 |
$this->data = $method(); |
|
412 |
||
413 |
if (sizeof($this->data)) |
|
414 |
{
|
|
415 |
$this->cookie_data['k'] = ''; |
|
416 |
$this->cookie_data['u'] = $this->data['user_id']; |
|
417 |
}
|
|
418 |
}
|
|
419 |
||
420 |
// If we're presented with an autologin key we'll join against it.
|
|
421 |
// Else if we've been passed a user_id we'll grab data based on that
|
|
422 |
if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data)) |
|
423 |
{
|
|
424 |
$sql = 'SELECT u.* |
|
425 |
FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k |
|
426 |
WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' |
|
427 |
AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") |
|
428 |
AND k.user_id = u.user_id
|
|
429 |
AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; |
|
430 |
$result = $db->sql_query($sql); |
|
431 |
$this->data = $db->sql_fetchrow($result); |
|
432 |
$db->sql_freeresult($result); |
|
433 |
$bot = false; |
|
434 |
}
|
|
435 |
else if ($user_id !== false && !sizeof($this->data)) |
|
436 |
{
|
|
437 |
$this->cookie_data['k'] = ''; |
|
438 |
$this->cookie_data['u'] = $user_id; |
|
439 |
||
440 |
$sql = 'SELECT * |
|
441 |
FROM ' . USERS_TABLE . ' |
|
442 |
WHERE user_id = ' . (int) $this->cookie_data['u'] . ' |
|
443 |
AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; |
|
444 |
$result = $db->sql_query($sql); |
|
445 |
$this->data = $db->sql_fetchrow($result); |
|
446 |
$db->sql_freeresult($result); |
|
447 |
$bot = false; |
|
448 |
}
|
|
449 |
||
450 |
// If no data was returned one or more of the following occurred:
|
|
451 |
// Key didn't match one in the DB
|
|
452 |
// User does not exist
|
|
453 |
// User is inactive
|
|
454 |
// User is bot
|
|
455 |
if (!sizeof($this->data) || !is_array($this->data)) |
|
456 |
{
|
|
457 |
$this->cookie_data['k'] = ''; |
|
458 |
$this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; |
|
459 |
||
460 |
if (!$bot) |
|
461 |
{
|
|
462 |
$sql = 'SELECT * |
|
463 |
FROM ' . USERS_TABLE . ' |
|
464 |
WHERE user_id = ' . (int) $this->cookie_data['u']; |
|
465 |
}
|
|
466 |
else
|
|
467 |
{
|
|
468 |
// We give bots always the same session if it is not yet expired.
|
|
469 |
$sql = 'SELECT u.*, s.* |
|
470 |
FROM ' . USERS_TABLE . ' u |
|
471 |
LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) |
|
472 |
WHERE u.user_id = ' . (int) $bot; |
|
473 |
}
|
|
474 |
||
475 |
$result = $db->sql_query($sql); |
|
476 |
$this->data = $db->sql_fetchrow($result); |
|
477 |
$db->sql_freeresult($result); |
|
478 |
}
|
|
479 |
||
480 |
if ($this->data['user_id'] != ANONYMOUS && !$bot) |
|
481 |
{
|
|
482 |
$this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time()); |
|
483 |
}
|
|
484 |
else
|
|
485 |
{
|
|
486 |
$this->data['session_last_visit'] = $this->time_now; |
|
487 |
}
|
|
488 |
||
489 |
// Force user id to be integer...
|
|
490 |
$this->data['user_id'] = (int) $this->data['user_id']; |
|
491 |
||
492 |
// At this stage we should have a filled data array, defined cookie u and k data.
|
|
493 |
// data array should contain recent session info if we're a real user and a recent
|
|
494 |
// session exists in which case session_id will also be set
|
|
495 |
||
496 |
// Is user banned? Are they excluded? Won't return on ban, exists within method
|
|
497 |
if ($this->data['user_type'] != USER_FOUNDER) |
|
498 |
{
|
|
499 |
if (!$config['forwarded_for_check']) |
|
500 |
{
|
|
501 |
$this->check_ban($this->data['user_id'], $this->ip); |
|
502 |
}
|
|
503 |
else
|
|
504 |
{
|
|
505 |
$ips = explode(', ', $this->forwarded_for); |
|
506 |
$ips[] = $this->ip; |
|
507 |
$this->check_ban($this->data['user_id'], $ips); |
|
508 |
}
|
|
509 |
}
|
|
510 |
||
511 |
$this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; |
|
512 |
$this->data['is_bot'] = ($bot) ? true : false; |
|
513 |
||
514 |
// If our friend is a bot, we re-assign a previously assigned session
|
|
515 |
if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) |
|
516 |
{
|
|
517 |
// Only assign the current session if the ip, browser and forwarded_for match...
|
|
518 |
if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) |
|
519 |
{
|
|
520 |
$s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); |
|
521 |
$u_ip = short_ipv6($this->ip, $config['ip_check']); |
|
522 |
}
|
|
523 |
else
|
|
524 |
{
|
|
525 |
$s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); |
|
526 |
$u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); |
|
527 |
}
|
|
528 |
||
529 |
$s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : ''; |
|
530 |
$u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : ''; |
|
531 |
||
532 |
$s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; |
|
533 |
$u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; |
|
534 |
||
535 |
if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) |
|
536 |
{
|
|
537 |
$this->session_id = $this->data['session_id']; |
|
538 |
||
539 |
// Only update session DB a minute or so after last update or if page changes
|
|
540 |
if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) |
|
541 |
{
|
|
542 |
$this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; |
|
543 |
||
544 |
$sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0); |
|
545 |
||
546 |
if ($this->update_session_page) |
|
547 |
{
|
|
548 |
$sql_ary['session_page'] = substr($this->page['page'], 0, 199); |
|
549 |
}
|
|
550 |
||
551 |
$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " |
|
552 |
WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; |
|
553 |
$db->sql_query($sql); |
|
554 |
||
555 |
// Update the last visit time
|
|
556 |
$sql = 'UPDATE ' . USERS_TABLE . ' |
|
557 |
SET user_lastvisit = ' . (int) $this->data['session_time'] . ' |
|
558 |
WHERE user_id = ' . (int) $this->data['user_id']; |
|
559 |
$db->sql_query($sql); |
|
560 |
}
|
|
561 |
||
562 |
$SID = '?sid='; |
|
563 |
$_SID = ''; |
|
564 |
return true; |
|
565 |
}
|
|
566 |
else
|
|
567 |
{
|
|
568 |
// If the ip and browser does not match make sure we only have one bot assigned to one session
|
|
569 |
$db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); |
|
570 |
}
|
|
571 |
}
|
|
572 |
||
573 |
$session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; |
|
574 |
$set_admin = ($set_admin && $this->data['is_registered']) ? true : false; |
|
575 |
||
576 |
// Create or update the session
|
|
577 |
$sql_ary = array( |
|
578 |
'session_user_id' => (int) $this->data['user_id'], |
|
579 |
'session_start' => (int) $this->time_now, |
|
580 |
'session_last_visit' => (int) $this->data['session_last_visit'], |
|
581 |
'session_time' => (int) $this->time_now, |
|
582 |
'session_browser' => (string) substr($this->browser, 0, 149), |
|
583 |
'session_forwarded_for' => (string) $this->forwarded_for, |
|
584 |
'session_ip' => (string) $this->ip, |
|
585 |
'session_autologin' => ($session_autologin) ? 1 : 0, |
|
586 |
'session_admin' => ($set_admin) ? 1 : 0, |
|
587 |
'session_viewonline' => ($viewonline) ? 1 : 0, |
|
588 |
);
|
|
589 |
||
590 |
if ($this->update_session_page) |
|
591 |
{
|
|
592 |
$sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); |
|
593 |
}
|
|
594 |
||
595 |
$db->sql_return_on_error(true); |
|
596 |
||
597 |
$sql = 'DELETE |
|
598 |
FROM ' . SESSIONS_TABLE . ' |
|
599 |
WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\' |
|
600 |
AND session_user_id = ' . ANONYMOUS; |
|
601 |
||
602 |
if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows())) |
|
603 |
{
|
|
604 |
// Limit new sessions in 1 minute period (if required)
|
|
605 |
if (empty($this->data['session_time']) && $config['active_sessions']) |
|
606 |
{
|
|
607 |
$sql = 'SELECT COUNT(session_id) AS sessions |
|
608 |
FROM ' . SESSIONS_TABLE . ' |
|
609 |
WHERE session_time >= ' . ($this->time_now - 60); |
|
610 |
$result = $db->sql_query($sql); |
|
611 |
$row = $db->sql_fetchrow($result); |
|
612 |
$db->sql_freeresult($result); |
|
613 |
||
614 |
if ((int) $row['sessions'] > (int) $config['active_sessions']) |
|
615 |
{
|
|
616 |
header('HTTP/1.1 503 Service Unavailable'); |
|
617 |
trigger_error('BOARD_UNAVAILABLE'); |
|
618 |
}
|
|
619 |
}
|
|
620 |
}
|
|
621 |
||
622 |
$this->session_id = $this->data['session_id'] = md5(unique_id()); |
|
623 |
||
624 |
$sql_ary['session_id'] = (string) $this->session_id; |
|
625 |
$sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); |
|
626 |
||
627 |
$sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); |
|
628 |
$db->sql_query($sql); |
|
629 |
||
630 |
$db->sql_return_on_error(false); |
|
631 |
||
632 |
// Regenerate autologin/persistent login key
|
|
633 |
if ($session_autologin) |
|
634 |
{
|
|
635 |
$this->set_login_key(); |
|
636 |
}
|
|
637 |
||
638 |
// refresh data
|
|
639 |
$SID = '?sid=' . $this->session_id; |
|
640 |
$_SID = $this->session_id; |
|
641 |
$this->data = array_merge($this->data, $sql_ary); |
|
642 |
||
643 |
if (!$bot) |
|
644 |
{
|
|
645 |
$cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000); |
|
646 |
||
647 |
$this->set_cookie('u', $this->cookie_data['u'], $cookie_expire); |
|
648 |
$this->set_cookie('k', $this->cookie_data['k'], $cookie_expire); |
|
649 |
$this->set_cookie('sid', $this->session_id, $cookie_expire); |
|
650 |
||
651 |
unset($cookie_expire); |
|
652 |
||
653 |
$sql = 'SELECT COUNT(session_id) AS sessions |
|
654 |
FROM ' . SESSIONS_TABLE . ' |
|
655 |
WHERE session_user_id = ' . (int) $this->data['user_id'] . ' |
|
656 |
AND session_time >= ' . ($this->time_now - $config['form_token_lifetime']); |
|
657 |
$result = $db->sql_query($sql); |
|
658 |
$row = $db->sql_fetchrow($result); |
|
659 |
$db->sql_freeresult($result); |
|
660 |
||
661 |
if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt'])) |
|
662 |
{
|
|
663 |
$this->data['user_form_salt'] = unique_id(); |
|
664 |
// Update the form key
|
|
665 |
$sql = 'UPDATE ' . USERS_TABLE . ' |
|
666 |
SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\' |
|
667 |
WHERE user_id = ' . (int) $this->data['user_id']; |
|
668 |
$db->sql_query($sql); |
|
669 |
}
|
|
670 |
}
|
|
671 |
else
|
|
672 |
{
|
|
673 |
$this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; |
|
674 |
||
675 |
// Update the last visit time
|
|
676 |
$sql = 'UPDATE ' . USERS_TABLE . ' |
|
677 |
SET user_lastvisit = ' . (int) $this->data['session_time'] . ' |
|
678 |
WHERE user_id = ' . (int) $this->data['user_id']; |
|
679 |
$db->sql_query($sql); |
|
680 |
||
681 |
$SID = '?sid='; |
|
682 |
$_SID = ''; |
|
683 |
}
|
|
684 |
||
685 |
return true; |
|
686 |
}
|
|
687 |
||
688 |
/**
|
|
689 |
* Kills a session
|
|
690 |
*
|
|
691 |
* This method does what it says on the tin. It will delete a pre-existing session.
|
|
692 |
* It resets cookie information (destroying any autologin key within that cookie data)
|
|
693 |
* and update the users information from the relevant session data. It will then
|
|
694 |
* grab guest user information.
|
|
695 |
*/
|
|
696 |
function session_kill($new_session = true) |
|
697 |
{
|
|
698 |
global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx; |
|
699 |
||
700 |
$sql = 'DELETE FROM ' . SESSIONS_TABLE . " |
|
701 |
WHERE session_id = '" . $db->sql_escape($this->session_id) . "' |
|
702 |
AND session_user_id = " . (int) $this->data['user_id']; |
|
703 |
$db->sql_query($sql); |
|
704 |
||
705 |
// Allow connecting logout with external auth method logout
|
|
706 |
$method = basename(trim($config['auth_method'])); |
|
707 |
include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); |
|
708 |
||
709 |
$method = 'logout_' . $method; |
|
710 |
if (function_exists($method)) |
|
711 |
{
|
|
712 |
$method($this->data, $new_session); |
|
713 |
}
|
|
714 |
||
715 |
if ($this->data['user_id'] != ANONYMOUS) |
|
716 |
{
|
|
717 |
// Delete existing session, update last visit info first!
|
|
718 |
if (!isset($this->data['session_time'])) |
|
719 |
{
|
|
720 |
$this->data['session_time'] = time(); |
|
721 |
}
|
|
722 |
||
723 |
$sql = 'UPDATE ' . USERS_TABLE . ' |
|
724 |
SET user_lastvisit = ' . (int) $this->data['session_time'] . ' |
|
725 |
WHERE user_id = ' . (int) $this->data['user_id']; |
|
726 |
$db->sql_query($sql); |
|
727 |
||
728 |
if ($this->cookie_data['k']) |
|
729 |
{
|
|
730 |
$sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' |
|
731 |
WHERE user_id = ' . (int) $this->data['user_id'] . " |
|
732 |
AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; |
|
733 |
$db->sql_query($sql); |
|
734 |
}
|
|
735 |
||
736 |
// Reset the data array
|
|
737 |
$this->data = array(); |
|
738 |
||
739 |
$sql = 'SELECT * |
|
740 |
FROM ' . USERS_TABLE . ' |
|
741 |
WHERE user_id = ' . ANONYMOUS; |
|
742 |
$result = $db->sql_query($sql); |
|
743 |
$this->data = $db->sql_fetchrow($result); |
|
744 |
$db->sql_freeresult($result); |
|
745 |
}
|
|
746 |
||
747 |
$cookie_expire = $this->time_now - 31536000; |
|
748 |
$this->set_cookie('u', '', $cookie_expire); |
|
749 |
$this->set_cookie('k', '', $cookie_expire); |
|
750 |
$this->set_cookie('sid', '', $cookie_expire); |
|
751 |
unset($cookie_expire); |
|
752 |
||
753 |
$SID = '?sid='; |
|
754 |
$this->session_id = $_SID = ''; |
|
755 |
||
756 |
// To make sure a valid session is created we create one for the anonymous user
|
|
757 |
if ($new_session) |
|
758 |
{
|
|
759 |
$this->session_create(ANONYMOUS); |
|
760 |
}
|
|
761 |
||
762 |
return true; |
|
763 |
}
|
|
764 |
||
765 |
/**
|
|
766 |
* Session garbage collection
|
|
767 |
*
|
|
768 |
* This looks a lot more complex than it really is. Effectively we are
|
|
769 |
* deleting any sessions older than an admin definable limit. Due to the
|
|
770 |
* way in which we maintain session data we have to ensure we update user
|
|
771 |
* data before those sessions are destroyed. In addition this method
|
|
772 |
* removes autologin key information that is older than an admin defined
|
|
773 |
* limit.
|
|
774 |
*/
|
|
775 |
function session_gc() |
|
776 |
{
|
|
777 |
global $db, $config; |
|
778 |
||
779 |
$batch_size = 10; |
|
780 |
||
781 |
if (!$this->time_now) |
|
782 |
{
|
|
783 |
$this->time_now = time(); |
|
784 |
}
|
|
785 |
||
786 |
// Firstly, delete guest sessions
|
|
787 |
$sql = 'DELETE FROM ' . SESSIONS_TABLE . ' |
|
788 |
WHERE session_user_id = ' . ANONYMOUS . ' |
|
789 |
AND session_time < ' . (int) ($this->time_now - $config['session_length']); |
|
790 |
$db->sql_query($sql); |
|
791 |
||
792 |
// Get expired sessions, only most recent for each user
|
|
793 |
$sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time |
|
794 |
FROM ' . SESSIONS_TABLE . ' |
|
795 |
WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' |
|
796 |
GROUP BY session_user_id, session_page'; |
|
797 |
$result = $db->sql_query_limit($sql, $batch_size); |
|
798 |
||
799 |
$del_user_id = array(); |
|
800 |
$del_sessions = 0; |
|
801 |
||
802 |
while ($row = $db->sql_fetchrow($result)) |
|
803 |
{
|
|
804 |
$sql = 'UPDATE ' . USERS_TABLE . ' |
|
805 |
SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' |
|
806 |
WHERE user_id = " . (int) $row['session_user_id']; |
|
807 |
$db->sql_query($sql); |
|
808 |
||
809 |
$del_user_id[] = (int) $row['session_user_id']; |
|
810 |
$del_sessions++; |
|
811 |
}
|
|
812 |
$db->sql_freeresult($result); |
|
813 |
||
814 |
if (sizeof($del_user_id)) |
|
815 |
{
|
|
816 |
// Delete expired sessions
|
|
817 |
$sql = 'DELETE FROM ' . SESSIONS_TABLE . ' |
|
818 |
WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' |
|
819 |
AND session_time < ' . ($this->time_now - $config['session_length']); |
|
820 |
$db->sql_query($sql); |
|
821 |
}
|
|
822 |
||
823 |
if ($del_sessions < $batch_size) |
|
824 |
{
|
|
825 |
// Less than 10 users, update gc timer ... else we want gc
|
|
826 |
// called again to delete other sessions
|
|
827 |
set_config('session_last_gc', $this->time_now, true); |
|
828 |
||
829 |
if ($config['max_autologin_time']) |
|
830 |
{
|
|
831 |
$sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' |
|
832 |
WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); |
|
833 |
$db->sql_query($sql); |
|
834 |
}
|
|
835 |
$this->confirm_gc(); |
|
836 |
}
|
|
837 |
||
838 |
return; |
|
839 |
}
|
|
840 |
||
841 |
function confirm_gc($type = 0) |
|
842 |
{
|
|
843 |
global $db, $config; |
|
844 |
||
845 |
$sql = 'SELECT DISTINCT c.session_id |
|
846 |
FROM ' . CONFIRM_TABLE . ' c |
|
847 |
LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) |
|
848 |
WHERE s.session_id IS NULL' . |
|
849 |
((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); |
|
850 |
$result = $db->sql_query($sql); |
|
851 |
||
852 |
if ($row = $db->sql_fetchrow($result)) |
|
853 |
{
|
|
854 |
$sql_in = array(); |
|
855 |
do
|
|
856 |
{
|
|
857 |
$sql_in[] = (string) $row['session_id']; |
|
858 |
}
|
|
859 |
while ($row = $db->sql_fetchrow($result)); |
|
860 |
||
861 |
if (sizeof($sql_in)) |
|
862 |
{
|
|
863 |
$sql = 'DELETE FROM ' . CONFIRM_TABLE . ' |
|
864 |
WHERE ' . $db->sql_in_set('session_id', $sql_in); |
|
865 |
$db->sql_query($sql); |
|
866 |
}
|
|
867 |
}
|
|
868 |
$db->sql_freeresult($result); |
|
869 |
}
|
|
870 |
||
871 |
||
872 |
/**
|
|
873 |
* Sets a cookie
|
|
874 |
*
|
|
875 |
* Sets a cookie of the given name with the specified data for the given length of time.
|
|
876 |
*/
|
|
877 |
function set_cookie($name, $cookiedata, $cookietime) |
|
878 |
{
|
|
879 |
global $config; |
|
880 |
||
881 |
$name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); |
|
882 |
$expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); |
|
883 |
$domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; |
|
884 |
||
885 |
header('Set-Cookie: ' . $name_data . '; expires=' . $expire . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false); |
|
886 |
}
|
|
887 |
||
888 |
/**
|
|
889 |
* Check for banned user
|
|
890 |
*
|
|
891 |
* Checks whether the supplied user is banned by id, ip or email. If no parameters
|
|
892 |
* are passed to the method pre-existing session data is used. If $return is false
|
|
893 |
* this routine does not return on finding a banned user, it outputs a relevant
|
|
894 |
* message and stops execution.
|
|
895 |
*
|
|
896 |
* @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs
|
|
897 |
*/
|
|
898 |
function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false) |
|
899 |
{
|
|
900 |
global $config, $db; |
|
901 |
||
902 |
if (defined('IN_CHECK_BAN')) |
|
903 |
{
|
|
904 |
return; |
|
905 |
}
|
|
906 |
||
907 |
$banned = false; |
|
908 |
$cache_ttl = 3600; |
|
909 |
$where_sql = array(); |
|
910 |
||
911 |
$sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end |
|
912 |
FROM ' . BANLIST_TABLE . ' |
|
913 |
WHERE '; |
|
914 |
||
915 |
// Determine which entries to check, only return those
|
|
916 |
if ($user_email === false) |
|
917 |
{
|
|
918 |
$where_sql[] = "ban_email = ''"; |
|
919 |
}
|
|
920 |
||
921 |
if ($user_ips === false) |
|
922 |
{
|
|
923 |
$where_sql[] = "(ban_ip = '' OR ban_exclude = 1)"; |
|
924 |
}
|
|
925 |
||
926 |
if ($user_id === false) |
|
927 |
{
|
|
928 |
$where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)'; |
|
929 |
}
|
|
930 |
else
|
|
931 |
{
|
|
932 |
$cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0; |
|
933 |
$_sql = '(ban_userid = ' . $user_id; |
|
934 |
||
935 |
if ($user_email !== false) |
|
936 |
{
|
|
937 |
$_sql .= " OR ban_email <> ''"; |
|
938 |
}
|
|
939 |
||
940 |
if ($user_ips !== false) |
|
941 |
{
|
|
942 |
$_sql .= " OR ban_ip <> ''"; |
|
943 |
}
|
|
944 |
||
945 |
$_sql .= ')'; |
|
946 |
||
947 |
$where_sql[] = $_sql; |
|
948 |
}
|
|
949 |
||
950 |
$sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : ''; |
|
951 |
$result = $db->sql_query($sql, $cache_ttl); |
|
952 |
||
953 |
$ban_triggered_by = 'user'; |
|
954 |
while ($row = $db->sql_fetchrow($result)) |
|
955 |
{
|
|
956 |
if ($row['ban_end'] && $row['ban_end'] < time()) |
|
957 |
{
|
|
958 |
continue; |
|
959 |
}
|
|
960 |
||
961 |
$ip_banned = false; |
|
962 |
if (!empty($row['ban_ip'])) |
|
963 |
{
|
|
964 |
if (!is_array($user_ips)) |
|
965 |
{
|
|
966 |
$ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips); |
|
967 |
}
|
|
968 |
else
|
|
969 |
{
|
|
970 |
foreach ($user_ips as $user_ip) |
|
971 |
{
|
|
972 |
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip)) |
|
973 |
{
|
|
974 |
$ip_banned = true; |
|
975 |
break; |
|
976 |
}
|
|
977 |
}
|
|
978 |
}
|
|
979 |
}
|
|
980 |
||
981 |
if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || |
|
982 |
$ip_banned || |
|
983 |
(!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email))) |
|
984 |
{
|
|
985 |
if (!empty($row['ban_exclude'])) |
|
986 |
{
|
|
987 |
$banned = false; |
|
988 |
break; |
|
989 |
}
|
|
990 |
else
|
|
991 |
{
|
|
992 |
$banned = true; |
|
993 |
$ban_row = $row; |
|
994 |
||
995 |
if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) |
|
996 |
{
|
|
997 |
$ban_triggered_by = 'user'; |
|
998 |
}
|
|
999 |
else if ($ip_banned) |
|
1000 |
{
|
|
1001 |
$ban_triggered_by = 'ip'; |
|
1002 |
}
|
|
1003 |
else
|
|
1004 |
{
|
|
1005 |
$ban_triggered_by = 'email'; |
|
1006 |
}
|
|
1007 |
||
1008 |
// Don't break. Check if there is an exclude rule for this user
|
|
1009 |
}
|
|
1010 |
}
|
|
1011 |
}
|
|
1012 |
$db->sql_freeresult($result); |
|
1013 |
||
1014 |
if ($banned && !$return) |
|
1015 |
{
|
|
1016 |
global $template; |
|
1017 |
||
1018 |
// If the session is empty we need to create a valid one...
|
|
1019 |
if (empty($this->session_id)) |
|
1020 |
{
|
|
1021 |
// This seems to be no longer needed? - #14971
|
|
1022 |
// $this->session_create(ANONYMOUS);
|
|
1023 |
}
|
|
1024 |
||
1025 |
// Initiate environment ... since it won't be set at this stage
|
|
1026 |
$this->setup(); |
|
1027 |
||
1028 |
// Logout the user, banned users are unable to use the normal 'logout' link
|
|
1029 |
if ($this->data['user_id'] != ANONYMOUS) |
|
1030 |
{
|
|
1031 |
$this->session_kill(); |
|
1032 |
}
|
|
1033 |
||
1034 |
// We show a login box here to allow founders accessing the board if banned by IP
|
|
1035 |
if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS) |
|
1036 |
{
|
|
1037 |
global $phpEx; |
|
1038 |
||
1039 |
$this->setup('ucp'); |
|
1040 |
$this->data['is_registered'] = $this->data['is_bot'] = false; |
|
1041 |
||
1042 |
// Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again.
|
|
1043 |
define('IN_CHECK_BAN', 1); |
|
1044 |
||
1045 |
login_box("index.$phpEx"); |
|
1046 |
||
1047 |
// The false here is needed, else the user is able to circumvent the ban.
|
|
1048 |
$this->session_kill(false); |
|
1049 |
}
|
|
1050 |
||
1051 |
// Ok, we catch the case of an empty session id for the anonymous user...
|
|
1052 |
// This can happen if the user is logging in, banned by username and the login_box() being called "again".
|
|
1053 |
if (empty($this->session_id) && defined('IN_CHECK_BAN')) |
|
1054 |
{
|
|
1055 |
$this->session_create(ANONYMOUS); |
|
1056 |
}
|
|
1057 |
||
1058 |
||
1059 |
// Determine which message to output
|
|
1060 |
$till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; |
|
1061 |
$message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; |
|
1062 |
||
1063 |
$message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>'); |
|
1064 |
$message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; |
|
1065 |
$message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; |
|
1066 |
||
1067 |
// To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again
|
|
1068 |
$this->session_kill(false); |
|
1069 |
||
1070 |
trigger_error($message); |
|
1071 |
}
|
|
1072 |
||
1073 |
return ($banned) ? true : false; |
|
1074 |
}
|
|
1075 |
||
1076 |
/**
|
|
1077 |
* Check if ip is blacklisted
|
|
1078 |
* This should be called only where absolutly necessary
|
|
1079 |
*
|
|
1080 |
* Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
|
|
1081 |
*
|
|
1082 |
* @author satmd (from the php manual)
|
|
1083 |
* @param string $mode register/post - spamcop for example is ommitted for posting
|
|
1084 |
* @return false if ip is not blacklisted, else an array([checked server], [lookup])
|
|
1085 |
*/
|
|
1086 |
function check_dnsbl($mode, $ip = false) |
|
1087 |
{
|
|
1088 |
if ($ip === false) |
|
1089 |
{
|
|
1090 |
$ip = $this->ip; |
|
1091 |
}
|
|
1092 |
||
1093 |
$dnsbl_check = array( |
|
1094 |
'list.dsbl.org' => 'http://dsbl.org/listing?', |
|
1095 |
'sbl-xbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', |
|
1096 |
);
|
|
1097 |
||
1098 |
if ($mode == 'register') |
|
1099 |
{
|
|
1100 |
$dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?'; |
|
1101 |
}
|
|
1102 |
||
1103 |
if ($ip) |
|
1104 |
{
|
|
1105 |
$quads = explode('.', $ip); |
|
1106 |
$reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; |
|
1107 |
||
1108 |
// Need to be listed on all servers...
|
|
1109 |
$listed = true; |
|
1110 |
$info = array(); |
|
1111 |
||
1112 |
foreach ($dnsbl_check as $dnsbl => $lookup) |
|
1113 |
{
|
|
1114 |
if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) |
|
1115 |
{
|
|
1116 |
$info = array($dnsbl, $lookup . $ip); |
|
1117 |
}
|
|
1118 |
else
|
|
1119 |
{
|
|
1120 |
$listed = false; |
|
1121 |
}
|
|
1122 |
}
|
|
1123 |
||
1124 |
if ($listed) |
|
1125 |
{
|
|
1126 |
return $info; |
|
1127 |
}
|
|
1128 |
}
|
|
1129 |
||
1130 |
return false; |
|
1131 |
}
|
|
1132 |
||
1133 |
/**
|
|
1134 |
* Check if URI is blacklisted
|
|
1135 |
* This should be called only where absolutly necessary, for example on the submitted website field
|
|
1136 |
* This function is not in use at the moment and is only included for testing purposes, it may not work at all!
|
|
1137 |
* This means it is untested at the moment and therefore commented out
|
|
1138 |
*
|
|
1139 |
* @param string $uri URI to check
|
|
1140 |
* @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists
|
|
1141 |
function check_uribl($uri)
|
|
1142 |
{
|
|
1143 |
// Normally parse_url() is not intended to parse uris
|
|
1144 |
// We need to get the top-level domain name anyway... change.
|
|
1145 |
$uri = parse_url($uri);
|
|
1146 |
||
1147 |
if ($uri === false || empty($uri['host']))
|
|
1148 |
{
|
|
1149 |
return false;
|
|
1150 |
}
|
|
1151 |
||
1152 |
$uri = trim($uri['host']);
|
|
1153 |
||
1154 |
if ($uri)
|
|
1155 |
{
|
|
1156 |
// One problem here... the return parameter for the "windows" method is different from what
|
|
1157 |
// we expect... this may render this check useless...
|
|
1158 |
if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true)
|
|
1159 |
{
|
|
1160 |
return true;
|
|
1161 |
}
|
|
1162 |
}
|
|
1163 |
||
1164 |
return false;
|
|
1165 |
}
|
|
1166 |
*/
|
|
1167 |
||
1168 |
/**
|
|
1169 |
* Set/Update a persistent login key
|
|
1170 |
*
|
|
1171 |
* This method creates or updates a persistent session key. When a user makes
|
|
1172 |
* use of persistent (formerly auto-) logins a key is generated and stored in the
|
|
1173 |
* DB. When they revisit with the same key it's automatically updated in both the
|
|
1174 |
* DB and cookie. Multiple keys may exist for each user representing different
|
|
1175 |
* browsers or locations. As with _any_ non-secure-socket no passphrase login this
|
|
1176 |
* remains vulnerable to exploit.
|
|
1177 |
*/
|
|
1178 |
function set_login_key($user_id = false, $key = false, $user_ip = false) |
|
1179 |
{
|
|
1180 |
global $config, $db; |
|
1181 |
||
1182 |
$user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; |
|
1183 |
$user_ip = ($user_ip === false) ? $this->ip : $user_ip; |
|
1184 |
$key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key; |
|
1185 |
||
1186 |
$key_id = unique_id(hexdec(substr($this->session_id, 0, 8))); |
|
1187 |
||
1188 |
$sql_ary = array( |
|
1189 |
'key_id' => (string) md5($key_id), |
|
1190 |
'last_ip' => (string) $this->ip, |
|
1191 |
'last_login' => (int) time() |
|
1192 |
);
|
|
1193 |
||
1194 |
if (!$key) |
|
1195 |
{
|
|
1196 |
$sql_ary += array( |
|
1197 |
'user_id' => (int) $user_id |
|
1198 |
);
|
|
1199 |
}
|
|
1200 |
||
1201 |
if ($key) |
|
1202 |
{
|
|
1203 |
$sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . ' |
|
1204 |
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' |
|
1205 |
WHERE user_id = ' . (int) $user_id . " |
|
1206 |
AND key_id = '" . $db->sql_escape(md5($key)) . "'"; |
|
1207 |
}
|
|
1208 |
else
|
|
1209 |
{
|
|
1210 |
$sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); |
|
1211 |
}
|
|
1212 |
$db->sql_query($sql); |
|
1213 |
||
1214 |
$this->cookie_data['k'] = $key_id; |
|
1215 |
||
1216 |
return false; |
|
1217 |
}
|
|
1218 |
||
1219 |
/**
|
|
1220 |
* Reset all login keys for the specified user
|
|
1221 |
*
|
|
1222 |
* This method removes all current login keys for a specified (or the current)
|
|
1223 |
* user. It will be called on password change to render old keys unusable
|
|
1224 |
*/
|
|
1225 |
function reset_login_keys($user_id = false) |
|
1226 |
{
|
|
1227 |
global $config, $db; |
|
1228 |
||
1229 |
$user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; |
|
1230 |
||
1231 |
$sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' |
|
1232 |
WHERE user_id = ' . (int) $user_id; |
|
1233 |
$db->sql_query($sql); |
|
1234 |
||
1235 |
// Let's also clear any current sessions for the specified user_id
|
|
1236 |
// If it's the current user then we'll leave this session intact
|
|
1237 |
$sql_where = 'session_user_id = ' . (int) $user_id; |
|
1238 |
$sql_where .= ($user_id === $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : ''; |
|
1239 |
||
1240 |
$sql = 'DELETE FROM ' . SESSIONS_TABLE . " |
|
1241 |
WHERE $sql_where"; |
|
1242 |
$db->sql_query($sql); |
|
1243 |
||
1244 |
// We're changing the password of the current user and they have a key
|
|
1245 |
// Lets regenerate it to be safe
|
|
1246 |
if ($user_id === $this->data['user_id'] && $this->cookie_data['k']) |
|
1247 |
{
|
|
1248 |
$this->set_login_key($user_id); |
|
1249 |
}
|
|
1250 |
}
|
|
1251 |
}
|
|
1252 |
||
1253 |
||
1254 |
/**
|
|
1255 |
* Base user class
|
|
1256 |
*
|
|
1257 |
* This is the overarching class which contains (through session extend)
|
|
1258 |
* all methods utilised for user functionality during a session.
|
|
1259 |
*
|
|
1260 |
* @package phpBB3
|
|
1261 |
*/
|
|
1262 |
class user extends session |
|
1263 |
{
|
|
1264 |
var $lang = array(); |
|
1265 |
var $help = array(); |
|
1266 |
var $theme = array(); |
|
1267 |
var $date_format; |
|
1268 |
var $timezone; |
|
1269 |
var $dst; |
|
1270 |
||
1271 |
var $lang_name; |
|
1272 |
var $lang_id = false; |
|
1273 |
var $lang_path; |
|
1274 |
var $img_lang; |
|
1275 |
var $img_array = array(); |
|
1276 |
||
1277 |
// Able to add new option (id 7)
|
|
1278 |
var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10); |
|
1279 |
var $keyvalues = array(); |
|
1280 |
||
1281 |
/**
|
|
1282 |
* Setup basic user-specific items (style, language, ...)
|
|
1283 |
*/
|
|
1284 |
function setup($lang_set = false, $style = false) |
|
1285 |
{
|
|
1286 |
global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; |
|
1287 |
||
1288 |
if ($this->data['user_id'] != ANONYMOUS) |
|
1289 |
{
|
|
1290 |
$this->lang_name = (file_exists($phpbb_root_path . 'language/' . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']); |
|
1291 |
$this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/'; |
|
1292 |
||
1293 |
$this->date_format = $this->data['user_dateformat']; |
|
1294 |
$this->timezone = $this->data['user_timezone'] * 3600; |
|
1295 |
$this->dst = $this->data['user_dst'] * 3600; |
|
1296 |
}
|
|
1297 |
else
|
|
1298 |
{
|
|
1299 |
$this->lang_name = basename($config['default_lang']); |
|
1300 |
$this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/'; |
|
1301 |
$this->date_format = $config['default_dateformat']; |
|
1302 |
$this->timezone = $config['board_timezone'] * 3600; |
|
1303 |
$this->dst = $config['board_dst'] * 3600; |
|
1304 |
||
1305 |
/**
|
|
1306 |
* If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
|
|
1307 |
* If re-enabled we need to make sure only those languages installed are checked
|
|
1308 |
* Commented out so we do not loose the code.
|
|
1309 |
||
1310 |
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
|
|
1311 |
{
|
|
1312 |
$accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
|
1313 |
||
1314 |
foreach ($accept_lang_ary as $accept_lang)
|
|
1315 |
{
|
|
1316 |
// Set correct format ... guess full xx_YY form
|
|
1317 |
$accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
|
|
1318 |
$accept_lang = basename($accept_lang);
|
|
1319 |
||
1320 |
if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
|
|
1321 |
{
|
|
1322 |
$this->lang_name = $config['default_lang'] = $accept_lang;
|
|
1323 |
$this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
|
|
1324 |
break;
|
|
1325 |
}
|
|
1326 |
else
|
|
1327 |
{
|
|
1328 |
// No match on xx_YY so try xx
|
|
1329 |
$accept_lang = substr($accept_lang, 0, 2);
|
|
1330 |
$accept_lang = basename($accept_lang);
|
|
1331 |
||
1332 |
if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
|
|
1333 |
{
|
|
1334 |
$this->lang_name = $config['default_lang'] = $accept_lang;
|
|
1335 |
$this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
|
|
1336 |
break;
|
|
1337 |
}
|
|
1338 |
}
|
|
1339 |
}
|
|
1340 |
}
|
|
1341 |
*/
|
|
1342 |
}
|
|
1343 |
||
1344 |
// We include common language file here to not load it every time a custom language file is included
|
|
1345 |
$lang = &$this->lang; |
|
1346 |
||
1347 |
if ((@include $this->lang_path . "common.$phpEx") === false) |
|
1348 |
{
|
|
1349 |
die('Language file ' . $this->lang_name . "/common.$phpEx" . " couldn't be opened."); |
|
1350 |
}
|
|
1351 |
||
1352 |
$this->add_lang($lang_set); |
|
1353 |
unset($lang_set); |
|
1354 |
||
1355 |
if (!empty($_GET['style']) && $auth->acl_get('a_styles')) |
|
1356 |
{
|
|
1357 |
global $SID, $_EXTRA_URL; |
|
1358 |
||
1359 |
$style = request_var('style', 0); |
|
1360 |
$SID .= '&style=' . $style; |
|
1361 |
$_EXTRA_URL = array('style=' . $style); |
|
1362 |
}
|
|
1363 |
else
|
|
1364 |
{
|
|
1365 |
// Set up style
|
|
1366 |
$style = ($style) ? $style : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']); |
|
1367 |
}
|
|
1368 |
||
1369 |
$sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name |
|
1370 |
FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i |
|
1371 |
WHERE s.style_id = $style |
|
1372 |
AND t.template_id = s.template_id
|
|
1373 |
AND c.theme_id = s.theme_id
|
|
1374 |
AND i.imageset_id = s.imageset_id"; |
|
1375 |
$result = $db->sql_query($sql, 3600); |
|
1376 |
$this->theme = $db->sql_fetchrow($result); |
|
1377 |
$db->sql_freeresult($result); |
|
1378 |
||
1379 |
// User has wrong style
|
|
1380 |
if (!$this->theme && $style == $this->data['user_style']) |
|
1381 |
{
|
|
1382 |
$style = $this->data['user_style'] = $config['default_style']; |
|
1383 |
||
1384 |
$sql = 'UPDATE ' . USERS_TABLE . " |
|
1385 |
SET user_style = $style |
|
1386 |
WHERE user_id = {$this->data['user_id']}"; |
|
1387 |
$db->sql_query($sql); |
|
1388 |
||
1389 |
$sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name |
|
1390 |
FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i |
|
1391 |
WHERE s.style_id = $style |
|
1392 |
AND t.template_id = s.template_id
|
|
1393 |
AND c.theme_id = s.theme_id
|
|
1394 |
AND i.imageset_id = s.imageset_id"; |
|
1395 |
$result = $db->sql_query($sql, 3600); |
|
1396 |
$this->theme = $db->sql_fetchrow($result); |
|
1397 |
$db->sql_freeresult($result); |
|
1398 |
}
|
|
1399 |
||
1400 |
if (!$this->theme) |
|
1401 |
{
|
|
1402 |
trigger_error('Could not get style data', E_USER_ERROR); |
|
1403 |
}
|
|
1404 |
||
1405 |
// Now parse the cfg file and cache it
|
|
1406 |
$parsed_items = $cache->obtain_cfg_items($this->theme); |
|
1407 |
||
1408 |
// We are only interested in the theme configuration for now
|
|
1409 |
$parsed_items = $parsed_items['theme']; |
|
1410 |
||
1411 |
$check_for = array( |
|
1412 |
'parse_css_file' => (int) 0, |
|
1413 |
'pagination_sep' => (string) ', ' |
|
1414 |
);
|
|
1415 |
||
1416 |
foreach ($check_for as $key => $default_value) |
|
1417 |
{
|
|
1418 |
$this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; |
|
1419 |
settype($this->theme[$key], gettype($default_value)); |
|
1420 |
||
1421 |
if (is_string($default_value)) |
|
1422 |
{
|
|
1423 |
$this->theme[$key] = htmlspecialchars($this->theme[$key]); |
|
1424 |
}
|
|
1425 |
}
|
|
1426 |
||
1427 |
// If the style author specified the theme needs to be cached
|
|
1428 |
// (because of the used paths and variables) than make sure it is the case.
|
|
1429 |
// For example, if the theme uses language-specific images it needs to be stored in db.
|
|
1430 |
if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file']) |
|
1431 |
{
|
|
1432 |
$this->theme['theme_storedb'] = 1; |
|
1433 |
||
1434 |
$stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css"); |
|
1435 |
// Match CSS imports
|
|
1436 |
$matches = array(); |
|
1437 |
preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches); |
|
1438 |
||
1439 |
if (sizeof($matches)) |
|
1440 |
{
|
|
1441 |
$content = ''; |
|
1442 |
foreach ($matches[0] as $idx => $match) |
|
1443 |
{
|
|
1444 |
if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx])) |
|
1445 |
{
|
|
1446 |
$content = trim($content); |
|
1447 |
}
|
|
1448 |
else
|
|
1449 |
{
|
|
1450 |
$content = ''; |
|
1451 |
}
|
|
1452 |
$stylesheet = str_replace($match, $content, $stylesheet); |
|
1453 |
}
|
|
1454 |
unset($content); |
|
1455 |
}
|
|
1456 |
||
1457 |
$stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet); |
|
1458 |
||
1459 |
$sql_ary = array( |
|
1460 |
'theme_data' => $stylesheet, |
|
1461 |
'theme_mtime' => time(), |
|
1462 |
'theme_storedb' => 1 |
|
1463 |
);
|
|
1464 |
||
1465 |
$sql = 'UPDATE ' . STYLES_THEME_TABLE . ' |
|
1466 |
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' |
|
1467 |
WHERE theme_id = ' . $this->theme['theme_id']; |
|
1468 |
$db->sql_query($sql); |
|
1469 |
||
1470 |
unset($sql_ary); |
|
1471 |
}
|
|
1472 |
||
1473 |
$template->set_template(); |
|
1474 |
||
1475 |
$this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang']; |
|
1476 |
||
1477 |
$sql = 'SELECT image_name, image_filename, image_lang, image_height, image_width |
|
1478 |
FROM ' . STYLES_IMAGESET_DATA_TABLE . ' |
|
1479 |
WHERE imageset_id = ' . $this->theme['imageset_id'] . " |
|
1480 |
AND image_lang IN ('" . $db->sql_escape($this->img_lang) . "', '')"; |
|
1481 |
$result = $db->sql_query($sql, 3600); |
|
1482 |
||
1483 |
$localised_images = false; |
|
1484 |
while ($row = $db->sql_fetchrow($result)) |
|
1485 |
{
|
|
1486 |
if ($row['image_lang']) |
|
1487 |
{
|
|
1488 |
$localised_images = true; |
|
1489 |
}
|
|
1490 |
||
1491 |
$this->img_array[$row['image_name']] = $row; |
|
1492 |
}
|
|
1493 |
$db->sql_freeresult($result); |
|
1494 |
||
1495 |
// there were no localised images, try to refresh the localised imageset for the user's language
|
|
1496 |
if (!$localised_images) |
|
1497 |
{
|
|
1498 |
// Attention: this code ignores the image definition list from acp_styles and just takes everything
|
|
1499 |
// that the config file contains
|
|
1500 |
$sql_ary = array(); |
|
1501 |
||
1502 |
$db->sql_transaction('begin'); |
|
1503 |
||
1504 |
$sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . ' |
|
1505 |
WHERE imageset_id = ' . $this->theme['imageset_id'] . ' |
|
1506 |
AND image_lang = \'' . $db->sql_escape($this->img_lang) . '\''; |
|
1507 |
$result = $db->sql_query($sql); |
|
1508 |
||
1509 |
if (@file_exists("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg")) |
|
1510 |
{
|
|
1511 |
$cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg"); |
|
1512 |
foreach ($cfg_data_imageset_data as $image_name => $value) |
|
1513 |
{
|
|
1514 |
if (strpos($value, '*') !== false) |
|
1515 |
{
|
|
1516 |
if (substr($value, -1, 1) === '*') |
|
1517 |
{
|
|
1518 |
list($image_filename, $image_height) = explode('*', $value); |
|
1519 |
$image_width = 0; |
|
1520 |
}
|
|
1521 |
else
|
|
1522 |
{
|
|
1523 |
list($image_filename, $image_height, $image_width) = explode('*', $value); |
|
1524 |
}
|
|
1525 |
}
|
|
1526 |
else
|
|
1527 |
{
|
|
1528 |
$image_filename = $value; |
|
1529 |
$image_height = $image_width = 0; |
|
1530 |
}
|
|
1531 |
||
1532 |
if (strpos($image_name, 'img_') === 0 && $image_filename) |
|
1533 |
{
|
|
1534 |
$image_name = substr($image_name, 4); |
|
1535 |
$sql_ary[] = array( |
|
1536 |
'image_name' => (string) $image_name, |
|
1537 |
'image_filename' => (string) $image_filename, |
|
1538 |
'image_height' => (int) $image_height, |
|
1539 |
'image_width' => (int) $image_width, |
|
1540 |
'imageset_id' => (int) $this->theme['imageset_id'], |
|
1541 |
'image_lang' => (string) $this->img_lang, |
|
1542 |
);
|
|
1543 |
}
|
|
1544 |
}
|
|
1545 |
}
|
|
1546 |
||
1547 |
if (sizeof($sql_ary)) |
|
1548 |
{
|
|
1549 |
$db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary); |
|
1550 |
$db->sql_transaction('commit'); |
|
1551 |
$cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); |
|
1552 |
||
1553 |
add_log('admin', 'LOG_IMAGESET_LANG_REFRESHED', $this->theme['imageset_name'], $this->img_lang); |
|
1554 |
}
|
|
1555 |
else
|
|
1556 |
{
|
|
1557 |
$db->sql_transaction('commit'); |
|
1558 |
add_log('admin', 'LOG_IMAGESET_LANG_MISSING', $this->theme['imageset_name'], $this->img_lang); |
|
1559 |
}
|
|
1560 |
}
|
|
1561 |
||
1562 |
// Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
|
|
1563 |
// After calling it we continue script execution...
|
|
1564 |
phpbb_user_session_handler(); |
|
1565 |
||
1566 |
// If this function got called from the error handler we are finished here.
|
|
1567 |
if (defined('IN_ERROR_HANDLER')) |
|
1568 |
{
|
|
1569 |
return; |
|
1570 |
}
|
|
1571 |
||
1572 |
// Disable board if the install/ directory is still present
|
|
1573 |
// For the brave development army we do not care about this, else we need to comment out this everytime we develop locally
|
|
1574 |
if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install')) |
|
1575 |
{
|
|
1576 |
// Adjust the message slightly according to the permissions
|
|
1577 |
if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) |
|
1578 |
{
|
|
1579 |
$message = 'REMOVE_INSTALL'; |
|
1580 |
}
|
|
1581 |
else
|
|
1582 |
{
|
|
1583 |
$message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; |
|
1584 |
}
|
|
1585 |
trigger_error($message); |
|
1586 |
}
|
|
1587 |
||
1588 |
// Is board disabled and user not an admin or moderator?
|
|
1589 |
if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) |
|
1590 |
{
|
|
1591 |
header('HTTP/1.1 503 Service Unavailable'); |
|
1592 |
||
1593 |
$message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; |
|
1594 |
trigger_error($message); |
|
1595 |
}
|
|
1596 |
||
1597 |
// Is load exceeded?
|
|
1598 |
if ($config['limit_load'] && $this->load !== false) |
|
1599 |
{
|
|
1600 |
if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN')) |
|
1601 |
{
|
|
1602 |
// Set board disabled to true to let the admins/mods get the proper notification
|
|
1603 |
$config['board_disable'] = '1'; |
|
1604 |
||
1605 |
if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) |
|
1606 |
{
|
|
1607 |
header('HTTP/1.1 503 Service Unavailable'); |
|
1608 |
trigger_error('BOARD_UNAVAILABLE'); |
|
1609 |
}
|
|
1610 |
}
|
|
1611 |
}
|
|
1612 |
||
1613 |
if (isset($this->data['session_viewonline'])) |
|
1614 |
{
|
|
1615 |
// Make sure the user is able to hide his session
|
|
1616 |
if (!$this->data['session_viewonline']) |
|
1617 |
{
|
|
1618 |
// Reset online status if not allowed to hide the session...
|
|
1619 |
if (!$auth->acl_get('u_hideonline')) |
|
1620 |
{
|
|
1621 |
$sql = 'UPDATE ' . SESSIONS_TABLE . ' |
|
1622 |
SET session_viewonline = 1
|
|
1623 |
WHERE session_user_id = ' . $this->data['user_id']; |
|
1624 |
$db->sql_query($sql); |
|
1625 |
$this->data['session_viewonline'] = 1; |
|
1626 |
}
|
|
1627 |
}
|
|
1628 |
else if (!$this->data['user_allow_viewonline']) |
|
1629 |
{
|
|
1630 |
// the user wants to hide and is allowed to -> cloaking device on.
|
|
1631 |
if ($auth->acl_get('u_hideonline')) |
|
1632 |
{
|
|
1633 |
$sql = 'UPDATE ' . SESSIONS_TABLE . ' |
|
1634 |
SET session_viewonline = 0
|
|
1635 |
WHERE session_user_id = ' . $this->data['user_id']; |
|
1636 |
$db->sql_query($sql); |
|
1637 |
$this->data['session_viewonline'] = 0; |
|
1638 |
}
|
|
1639 |
}
|
|
1640 |
}
|
|
1641 |
||
1642 |
||
1643 |
// Does the user need to change their password? If so, redirect to the
|
|
1644 |
// ucp profile reg_details page ... of course do not redirect if we're already in the ucp
|
|
1645 |
if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && $this->data['is_registered'] && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) |
|
1646 |
{
|
|
1647 |
if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") |
|
1648 |
{
|
|
1649 |
redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=reg_details')); |
|
1650 |
}
|
|
1651 |
}
|
|
1652 |
||
1653 |
return; |
|
1654 |
}
|
|
1655 |
||
1656 |
/**
|
|
1657 |
* Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
|
|
1658 |
*
|
|
1659 |
* @param mixed $lang_set specifies the language entries to include
|
|
1660 |
* @param bool $use_db internal variable for recursion, do not use
|
|
1661 |
* @param bool $use_help internal variable for recursion, do not use
|
|
1662 |
*
|
|
1663 |
* Examples:
|
|
1664 |
* <code>
|
|
1665 |
* $lang_set = array('posting', 'help' => 'faq');
|
|
1666 |
* $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
|
|
1667 |
* $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
|
|
1668 |
* $lang_set = 'posting'
|
|
1669 |
* $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
|
|
1670 |
* </code>
|
|
1671 |
*/
|
|
1672 |
function add_lang($lang_set, $use_db = false, $use_help = false) |
|
1673 |
{
|
|
1674 |
global $phpEx; |
|
1675 |
||
1676 |
if (is_array($lang_set)) |
|
1677 |
{
|
|
1678 |
foreach ($lang_set as $key => $lang_file) |
|
1679 |
{
|
|
1680 |
// Please do not delete this line.
|
|
1681 |
// We have to force the type here, else [array] language inclusion will not work
|
|
1682 |
$key = (string) $key; |
|
1683 |
||
1684 |
if ($key == 'db') |
|
1685 |
{
|
|
1686 |
$this->add_lang($lang_file, true, $use_help); |
|
1687 |
}
|
|
1688 |
else if ($key == 'help') |
|
1689 |
{
|
|
1690 |
$this->add_lang($lang_file, $use_db, true); |
|
1691 |
}
|
|
1692 |
else if (!is_array($lang_file)) |
|
1693 |
{
|
|
1694 |
$this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help); |
|
1695 |
}
|
|
1696 |
else
|
|
1697 |
{
|
|
1698 |
$this->add_lang($lang_file, $use_db, $use_help); |
|
1699 |
}
|
|
1700 |
}
|
|
1701 |
unset($lang_set); |
|
1702 |
}
|
|
1703 |
else if ($lang_set) |
|
1704 |
{
|
|
1705 |
$this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help); |
|
1706 |
}
|
|
1707 |
}
|
|
1708 |
||
1709 |
/**
|
|
1710 |
* Set language entry (called by add_lang)
|
|
1711 |
* @access private
|
|
1712 |
*/
|
|
1713 |
function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false) |
|
1714 |
{
|
|
1715 |
global $phpEx; |
|
1716 |
||
1717 |
// Make sure the language path is set (if the user setup did not happen it is not set)
|
|
1718 |
if (!$this->lang_path) |
|
1719 |
{
|
|
1720 |
global $phpbb_root_path, $config; |
|
1721 |
||
1722 |
$this->lang_path = $phpbb_root_path . 'language/' . basename($config['default_lang']) . '/'; |
|
1723 |
}
|
|
1724 |
||
1725 |
// $lang == $this->lang
|
|
1726 |
// $help == $this->help
|
|
1727 |
// - add appropriate variables here, name them as they are used within the language file...
|
|
1728 |
if (!$use_db) |
|
1729 |
{
|
|
1730 |
if ($use_help && strpos($lang_file, '/') !== false) |
|
1731 |
{
|
|
1732 |
$language_filename = $this->lang_path . substr($lang_file, 0, stripos($lang_file, '/') + 1) . 'help_' . substr($lang_file, stripos($lang_file, '/') + 1) . '.' . $phpEx; |
|
1733 |
}
|
|
1734 |
else
|
|
1735 |
{
|
|
1736 |
$language_filename = $this->lang_path . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx; |
|
1737 |
}
|
|
1738 |
||
1739 |
if ((@include $language_filename) === false) |
|
1740 |
{
|
|
1741 |
trigger_error('Language file ' . basename($language_filename) . ' couldn\'t be opened.', E_USER_ERROR); |
|
1742 |
}
|
|
1743 |
}
|
|
1744 |
else if ($use_db) |
|
1745 |
{
|
|
1746 |
// Get Database Language Strings
|
|
1747 |
// Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
|
|
1748 |
// For example: help:faq, posting
|
|
1749 |
}
|
|
1750 |
}
|
|
1751 |
||
1752 |
/**
|
|
1753 |
* Format user date
|
|
1754 |
*/
|
|
1755 |
function format_date($gmepoch, $format = false, $forcedate = false) |
|
1756 |
{
|
|
1757 |
static $midnight; |
|
1758 |
||
1759 |
$lang_dates = $this->lang['datetime']; |
|
1760 |
$format = (!$format) ? $this->date_format : $format; |
|
1761 |
||
1762 |
// Short representation of month in format
|
|
1763 |
if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false)) |
|
1764 |
{
|
|
1765 |
$lang_dates['May'] = $lang_dates['May_short']; |
|
1766 |
}
|
|
1767 |
||
1768 |
unset($lang_dates['May_short']); |
|
1769 |
||
1770 |
if (!$midnight) |
|
1771 |
{
|
|
1772 |
list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $this->timezone + $this->dst)); |
|
1773 |
$midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst; |
|
1774 |
}
|
|
1775 |
||
1776 |
if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate)) |
|
1777 |
{
|
|
1778 |
return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates); |
|
1779 |
}
|
|
1780 |
||
1781 |
if ($gmepoch > $midnight + 86400 && !$forcedate) |
|
1782 |
{
|
|
1783 |
$format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); |
|
1784 |
return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); |
|
1785 |
}
|
|
1786 |
else if ($gmepoch > $midnight && !$forcedate) |
|
1787 |
{
|
|
1788 |
$format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); |
|
1789 |
return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); |
|
1790 |
}
|
|
1791 |
else if ($gmepoch > $midnight - 86400 && !$forcedate) |
|
1792 |
{
|
|
1793 |
$format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); |
|
1794 |
return str_replace('||', $this->lang['datetime']['YESTERDAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); |
|
1795 |
}
|
|
1796 |
||
1797 |
return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates); |
|
1798 |
}
|
|
1799 |
||
1800 |
/**
|
|
1801 |
* Get language id currently used by the user
|
|
1802 |
*/
|
|
1803 |
function get_iso_lang_id() |
|
1804 |
{
|
|
1805 |
global $config, $db; |
|
1806 |
||
1807 |
if (!empty($this->lang_id)) |
|
1808 |
{
|
|
1809 |
return $this->lang_id; |
|
1810 |
}
|
|
1811 |
||
1812 |
if (!$this->lang_name) |
|
1813 |
{
|
|
1814 |
$this->lang_name = $config['default_lang']; |
|
1815 |
}
|
|
1816 |
||
1817 |
$sql = 'SELECT lang_id |
|
1818 |
FROM ' . LANG_TABLE . " |
|
1819 |
WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'"; |
|
1820 |
$result = $db->sql_query($sql); |
|
1821 |
$this->lang_id = (int) $db->sql_fetchfield('lang_id'); |
|
1822 |
$db->sql_freeresult($result); |
|
1823 |
||
1824 |
return $this->lang_id; |
|
1825 |
}
|
|
1826 |
||
1827 |
/**
|
|
1828 |
* Get users profile fields
|
|
1829 |
*/
|
|
1830 |
function get_profile_fields($user_id) |
|
1831 |
{
|
|
1832 |
global $db; |
|
1833 |
||
1834 |
if (isset($this->profile_fields)) |
|
1835 |
{
|
|
1836 |
return; |
|
1837 |
}
|
|
1838 |
||
1839 |
$sql = 'SELECT * |
|
1840 |
FROM ' . PROFILE_FIELDS_DATA_TABLE . " |
|
1841 |
WHERE user_id = $user_id"; |
|
1842 |
$result = $db->sql_query_limit($sql, 1); |
|
1843 |
$this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row; |
|
1844 |
$db->sql_freeresult($result); |
|
1845 |
}
|
|
1846 |
||
1847 |
/**
|
|
1848 |
* Specify/Get image
|
|
1849 |
*/
|
|
1850 |
function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag') |
|
1851 |
{
|
|
1852 |
static $imgs; |
|
1853 |
global $phpbb_root_path; |
|
1854 |
||
1855 |
$img_data = &$imgs[$img]; |
|
1856 |
||
1857 |
if (empty($img_data)) |
|
1858 |
{
|
|
1859 |
if (!isset($this->img_array[$img])) |
|
1860 |
{
|
|
1861 |
// Do not fill the image to let designers decide what to do if the image is empty
|
|
1862 |
$img_data = ''; |
|
1863 |
return $img_data; |
|
1864 |
}
|
|
1865 |
||
1866 |
$img_data['src'] = $phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; |
|
1867 |
$img_data['width'] = $this->img_array[$img]['image_width']; |
|
1868 |
$img_data['height'] = $this->img_array[$img]['image_height']; |
|
1869 |
}
|
|
1870 |
||
1871 |
$alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; |
|
1872 |
||
1873 |
switch ($type) |
|
1874 |
{
|
|
1875 |
case 'src': |
|
1876 |
return $img_data['src']; |
|
1877 |
break; |
|
1878 |
||
1879 |
case 'width': |
|
1880 |
return ($width === false) ? $img_data['width'] : $width; |
|
1881 |
break; |
|
1882 |
||
1883 |
case 'height': |
|
1884 |
return $img_data['height']; |
|
1885 |
break; |
|
1886 |
||
1887 |
default: |
|
1888 |
$use_width = ($width === false) ? $img_data['width'] : $width; |
|
1889 |
||
1890 |
return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; |
|
1891 |
break; |
|
1892 |
}
|
|
1893 |
}
|
|
1894 |
||
1895 |
/**
|
|
1896 |
* Get option bit field from user options
|
|
1897 |
*/
|
|
1898 |
function optionget($key, $data = false) |
|
1899 |
{
|
|
1900 |
if (!isset($this->keyvalues[$key])) |
|
1901 |
{
|
|
1902 |
$var = ($data) ? $data : $this->data['user_options']; |
|
1903 |
$this->keyvalues[$key] = ($var & 1 << $this->keyoptions[$key]) ? true : false; |
|
1904 |
}
|
|
1905 |
||
1906 |
return $this->keyvalues[$key]; |
|
1907 |
}
|
|
1908 |
||
1909 |
/**
|
|
1910 |
* Set option bit field for user options
|
|
1911 |
*/
|
|
1912 |
function optionset($key, $value, $data = false) |
|
1913 |
{
|
|
1914 |
$var = ($data) ? $data : $this->data['user_options']; |
|
1915 |
||
1916 |
if ($value && !($var & 1 << $this->keyoptions[$key])) |
|
1917 |
{
|
|
1918 |
$var += 1 << $this->keyoptions[$key]; |
|
1919 |
}
|
|
1920 |
else if (!$value && ($var & 1 << $this->keyoptions[$key])) |
|
1921 |
{
|
|
1922 |
$var -= 1 << $this->keyoptions[$key]; |
|
1923 |
}
|
|
1924 |
else
|
|
1925 |
{
|
|
1926 |
return ($data) ? $var : false; |
|
1927 |
}
|
|
1928 |
||
1929 |
if (!$data) |
|
1930 |
{
|
|
1931 |
$this->data['user_options'] = $var; |
|
1932 |
return true; |
|
1933 |
}
|
|
1934 |
else
|
|
1935 |
{
|
|
1936 |
return $var; |
|
1937 |
}
|
|
1938 |
}
|
|
1939 |
}
|
|
1940 |
||
1941 |
?>
|