~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to www/php/phpBB3/includes/session.php

  • Committer: mattgiuca
  • Date: 2008-02-15 04:45:12 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:472
db.py: No longer exceptions if password is not supplied.
makeuser: Converted explicit args into kwargs which are simply forwarded along
    to db. Makeuser db NO LONGER accepts "force" argument (which used to
    delete and replace login rows). This is dangerous, and we have removed the
    delete user functionality altogether - because we never delete users.
makeuser.py (script): Major change. Replaced the command-line interface so it
    now only takes 3 required arguments, and a bunch of optional arguments
    getopts style.
    All the arguments are specified at the top; the rest of the code works
    with these data structures so they are only specified in one place
    (including all the work of putting them into a dict and passing it to the
    database).
    Note that makeuser.py is a *second* point of control for the list of the
    login fields (the other is in db.DB.login_fields_list). This is by design,
    because there is a semantic difference between "what fields are in the db"
    and "what arguments should we accept on the command line".

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
                // Shared secret between IVLE and the Forum
 
361
                $ivle_secret = 'VERYSECRET';
 
362
 
 
363
                // Shared Cookie
 
364
                $ivle_cookie = $_COOKIE['ivlecookie'];
 
365
    
 
366
                // Decode and unescape the Cookie contents
 
367
                $cookie = explode(':',$ivle_cookie);
 
368
                $ivle_uid = preg_replace('/\\\(.)/','$1',$cookie[0]);
 
369
                $ivle_nick = preg_replace('/\\\(.)/','$1',$cookie[1]);
 
370
                $ivle_email = preg_replace('/\\\(.)/','$1',$cookie[2]);
 
371
                $ivle_hash = preg_replace('/\\\(.)/','$1',$cookie[3]);
 
372
    
 
373
                // Check if uid + nick + email + secret is the same as the hash
 
374
                $ivle_auth = False; // Flag just incase anything else need to know
 
375
                if (md5($ivle_uid.$ivle_nick.$ivle_email.$ivle_secret) == $ivle_hash) {
 
376
                        $ivle_auth = True;
 
377
    
 
378
                        // Check if the user exists in the database
 
379
                        $sql = 'SELECT user_id
 
380
                                        FROM ' . USERS_TABLE . '
 
381
                                        WHERE username = "' . $db->sql_escape($ivle_uid) . '";';
 
382
                        $result = $db->sql_query($sql);
 
383
                        $row = $db->sql_fetchrow($result);
 
384
                        $user_id = $row['user_id'];
 
385
                        $db->sql_freeresult($result);
 
386
 
 
387
                        // If no user_id is found for the username, create a new user
 
388
                        if(!$user_id) {
 
389
                    // Needed for IVLE auth overide
 
390
                    include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx);
 
391
          
 
392
                                // Get the default group
 
393
                                $sql = 'SELECT group_id
 
394
                                                FROM ' . GROUPS_TABLE . "
 
395
                                                WHERE group_name = '" . $db->sql_escape('REGISTERED') . "'
 
396
                                                AND group_type = " . GROUP_SPECIAL;
 
397
                                $result = $db->sql_query($sql);
 
398
                                $row = $db->sql_fetchrow($result);
 
399
                                $db->sql_freeresult($result);
 
400
 
 
401
                                if (!$row) {
 
402
                                        trigger_error('NO_GROUP');
 
403
                                }
 
404
 
 
405
                                $group_id = $row['group_id'];
 
406
 
 
407
                                // Get the Time and Timezone
 
408
                                $timezone = date('Z') / 3600;
 
409
                                $is_dst = date('I');
 
410
                                $timezone = ($is_dst) ? $timezone - 1 : $timezone;
 
411
 
 
412
                                $user_row = array(
 
413
                                        'username'                              => $ivle_uid,
 
414
                                        'user_password'                 => '', # Not a valid hash
 
415
                                        'user_email'                    => $ivle_email,
 
416
                                        'group_id'                              => (int) $group_id,
 
417
                                        'user_timezone'                 => (float) $timezone,
 
418
                                        'user_dst'                              => $is_dst,
 
419
                                        'user_lang'                             => 'en',
 
420
                                        'user_type'                             => USER_NORMAL,
 
421
                                        'user_actkey'                   => '',
 
422
                                        'user_ip'                               => $this->ip,
 
423
                                        'user_regdate'                  => time(),
 
424
                                        'user_inactive_reason'  => 0,
 
425
                                        'user_inactive_time'    => 0,
 
426
                                );
 
427
         
 
428
                                // Add user
 
429
                                $user_id = user_add($user_row);
 
430
                        }
 
431
                }
 
432
                /* IVLE: End of IVLE Code */
 
433
 
 
434
 
 
435
                // Do we allow autologin on this board? No? Then override anything
 
436
                // that may be requested here
 
437
                if (!$config['allow_autologin'])
 
438
                {
 
439
                        $this->cookie_data['k'] = $persist_login = false;
 
440
                }
 
441
 
 
442
                /**
 
443
                * Here we do a bot check, oh er saucy! No, not that kind of bot
 
444
                * check. We loop through the list of bots defined by the admin and
 
445
                * see if we have any useragent and/or IP matches. If we do, this is a
 
446
                * bot, act accordingly
 
447
                */
 
448
                $bot = false;
 
449
                $active_bots = $cache->obtain_bots();
 
450
 
 
451
                foreach ($active_bots as $row)
 
452
                {
 
453
                        if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser))
 
454
                        {
 
455
                                $bot = $row['user_id'];
 
456
                        }
 
457
 
 
458
                        // If ip is supplied, we will make sure the ip is matching too...
 
459
                        if ($row['bot_ip'] && ($bot || !$row['bot_agent']))
 
460
                        {
 
461
                                // Set bot to false, then we only have to set it to true if it is matching
 
462
                                $bot = false;
 
463
 
 
464
                                foreach (explode(',', $row['bot_ip']) as $bot_ip)
 
465
                                {
 
466
                                        if (strpos($this->ip, $bot_ip) === 0)
 
467
                                        {
 
468
                                                $bot = (int) $row['user_id'];
 
469
                                                break;
 
470
                                        }
 
471
                                }
 
472
                        }
 
473
 
 
474
                        if ($bot)
 
475
                        {
 
476
                                break;
 
477
                        }
 
478
                }
 
479
 
 
480
                $method = basename(trim($config['auth_method']));
 
481
                include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
 
482
 
 
483
                $method = 'autologin_' . $method;
 
484
                if (function_exists($method))
 
485
                {
 
486
                        $this->data = $method();
 
487
 
 
488
                        if (sizeof($this->data))
 
489
                        {
 
490
                                $this->cookie_data['k'] = '';
 
491
                                $this->cookie_data['u'] = $this->data['user_id'];
 
492
                        }
 
493
                }
 
494
 
 
495
                // If we're presented with an autologin key we'll join against it.
 
496
                // Else if we've been passed a user_id we'll grab data based on that
 
497
                if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
 
498
                {
 
499
                        $sql = 'SELECT u.*
 
500
                                FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
 
501
                                WHERE u.user_id = ' . (int) $this->cookie_data['u'] . '
 
502
                                        AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
 
503
                                        AND k.user_id = u.user_id
 
504
                                        AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
 
505
                        $result = $db->sql_query($sql);
 
506
                        $this->data = $db->sql_fetchrow($result);
 
507
                        $db->sql_freeresult($result);
 
508
                        $bot = false;
 
509
                }
 
510
                else if ($user_id !== false && !sizeof($this->data))
 
511
                {
 
512
                        $this->cookie_data['k'] = '';
 
513
                        $this->cookie_data['u'] = $user_id;
 
514
 
 
515
                        $sql = 'SELECT *
 
516
                                FROM ' . USERS_TABLE . '
 
517
                                WHERE user_id = ' . (int) $this->cookie_data['u'] . '
 
518
                                        AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
 
519
                        $result = $db->sql_query($sql);
 
520
                        $this->data = $db->sql_fetchrow($result);
 
521
                        $db->sql_freeresult($result);
 
522
                        $bot = false;
 
523
                }
 
524
 
 
525
                // If no data was returned one or more of the following occurred:
 
526
                // Key didn't match one in the DB
 
527
                // User does not exist
 
528
                // User is inactive
 
529
                // User is bot
 
530
                if (!sizeof($this->data) || !is_array($this->data))
 
531
                {
 
532
                        $this->cookie_data['k'] = '';
 
533
                        $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;
 
534
 
 
535
                        if (!$bot)
 
536
                        {
 
537
                                $sql = 'SELECT *
 
538
                                        FROM ' . USERS_TABLE . '
 
539
                                        WHERE user_id = ' . (int) $this->cookie_data['u'];
 
540
                        }
 
541
                        else
 
542
                        {
 
543
                                // We give bots always the same session if it is not yet expired.
 
544
                                $sql = 'SELECT u.*, s.*
 
545
                                        FROM ' . USERS_TABLE . ' u
 
546
                                        LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id)
 
547
                                        WHERE u.user_id = ' . (int) $bot;
 
548
                        }
 
549
 
 
550
                        $result = $db->sql_query($sql);
 
551
                        $this->data = $db->sql_fetchrow($result);
 
552
                        $db->sql_freeresult($result);
 
553
                }
 
554
 
 
555
                if ($this->data['user_id'] != ANONYMOUS && !$bot)
 
556
                {
 
557
                        $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());
 
558
                }
 
559
                else
 
560
                {
 
561
                        $this->data['session_last_visit'] = $this->time_now;
 
562
                }
 
563
 
 
564
                // Force user id to be integer...
 
565
                $this->data['user_id'] = (int) $this->data['user_id'];
 
566
 
 
567
                // At this stage we should have a filled data array, defined cookie u and k data.
 
568
                // data array should contain recent session info if we're a real user and a recent
 
569
                // session exists in which case session_id will also be set
 
570
 
 
571
                // Is user banned? Are they excluded? Won't return on ban, exists within method
 
572
                if ($this->data['user_type'] != USER_FOUNDER)
 
573
                {
 
574
                        if (!$config['forwarded_for_check'])
 
575
                        {
 
576
                                $this->check_ban($this->data['user_id'], $this->ip);
 
577
                        }
 
578
                        else
 
579
                        {
 
580
                                $ips = explode(', ', $this->forwarded_for);
 
581
                                $ips[] = $this->ip;
 
582
                                $this->check_ban($this->data['user_id'], $ips);
 
583
                        }
 
584
                }
 
585
 
 
586
                $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
 
587
                $this->data['is_bot'] = ($bot) ? true : false;
 
588
 
 
589
                // If our friend is a bot, we re-assign a previously assigned session
 
590
                if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id'])
 
591
                {
 
592
                        // Only assign the current session if the ip, browser and forwarded_for match...
 
593
                        if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
 
594
                        {
 
595
                                $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
 
596
                                $u_ip = short_ipv6($this->ip, $config['ip_check']);
 
597
                        }
 
598
                        else
 
599
                        {
 
600
                                $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
 
601
                                $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
 
602
                        }
 
603
 
 
604
                        $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : '';
 
605
                        $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : '';
 
606
 
 
607
                        $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
 
608
                        $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
 
609
 
 
610
                        if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
 
611
                        {
 
612
                                $this->session_id = $this->data['session_id'];
 
613
 
 
614
                                // Only update session DB a minute or so after last update or if page changes
 
615
                                if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
 
616
                                {
 
617
                                        $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
 
618
 
 
619
                                        $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0);
 
620
 
 
621
                                        if ($this->update_session_page)
 
622
                                        {
 
623
                                                $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
 
624
                                        }
 
625
 
 
626
                                        $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
 
627
                                                WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
 
628
                                        $db->sql_query($sql);
 
629
 
 
630
                                        // Update the last visit time
 
631
                                        $sql = 'UPDATE ' . USERS_TABLE . '
 
632
                                                SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 
633
                                                WHERE user_id = ' . (int) $this->data['user_id'];
 
634
                                        $db->sql_query($sql);
 
635
                                }
 
636
 
 
637
                                $SID = '?sid=';
 
638
                                $_SID = '';
 
639
                                return true;
 
640
                        }
 
641
                        else
 
642
                        {
 
643
                                // If the ip and browser does not match make sure we only have one bot assigned to one session
 
644
                                $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']);
 
645
                        }
 
646
                }
 
647
 
 
648
                $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;
 
649
                $set_admin = ($set_admin && $this->data['is_registered']) ? true : false;
 
650
 
 
651
                // Create or update the session
 
652
                $sql_ary = array(
 
653
                        'session_user_id'               => (int) $this->data['user_id'],
 
654
                        'session_start'                 => (int) $this->time_now,
 
655
                        'session_last_visit'    => (int) $this->data['session_last_visit'],
 
656
                        'session_time'                  => (int) $this->time_now,
 
657
                        'session_browser'               => (string) substr($this->browser, 0, 149),
 
658
                        'session_forwarded_for' => (string) $this->forwarded_for,
 
659
                        'session_ip'                    => (string) $this->ip,
 
660
                        'session_autologin'             => ($session_autologin) ? 1 : 0,
 
661
                        'session_admin'                 => ($set_admin) ? 1 : 0,
 
662
                        'session_viewonline'    => ($viewonline) ? 1 : 0,
 
663
                );
 
664
 
 
665
                if ($this->update_session_page)
 
666
                {
 
667
                        $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
 
668
                }
 
669
 
 
670
                $db->sql_return_on_error(true);
 
671
 
 
672
                $sql = 'DELETE
 
673
                        FROM ' . SESSIONS_TABLE . '
 
674
                        WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'
 
675
                                AND session_user_id = ' . ANONYMOUS;
 
676
 
 
677
                if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()))
 
678
                {
 
679
                        // Limit new sessions in 1 minute period (if required)
 
680
                        if (empty($this->data['session_time']) && $config['active_sessions'])
 
681
                        {
 
682
                                $sql = 'SELECT COUNT(session_id) AS sessions
 
683
                                        FROM ' . SESSIONS_TABLE . '
 
684
                                        WHERE session_time >= ' . ($this->time_now - 60);
 
685
                                $result = $db->sql_query($sql);
 
686
                                $row = $db->sql_fetchrow($result);
 
687
                                $db->sql_freeresult($result);
 
688
 
 
689
                                if ((int) $row['sessions'] > (int) $config['active_sessions'])
 
690
                                {
 
691
                                        header('HTTP/1.1 503 Service Unavailable');
 
692
                                        trigger_error('BOARD_UNAVAILABLE');
 
693
                                }
 
694
                        }
 
695
                }
 
696
 
 
697
                $this->session_id = $this->data['session_id'] = md5(unique_id());
 
698
 
 
699
                $sql_ary['session_id'] = (string) $this->session_id;
 
700
                $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
 
701
 
 
702
                $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
 
703
                $db->sql_query($sql);
 
704
 
 
705
                $db->sql_return_on_error(false);
 
706
 
 
707
                // Regenerate autologin/persistent login key
 
708
                if ($session_autologin)
 
709
                {
 
710
                        $this->set_login_key();
 
711
                }
 
712
 
 
713
                // refresh data
 
714
                $SID = '?sid=' . $this->session_id;
 
715
                $_SID = $this->session_id;
 
716
                $this->data = array_merge($this->data, $sql_ary);
 
717
 
 
718
                if (!$bot)
 
719
                {
 
720
                        $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000);
 
721
 
 
722
                        $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire);
 
723
                        $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire);
 
724
                        $this->set_cookie('sid', $this->session_id, $cookie_expire);
 
725
 
 
726
                        unset($cookie_expire);
 
727
                        
 
728
                        $sql = 'SELECT COUNT(session_id) AS sessions
 
729
                                        FROM ' . SESSIONS_TABLE . '
 
730
                                        WHERE session_user_id = ' . (int) $this->data['user_id'] . '
 
731
                                        AND session_time >= ' . ($this->time_now - $config['form_token_lifetime']);
 
732
                        $result = $db->sql_query($sql);
 
733
                        $row = $db->sql_fetchrow($result);
 
734
                        $db->sql_freeresult($result);
 
735
 
 
736
                        if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt']))
 
737
                        {
 
738
                                $this->data['user_form_salt'] = unique_id();
 
739
                                // Update the form key
 
740
                                $sql = 'UPDATE ' . USERS_TABLE . '
 
741
                                        SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\'
 
742
                                        WHERE user_id = ' . (int) $this->data['user_id'];
 
743
                                $db->sql_query($sql);
 
744
                        }
 
745
                }
 
746
                else
 
747
                {
 
748
                        $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
 
749
 
 
750
                        // Update the last visit time
 
751
                        $sql = 'UPDATE ' . USERS_TABLE . '
 
752
                                SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 
753
                                WHERE user_id = ' . (int) $this->data['user_id'];
 
754
                        $db->sql_query($sql);
 
755
 
 
756
                        $SID = '?sid=';
 
757
                        $_SID = '';
 
758
                }
 
759
 
 
760
                return true;
 
761
        }
 
762
 
 
763
        /**
 
764
        * Kills a session
 
765
        *
 
766
        * This method does what it says on the tin. It will delete a pre-existing session.
 
767
        * It resets cookie information (destroying any autologin key within that cookie data)
 
768
        * and update the users information from the relevant session data. It will then
 
769
        * grab guest user information.
 
770
        */
 
771
        function session_kill($new_session = true)
 
772
        {
 
773
                global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx;
 
774
 
 
775
                $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
 
776
                        WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
 
777
                                AND session_user_id = " . (int) $this->data['user_id'];
 
778
                $db->sql_query($sql);
 
779
 
 
780
                // Allow connecting logout with external auth method logout
 
781
                $method = basename(trim($config['auth_method']));
 
782
                include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
 
783
 
 
784
                $method = 'logout_' . $method;
 
785
                if (function_exists($method))
 
786
                {
 
787
                        $method($this->data, $new_session);
 
788
                }
 
789
 
 
790
                if ($this->data['user_id'] != ANONYMOUS)
 
791
                {
 
792
                        // Delete existing session, update last visit info first!
 
793
                        if (!isset($this->data['session_time']))
 
794
                        {
 
795
                                $this->data['session_time'] = time();
 
796
                        }
 
797
 
 
798
                        $sql = 'UPDATE ' . USERS_TABLE . '
 
799
                                SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 
800
                                WHERE user_id = ' . (int) $this->data['user_id'];
 
801
                        $db->sql_query($sql);
 
802
 
 
803
                        if ($this->cookie_data['k'])
 
804
                        {
 
805
                                $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 
806
                                        WHERE user_id = ' . (int) $this->data['user_id'] . "
 
807
                                                AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
 
808
                                $db->sql_query($sql);
 
809
                        }
 
810
 
 
811
                        // Reset the data array
 
812
                        $this->data = array();
 
813
 
 
814
                        $sql = 'SELECT *
 
815
                                FROM ' . USERS_TABLE . '
 
816
                                WHERE user_id = ' . ANONYMOUS;
 
817
                        $result = $db->sql_query($sql);
 
818
                        $this->data = $db->sql_fetchrow($result);
 
819
                        $db->sql_freeresult($result);
 
820
                }
 
821
 
 
822
                $cookie_expire = $this->time_now - 31536000;
 
823
                $this->set_cookie('u', '', $cookie_expire);
 
824
                $this->set_cookie('k', '', $cookie_expire);
 
825
                $this->set_cookie('sid', '', $cookie_expire);
 
826
                unset($cookie_expire);
 
827
 
 
828
                $SID = '?sid=';
 
829
                $this->session_id = $_SID = '';
 
830
 
 
831
                // To make sure a valid session is created we create one for the anonymous user
 
832
                if ($new_session)
 
833
                {
 
834
                        $this->session_create(ANONYMOUS);
 
835
                }
 
836
 
 
837
                return true;
 
838
        }
 
839
 
 
840
        /**
 
841
        * Session garbage collection
 
842
        *
 
843
        * This looks a lot more complex than it really is. Effectively we are
 
844
        * deleting any sessions older than an admin definable limit. Due to the
 
845
        * way in which we maintain session data we have to ensure we update user
 
846
        * data before those sessions are destroyed. In addition this method
 
847
        * removes autologin key information that is older than an admin defined
 
848
        * limit.
 
849
        */
 
850
        function session_gc()
 
851
        {
 
852
                global $db, $config;
 
853
 
 
854
                $batch_size = 10;
 
855
                
 
856
                if (!$this->time_now)
 
857
                {
 
858
                        $this->time_now = time();
 
859
                }
 
860
 
 
861
                // Firstly, delete guest sessions
 
862
                $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
 
863
                        WHERE session_user_id = ' . ANONYMOUS . '
 
864
                                AND session_time < ' . (int) ($this->time_now - $config['session_length']);
 
865
                $db->sql_query($sql);
 
866
 
 
867
                // Get expired sessions, only most recent for each user
 
868
                $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time
 
869
                        FROM ' . SESSIONS_TABLE . '
 
870
                        WHERE session_time < ' . ($this->time_now - $config['session_length']) . '
 
871
                        GROUP BY session_user_id, session_page';
 
872
                $result = $db->sql_query_limit($sql, $batch_size);
 
873
 
 
874
                $del_user_id = array();
 
875
                $del_sessions = 0;
 
876
 
 
877
                while ($row = $db->sql_fetchrow($result))
 
878
                {
 
879
                        $sql = 'UPDATE ' . USERS_TABLE . '
 
880
                                SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
 
881
                                WHERE user_id = " . (int) $row['session_user_id'];
 
882
                        $db->sql_query($sql);
 
883
 
 
884
                        $del_user_id[] = (int) $row['session_user_id'];
 
885
                        $del_sessions++;
 
886
                }
 
887
                $db->sql_freeresult($result);
 
888
 
 
889
                if (sizeof($del_user_id))
 
890
                {
 
891
                        // Delete expired sessions
 
892
                        $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
 
893
                                WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . '
 
894
                                        AND session_time < ' . ($this->time_now - $config['session_length']);
 
895
                        $db->sql_query($sql);
 
896
                }
 
897
 
 
898
                if ($del_sessions < $batch_size)
 
899
                {
 
900
                        // Less than 10 users, update gc timer ... else we want gc
 
901
                        // called again to delete other sessions
 
902
                        set_config('session_last_gc', $this->time_now, true);
 
903
                        
 
904
                        if ($config['max_autologin_time'])
 
905
                        {
 
906
                                $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 
907
                                        WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time']));
 
908
                                $db->sql_query($sql);
 
909
                        }
 
910
                        $this->confirm_gc();
 
911
                }
 
912
                
 
913
                return;
 
914
        }
 
915
        
 
916
        function confirm_gc($type = 0)
 
917
        {
 
918
                global $db, $config;
 
919
                
 
920
                $sql = 'SELECT DISTINCT c.session_id
 
921
                                FROM ' . CONFIRM_TABLE . ' c
 
922
                                LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id)
 
923
                                WHERE s.session_id IS NULL' .
 
924
                                        ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type);
 
925
                $result = $db->sql_query($sql);
 
926
 
 
927
                if ($row = $db->sql_fetchrow($result))
 
928
                {
 
929
                        $sql_in = array();
 
930
                        do
 
931
                        {
 
932
                                $sql_in[] = (string) $row['session_id'];
 
933
                        }
 
934
                        while ($row = $db->sql_fetchrow($result));
 
935
 
 
936
                        if (sizeof($sql_in))
 
937
                        {
 
938
                                $sql = 'DELETE FROM ' . CONFIRM_TABLE . '
 
939
                                        WHERE ' . $db->sql_in_set('session_id', $sql_in);
 
940
                                $db->sql_query($sql);
 
941
                        }
 
942
                }
 
943
                $db->sql_freeresult($result);
 
944
        }
 
945
        
 
946
        
 
947
        /**
 
948
        * Sets a cookie
 
949
        *
 
950
        * Sets a cookie of the given name with the specified data for the given length of time.
 
951
        */
 
952
        function set_cookie($name, $cookiedata, $cookietime)
 
953
        {
 
954
                global $config;
 
955
 
 
956
                $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
 
957
                $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
 
958
                $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
 
959
 
 
960
                header('Set-Cookie: ' . $name_data . '; expires=' . $expire . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
 
961
        }
 
962
 
 
963
        /**
 
964
        * Check for banned user
 
965
        *
 
966
        * Checks whether the supplied user is banned by id, ip or email. If no parameters
 
967
        * are passed to the method pre-existing session data is used. If $return is false
 
968
        * this routine does not return on finding a banned user, it outputs a relevant
 
969
        * message and stops execution.
 
970
        *
 
971
        * @param string|array   $user_ips       Can contain a string with one IP or an array of multiple IPs
 
972
        */
 
973
        function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
 
974
        {
 
975
                global $config, $db;
 
976
 
 
977
                if (defined('IN_CHECK_BAN'))
 
978
                {
 
979
                        return;
 
980
                }
 
981
 
 
982
                $banned = false;
 
983
                $cache_ttl = 3600;
 
984
                $where_sql = array();
 
985
 
 
986
                $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end
 
987
                        FROM ' . BANLIST_TABLE . '
 
988
                        WHERE ';
 
989
 
 
990
                // Determine which entries to check, only return those
 
991
                if ($user_email === false)
 
992
                {
 
993
                        $where_sql[] = "ban_email = ''";
 
994
                }
 
995
 
 
996
                if ($user_ips === false)
 
997
                {
 
998
                        $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)";
 
999
                }
 
1000
 
 
1001
                if ($user_id === false)
 
1002
                {
 
1003
                        $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)';
 
1004
                }
 
1005
                else
 
1006
                {
 
1007
                        $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0;
 
1008
                        $_sql = '(ban_userid = ' . $user_id;
 
1009
 
 
1010
                        if ($user_email !== false)
 
1011
                        {
 
1012
                                $_sql .= " OR ban_email <> ''";
 
1013
                        }
 
1014
 
 
1015
                        if ($user_ips !== false)
 
1016
                        {
 
1017
                                $_sql .= " OR ban_ip <> ''";
 
1018
                        }
 
1019
 
 
1020
                        $_sql .= ')';
 
1021
 
 
1022
                        $where_sql[] = $_sql;
 
1023
                }
 
1024
 
 
1025
                $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : '';
 
1026
                $result = $db->sql_query($sql, $cache_ttl);
 
1027
 
 
1028
                $ban_triggered_by = 'user';
 
1029
                while ($row = $db->sql_fetchrow($result))
 
1030
                {
 
1031
                        if ($row['ban_end'] && $row['ban_end'] < time())
 
1032
                        {
 
1033
                                continue;
 
1034
                        }
 
1035
 
 
1036
                        $ip_banned = false;
 
1037
                        if (!empty($row['ban_ip']))
 
1038
                        {
 
1039
                                if (!is_array($user_ips))
 
1040
                                {
 
1041
                                        $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
 
1042
                                }
 
1043
                                else
 
1044
                                {
 
1045
                                        foreach ($user_ips as $user_ip)
 
1046
                                        {
 
1047
                                                if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
 
1048
                                                {
 
1049
                                                        $ip_banned = true;
 
1050
                                                        break;
 
1051
                                                }
 
1052
                                        }
 
1053
                                }
 
1054
                        }
 
1055
 
 
1056
                        if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) ||
 
1057
                                $ip_banned ||
 
1058
                                (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
 
1059
                        {
 
1060
                                if (!empty($row['ban_exclude']))
 
1061
                                {
 
1062
                                        $banned = false;
 
1063
                                        break;
 
1064
                                }
 
1065
                                else
 
1066
                                {
 
1067
                                        $banned = true;
 
1068
                                        $ban_row = $row;
 
1069
 
 
1070
                                        if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id)
 
1071
                                        {
 
1072
                                                $ban_triggered_by = 'user';
 
1073
                                        }
 
1074
                                        else if ($ip_banned)
 
1075
                                        {
 
1076
                                                $ban_triggered_by = 'ip';
 
1077
                                        }
 
1078
                                        else
 
1079
                                        {
 
1080
                                                $ban_triggered_by = 'email';
 
1081
                                        }
 
1082
 
 
1083
                                        // Don't break. Check if there is an exclude rule for this user
 
1084
                                }
 
1085
                        }
 
1086
                }
 
1087
                $db->sql_freeresult($result);
 
1088
 
 
1089
                if ($banned && !$return)
 
1090
                {
 
1091
                        global $template;
 
1092
 
 
1093
                        // If the session is empty we need to create a valid one...
 
1094
                        if (empty($this->session_id))
 
1095
                        {
 
1096
                                // This seems to be no longer needed? - #14971
 
1097
//                              $this->session_create(ANONYMOUS);
 
1098
                        }
 
1099
 
 
1100
                        // Initiate environment ... since it won't be set at this stage
 
1101
                        $this->setup();
 
1102
 
 
1103
                        // Logout the user, banned users are unable to use the normal 'logout' link
 
1104
                        if ($this->data['user_id'] != ANONYMOUS)
 
1105
                        {
 
1106
                                $this->session_kill();
 
1107
                        }
 
1108
 
 
1109
                        // We show a login box here to allow founders accessing the board if banned by IP
 
1110
                        if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS)
 
1111
                        {
 
1112
                                global $phpEx;
 
1113
 
 
1114
                                $this->setup('ucp');
 
1115
                                $this->data['is_registered'] = $this->data['is_bot'] = false;
 
1116
 
 
1117
                                // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again.
 
1118
                                define('IN_CHECK_BAN', 1);
 
1119
 
 
1120
                                login_box("index.$phpEx");
 
1121
 
 
1122
                                // The false here is needed, else the user is able to circumvent the ban.
 
1123
                                $this->session_kill(false);
 
1124
                        }
 
1125
 
 
1126
                        // Ok, we catch the case of an empty session id for the anonymous user...
 
1127
                        // This can happen if the user is logging in, banned by username and the login_box() being called "again".
 
1128
                        if (empty($this->session_id) && defined('IN_CHECK_BAN'))
 
1129
                        {
 
1130
                                $this->session_create(ANONYMOUS);
 
1131
                        }
 
1132
 
 
1133
 
 
1134
                        // Determine which message to output
 
1135
                        $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
 
1136
                        $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
 
1137
 
 
1138
                        $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>');
 
1139
                        $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : '';
 
1140
                        $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>';
 
1141
 
 
1142
                        // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again
 
1143
                        $this->session_kill(false);
 
1144
 
 
1145
                        trigger_error($message);
 
1146
                }
 
1147
 
 
1148
                return ($banned) ? true : false;
 
1149
        }
 
1150
 
 
1151
        /**
 
1152
        * Check if ip is blacklisted
 
1153
        * This should be called only where absolutly necessary
 
1154
        *
 
1155
        * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
 
1156
        *
 
1157
        * @author satmd (from the php manual)
 
1158
        * @param string $mode register/post - spamcop for example is ommitted for posting
 
1159
        * @return false if ip is not blacklisted, else an array([checked server], [lookup])
 
1160
        */
 
1161
        function check_dnsbl($mode, $ip = false)
 
1162
        {
 
1163
                if ($ip === false)
 
1164
                {
 
1165
                        $ip = $this->ip;
 
1166
                }
 
1167
 
 
1168
                $dnsbl_check = array(
 
1169
                        'list.dsbl.org'                 => 'http://dsbl.org/listing?',
 
1170
                        'sbl-xbl.spamhaus.org'  => 'http://www.spamhaus.org/query/bl?ip=',
 
1171
                );
 
1172
 
 
1173
                if ($mode == 'register')
 
1174
                {
 
1175
                        $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?';
 
1176
                }
 
1177
 
 
1178
                if ($ip)
 
1179
                {
 
1180
                        $quads = explode('.', $ip);
 
1181
                        $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0];
 
1182
 
 
1183
                        // Need to be listed on all servers...
 
1184
                        $listed = true;
 
1185
                        $info = array();
 
1186
 
 
1187
                        foreach ($dnsbl_check as $dnsbl => $lookup)
 
1188
                        {
 
1189
                                if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true)
 
1190
                                {
 
1191
                                        $info = array($dnsbl, $lookup . $ip);
 
1192
                                }
 
1193
                                else
 
1194
                                {
 
1195
                                        $listed = false;
 
1196
                                }
 
1197
                        }
 
1198
 
 
1199
                        if ($listed)
 
1200
                        {
 
1201
                                return $info;
 
1202
                        }
 
1203
                }
 
1204
 
 
1205
                return false;
 
1206
        }
 
1207
 
 
1208
        /**
 
1209
        * Check if URI is blacklisted
 
1210
        * This should be called only where absolutly necessary, for example on the submitted website field
 
1211
        * This function is not in use at the moment and is only included for testing purposes, it may not work at all!
 
1212
        * This means it is untested at the moment and therefore commented out
 
1213
        *
 
1214
        * @param string $uri URI to check
 
1215
        * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists
 
1216
        function check_uribl($uri)
 
1217
        {
 
1218
                // Normally parse_url() is not intended to parse uris
 
1219
                // We need to get the top-level domain name anyway... change.
 
1220
                $uri = parse_url($uri);
 
1221
 
 
1222
                if ($uri === false || empty($uri['host']))
 
1223
                {
 
1224
                        return false;
 
1225
                }
 
1226
 
 
1227
                $uri = trim($uri['host']);
 
1228
 
 
1229
                if ($uri)
 
1230
                {
 
1231
                        // One problem here... the return parameter for the "windows" method is different from what
 
1232
                        // we expect... this may render this check useless...
 
1233
                        if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true)
 
1234
                        {
 
1235
                                return true;
 
1236
                        }
 
1237
                }
 
1238
 
 
1239
                return false;
 
1240
        }
 
1241
        */
 
1242
 
 
1243
        /**
 
1244
        * Set/Update a persistent login key
 
1245
        *
 
1246
        * This method creates or updates a persistent session key. When a user makes
 
1247
        * use of persistent (formerly auto-) logins a key is generated and stored in the
 
1248
        * DB. When they revisit with the same key it's automatically updated in both the
 
1249
        * DB and cookie. Multiple keys may exist for each user representing different
 
1250
        * browsers or locations. As with _any_ non-secure-socket no passphrase login this
 
1251
        * remains vulnerable to exploit.
 
1252
        */
 
1253
        function set_login_key($user_id = false, $key = false, $user_ip = false)
 
1254
        {
 
1255
                global $config, $db;
 
1256
 
 
1257
                $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
 
1258
                $user_ip = ($user_ip === false) ? $this->ip : $user_ip;
 
1259
                $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key;
 
1260
 
 
1261
                $key_id = unique_id(hexdec(substr($this->session_id, 0, 8)));
 
1262
 
 
1263
                $sql_ary = array(
 
1264
                        'key_id'                => (string) md5($key_id),
 
1265
                        'last_ip'               => (string) $this->ip,
 
1266
                        'last_login'    => (int) time()
 
1267
                );
 
1268
 
 
1269
                if (!$key)
 
1270
                {
 
1271
                        $sql_ary += array(
 
1272
                                'user_id'       => (int) $user_id
 
1273
                        );
 
1274
                }
 
1275
 
 
1276
                if ($key)
 
1277
                {
 
1278
                        $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . '
 
1279
                                SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 
1280
                                WHERE user_id = ' . (int) $user_id . "
 
1281
                                        AND key_id = '" . $db->sql_escape(md5($key)) . "'";
 
1282
                }
 
1283
                else
 
1284
                {
 
1285
                        $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
 
1286
                }
 
1287
                $db->sql_query($sql);
 
1288
 
 
1289
                $this->cookie_data['k'] = $key_id;
 
1290
 
 
1291
                return false;
 
1292
        }
 
1293
 
 
1294
        /**
 
1295
        * Reset all login keys for the specified user
 
1296
        *
 
1297
        * This method removes all current login keys for a specified (or the current)
 
1298
        * user. It will be called on password change to render old keys unusable
 
1299
        */
 
1300
        function reset_login_keys($user_id = false)
 
1301
        {
 
1302
                global $config, $db;
 
1303
 
 
1304
                $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
 
1305
 
 
1306
                $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 
1307
                        WHERE user_id = ' . (int) $user_id;
 
1308
                $db->sql_query($sql);
 
1309
 
 
1310
                // Let's also clear any current sessions for the specified user_id
 
1311
                // If it's the current user then we'll leave this session intact
 
1312
                $sql_where = 'session_user_id = ' . (int) $user_id;
 
1313
                $sql_where .= ($user_id === $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : '';
 
1314
 
 
1315
                $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
 
1316
                        WHERE $sql_where";
 
1317
                $db->sql_query($sql);
 
1318
 
 
1319
                // We're changing the password of the current user and they have a key
 
1320
                // Lets regenerate it to be safe
 
1321
                if ($user_id === $this->data['user_id'] && $this->cookie_data['k'])
 
1322
                {
 
1323
                        $this->set_login_key($user_id);
 
1324
                }
 
1325
        }
 
1326
}
 
1327
 
 
1328
 
 
1329
/**
 
1330
* Base user class
 
1331
*
 
1332
* This is the overarching class which contains (through session extend)
 
1333
* all methods utilised for user functionality during a session.
 
1334
*
 
1335
* @package phpBB3
 
1336
*/
 
1337
class user extends session
 
1338
{
 
1339
        var $lang = array();
 
1340
        var $help = array();
 
1341
        var $theme = array();
 
1342
        var $date_format;
 
1343
        var $timezone;
 
1344
        var $dst;
 
1345
 
 
1346
        var $lang_name;
 
1347
        var $lang_id = false;
 
1348
        var $lang_path;
 
1349
        var $img_lang;
 
1350
        var $img_array = array();
 
1351
 
 
1352
        // Able to add new option (id 7)
 
1353
        var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10);
 
1354
        var $keyvalues = array();
 
1355
 
 
1356
        /**
 
1357
        * Setup basic user-specific items (style, language, ...)
 
1358
        */
 
1359
        function setup($lang_set = false, $style = false)
 
1360
        {
 
1361
                global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
 
1362
 
 
1363
                if ($this->data['user_id'] != ANONYMOUS)
 
1364
                {
 
1365
                        $this->lang_name = (file_exists($phpbb_root_path . 'language/' . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
 
1366
                        $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/';
 
1367
 
 
1368
                        $this->date_format = $this->data['user_dateformat'];
 
1369
                        $this->timezone = $this->data['user_timezone'] * 3600;
 
1370
                        $this->dst = $this->data['user_dst'] * 3600;
 
1371
                }
 
1372
                else
 
1373
                {
 
1374
                        $this->lang_name = basename($config['default_lang']);
 
1375
                        $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/';
 
1376
                        $this->date_format = $config['default_dateformat'];
 
1377
                        $this->timezone = $config['board_timezone'] * 3600;
 
1378
                        $this->dst = $config['board_dst'] * 3600;
 
1379
 
 
1380
                        /**
 
1381
                        * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
 
1382
                        * If re-enabled we need to make sure only those languages installed are checked
 
1383
                        * Commented out so we do not loose the code.
 
1384
 
 
1385
                        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
 
1386
                        {
 
1387
                                $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
 
1388
 
 
1389
                                foreach ($accept_lang_ary as $accept_lang)
 
1390
                                {
 
1391
                                        // Set correct format ... guess full xx_YY form
 
1392
                                        $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
 
1393
                                        $accept_lang = basename($accept_lang);
 
1394
 
 
1395
                                        if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
 
1396
                                        {
 
1397
                                                $this->lang_name = $config['default_lang'] = $accept_lang;
 
1398
                                                $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
 
1399
                                                break;
 
1400
                                        }
 
1401
                                        else
 
1402
                                        {
 
1403
                                                // No match on xx_YY so try xx
 
1404
                                                $accept_lang = substr($accept_lang, 0, 2);
 
1405
                                                $accept_lang = basename($accept_lang);
 
1406
 
 
1407
                                                if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
 
1408
                                                {
 
1409
                                                        $this->lang_name = $config['default_lang'] = $accept_lang;
 
1410
                                                        $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
 
1411
                                                        break;
 
1412
                                                }
 
1413
                                        }
 
1414
                                }
 
1415
                        }
 
1416
                        */
 
1417
                }
 
1418
 
 
1419
                // We include common language file here to not load it every time a custom language file is included
 
1420
                $lang = &$this->lang;
 
1421
 
 
1422
                if ((@include $this->lang_path . "common.$phpEx") === false)
 
1423
                {
 
1424
                        die('Language file ' . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
 
1425
                }
 
1426
 
 
1427
                $this->add_lang($lang_set);
 
1428
                unset($lang_set);
 
1429
 
 
1430
                if (!empty($_GET['style']) && $auth->acl_get('a_styles'))
 
1431
                {
 
1432
                        global $SID, $_EXTRA_URL;
 
1433
 
 
1434
                        $style = request_var('style', 0);
 
1435
                        $SID .= '&amp;style=' . $style;
 
1436
                        $_EXTRA_URL = array('style=' . $style);
 
1437
                }
 
1438
                else
 
1439
                {
 
1440
                        // Set up style
 
1441
                        $style = ($style) ? $style : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']);
 
1442
                }
 
1443
 
 
1444
                $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
 
1445
                        FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
 
1446
                        WHERE s.style_id = $style
 
1447
                                AND t.template_id = s.template_id
 
1448
                                AND c.theme_id = s.theme_id
 
1449
                                AND i.imageset_id = s.imageset_id";
 
1450
                $result = $db->sql_query($sql, 3600);
 
1451
                $this->theme = $db->sql_fetchrow($result);
 
1452
                $db->sql_freeresult($result);
 
1453
 
 
1454
                // User has wrong style
 
1455
                if (!$this->theme && $style == $this->data['user_style'])
 
1456
                {
 
1457
                        $style = $this->data['user_style'] = $config['default_style'];
 
1458
 
 
1459
                        $sql = 'UPDATE ' . USERS_TABLE . "
 
1460
                                SET user_style = $style
 
1461
                                WHERE user_id = {$this->data['user_id']}";
 
1462
                        $db->sql_query($sql);
 
1463
 
 
1464
                        $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
 
1465
                                FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
 
1466
                                WHERE s.style_id = $style
 
1467
                                        AND t.template_id = s.template_id
 
1468
                                        AND c.theme_id = s.theme_id
 
1469
                                        AND i.imageset_id = s.imageset_id";
 
1470
                        $result = $db->sql_query($sql, 3600);
 
1471
                        $this->theme = $db->sql_fetchrow($result);
 
1472
                        $db->sql_freeresult($result);
 
1473
                }
 
1474
 
 
1475
                if (!$this->theme)
 
1476
                {
 
1477
                        trigger_error('Could not get style data', E_USER_ERROR);
 
1478
                }
 
1479
 
 
1480
                // Now parse the cfg file and cache it
 
1481
                $parsed_items = $cache->obtain_cfg_items($this->theme);
 
1482
 
 
1483
                // We are only interested in the theme configuration for now
 
1484
                $parsed_items = $parsed_items['theme'];
 
1485
 
 
1486
                $check_for = array(
 
1487
                        'parse_css_file'        => (int) 0,
 
1488
                        'pagination_sep'        => (string) ', '
 
1489
                );
 
1490
 
 
1491
                foreach ($check_for as $key => $default_value)
 
1492
                {
 
1493
                        $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value;
 
1494
                        settype($this->theme[$key], gettype($default_value));
 
1495
 
 
1496
                        if (is_string($default_value))
 
1497
                        {
 
1498
                                $this->theme[$key] = htmlspecialchars($this->theme[$key]);
 
1499
                        }
 
1500
                }
 
1501
 
 
1502
                // If the style author specified the theme needs to be cached
 
1503
                // (because of the used paths and variables) than make sure it is the case.
 
1504
                // For example, if the theme uses language-specific images it needs to be stored in db.
 
1505
                if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file'])
 
1506
                {
 
1507
                        $this->theme['theme_storedb'] = 1;
 
1508
 
 
1509
                        $stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css");
 
1510
                        // Match CSS imports
 
1511
                        $matches = array();
 
1512
                        preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches);
 
1513
 
 
1514
                        if (sizeof($matches))
 
1515
                        {
 
1516
                                $content = '';
 
1517
                                foreach ($matches[0] as $idx => $match)
 
1518
                                {
 
1519
                                        if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx]))
 
1520
                                        {
 
1521
                                                $content = trim($content);
 
1522
                                        }
 
1523
                                        else
 
1524
                                        {
 
1525
                                                $content = '';
 
1526
                                        }
 
1527
                                        $stylesheet = str_replace($match, $content, $stylesheet);
 
1528
                                }
 
1529
                                unset($content);
 
1530
                        }
 
1531
 
 
1532
                        $stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet);
 
1533
 
 
1534
                        $sql_ary = array(
 
1535
                                'theme_data'    => $stylesheet,
 
1536
                                'theme_mtime'   => time(),
 
1537
                                'theme_storedb' => 1
 
1538
                        );
 
1539
 
 
1540
                        $sql = 'UPDATE ' . STYLES_THEME_TABLE . '
 
1541
                                SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 
1542
                                WHERE theme_id = ' . $this->theme['theme_id'];
 
1543
                        $db->sql_query($sql);
 
1544
 
 
1545
                        unset($sql_ary);
 
1546
                }
 
1547
 
 
1548
                $template->set_template();
 
1549
 
 
1550
                $this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang'];
 
1551
 
 
1552
                $sql = 'SELECT image_name, image_filename, image_lang, image_height, image_width
 
1553
                        FROM ' . STYLES_IMAGESET_DATA_TABLE . '
 
1554
                        WHERE imageset_id = ' . $this->theme['imageset_id'] . "
 
1555
                        AND image_lang IN ('" . $db->sql_escape($this->img_lang) . "', '')";
 
1556
                $result = $db->sql_query($sql, 3600);
 
1557
 
 
1558
                $localised_images = false;
 
1559
                while ($row = $db->sql_fetchrow($result))
 
1560
                {
 
1561
                        if ($row['image_lang'])
 
1562
                        {
 
1563
                                $localised_images = true;
 
1564
                        }
 
1565
 
 
1566
                        $this->img_array[$row['image_name']] = $row;
 
1567
                }
 
1568
                $db->sql_freeresult($result);
 
1569
 
 
1570
                // there were no localised images, try to refresh the localised imageset for the user's language
 
1571
                if (!$localised_images)
 
1572
                {
 
1573
                        // Attention: this code ignores the image definition list from acp_styles and just takes everything
 
1574
                        // that the config file contains
 
1575
                        $sql_ary = array();
 
1576
 
 
1577
                        $db->sql_transaction('begin');
 
1578
 
 
1579
                        $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . '
 
1580
                                WHERE imageset_id = ' . $this->theme['imageset_id'] . '
 
1581
                                        AND image_lang = \'' . $db->sql_escape($this->img_lang) . '\'';
 
1582
                        $result = $db->sql_query($sql);
 
1583
 
 
1584
                        if (@file_exists("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg"))
 
1585
                        {
 
1586
                                $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg");
 
1587
                                foreach ($cfg_data_imageset_data as $image_name => $value)
 
1588
                                {
 
1589
                                        if (strpos($value, '*') !== false)
 
1590
                                        {
 
1591
                                                if (substr($value, -1, 1) === '*')
 
1592
                                                {
 
1593
                                                        list($image_filename, $image_height) = explode('*', $value);
 
1594
                                                        $image_width = 0;
 
1595
                                                }
 
1596
                                                else
 
1597
                                                {
 
1598
                                                        list($image_filename, $image_height, $image_width) = explode('*', $value);
 
1599
                                                }
 
1600
                                        }
 
1601
                                        else
 
1602
                                        {
 
1603
                                                $image_filename = $value;
 
1604
                                                $image_height = $image_width = 0;
 
1605
                                        }
 
1606
 
 
1607
                                        if (strpos($image_name, 'img_') === 0 && $image_filename)
 
1608
                                        {
 
1609
                                                $image_name = substr($image_name, 4);
 
1610
                                                $sql_ary[] = array(
 
1611
                                                        'image_name'            => (string) $image_name,
 
1612
                                                        'image_filename'        => (string) $image_filename,
 
1613
                                                        'image_height'          => (int) $image_height,
 
1614
                                                        'image_width'           => (int) $image_width,
 
1615
                                                        'imageset_id'           => (int) $this->theme['imageset_id'],
 
1616
                                                        'image_lang'            => (string) $this->img_lang,
 
1617
                                                );
 
1618
                                        }
 
1619
                                }
 
1620
                        }
 
1621
 
 
1622
                        if (sizeof($sql_ary))
 
1623
                        {
 
1624
                                $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary);
 
1625
                                $db->sql_transaction('commit');
 
1626
                                $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
 
1627
 
 
1628
                                add_log('admin', 'LOG_IMAGESET_LANG_REFRESHED', $this->theme['imageset_name'], $this->img_lang);
 
1629
                        }
 
1630
                        else
 
1631
                        {
 
1632
                                $db->sql_transaction('commit');
 
1633
                                add_log('admin', 'LOG_IMAGESET_LANG_MISSING', $this->theme['imageset_name'], $this->img_lang);
 
1634
                        }
 
1635
                }
 
1636
 
 
1637
                // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
 
1638
                // After calling it we continue script execution...
 
1639
                phpbb_user_session_handler();
 
1640
 
 
1641
                // If this function got called from the error handler we are finished here.
 
1642
                if (defined('IN_ERROR_HANDLER'))
 
1643
                {
 
1644
                        return;
 
1645
                }
 
1646
 
 
1647
                // Disable board if the install/ directory is still present
 
1648
                // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally
 
1649
                if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install'))
 
1650
                {
 
1651
                        // Adjust the message slightly according to the permissions
 
1652
                        if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))
 
1653
                        {
 
1654
                                $message = 'REMOVE_INSTALL';
 
1655
                        }
 
1656
                        else
 
1657
                        {
 
1658
                                $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
 
1659
                        }
 
1660
                        trigger_error($message);
 
1661
                }
 
1662
 
 
1663
                // Is board disabled and user not an admin or moderator?
 
1664
                if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
 
1665
                {
 
1666
                        header('HTTP/1.1 503 Service Unavailable');
 
1667
 
 
1668
                        $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
 
1669
                        trigger_error($message);
 
1670
                }
 
1671
 
 
1672
                // Is load exceeded?
 
1673
                if ($config['limit_load'] && $this->load !== false)
 
1674
                {
 
1675
                        if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN'))
 
1676
                        {
 
1677
                                // Set board disabled to true to let the admins/mods get the proper notification
 
1678
                                $config['board_disable'] = '1';
 
1679
 
 
1680
                                if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
 
1681
                                {
 
1682
                                        header('HTTP/1.1 503 Service Unavailable');
 
1683
                                        trigger_error('BOARD_UNAVAILABLE');
 
1684
                                }
 
1685
                        }
 
1686
                }
 
1687
 
 
1688
                if (isset($this->data['session_viewonline']))
 
1689
                {
 
1690
                        // Make sure the user is able to hide his session
 
1691
                        if (!$this->data['session_viewonline'])
 
1692
                        {
 
1693
                                // Reset online status if not allowed to hide the session...
 
1694
                                if (!$auth->acl_get('u_hideonline'))
 
1695
                                {
 
1696
                                        $sql = 'UPDATE ' . SESSIONS_TABLE . '
 
1697
                                                SET session_viewonline = 1
 
1698
                                                WHERE session_user_id = ' . $this->data['user_id'];
 
1699
                                        $db->sql_query($sql);
 
1700
                                        $this->data['session_viewonline'] = 1;
 
1701
                                }
 
1702
                        }
 
1703
                        else if (!$this->data['user_allow_viewonline'])
 
1704
                        {
 
1705
                                // the user wants to hide and is allowed to  -> cloaking device on.
 
1706
                                if ($auth->acl_get('u_hideonline'))
 
1707
                                {
 
1708
                                        $sql = 'UPDATE ' . SESSIONS_TABLE . '
 
1709
                                                SET session_viewonline = 0
 
1710
                                                WHERE session_user_id = ' . $this->data['user_id'];
 
1711
                                        $db->sql_query($sql);
 
1712
                                        $this->data['session_viewonline'] = 0;
 
1713
                                }
 
1714
                        }
 
1715
                }
 
1716
 
 
1717
 
 
1718
                // Does the user need to change their password? If so, redirect to the
 
1719
                // ucp profile reg_details page ... of course do not redirect if we're already in the ucp
 
1720
                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))
 
1721
                {
 
1722
                        if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx")
 
1723
                        {
 
1724
                                redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=reg_details'));
 
1725
                        }
 
1726
                }
 
1727
 
 
1728
                return;
 
1729
        }
 
1730
 
 
1731
        /**
 
1732
        * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
 
1733
        *
 
1734
        * @param mixed $lang_set specifies the language entries to include
 
1735
        * @param bool $use_db internal variable for recursion, do not use
 
1736
        * @param bool $use_help internal variable for recursion, do not use
 
1737
        *
 
1738
        * Examples:
 
1739
        * <code>
 
1740
        * $lang_set = array('posting', 'help' => 'faq');
 
1741
        * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
 
1742
        * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
 
1743
        * $lang_set = 'posting'
 
1744
        * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
 
1745
        * </code>
 
1746
        */
 
1747
        function add_lang($lang_set, $use_db = false, $use_help = false)
 
1748
        {
 
1749
                global $phpEx;
 
1750
 
 
1751
                if (is_array($lang_set))
 
1752
                {
 
1753
                        foreach ($lang_set as $key => $lang_file)
 
1754
                        {
 
1755
                                // Please do not delete this line.
 
1756
                                // We have to force the type here, else [array] language inclusion will not work
 
1757
                                $key = (string) $key;
 
1758
 
 
1759
                                if ($key == 'db')
 
1760
                                {
 
1761
                                        $this->add_lang($lang_file, true, $use_help);
 
1762
                                }
 
1763
                                else if ($key == 'help')
 
1764
                                {
 
1765
                                        $this->add_lang($lang_file, $use_db, true);
 
1766
                                }
 
1767
                                else if (!is_array($lang_file))
 
1768
                                {
 
1769
                                        $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help);
 
1770
                                }
 
1771
                                else
 
1772
                                {
 
1773
                                        $this->add_lang($lang_file, $use_db, $use_help);
 
1774
                                }
 
1775
                        }
 
1776
                        unset($lang_set);
 
1777
                }
 
1778
                else if ($lang_set)
 
1779
                {
 
1780
                        $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help);
 
1781
                }
 
1782
        }
 
1783
 
 
1784
        /**
 
1785
        * Set language entry (called by add_lang)
 
1786
        * @access private
 
1787
        */
 
1788
        function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false)
 
1789
        {
 
1790
                global $phpEx;
 
1791
 
 
1792
                // Make sure the language path is set (if the user setup did not happen it is not set)
 
1793
                if (!$this->lang_path)
 
1794
                {
 
1795
                        global $phpbb_root_path, $config;
 
1796
 
 
1797
                        $this->lang_path = $phpbb_root_path . 'language/' . basename($config['default_lang']) . '/';
 
1798
                }
 
1799
 
 
1800
                // $lang == $this->lang
 
1801
                // $help == $this->help
 
1802
                // - add appropriate variables here, name them as they are used within the language file...
 
1803
                if (!$use_db)
 
1804
                {
 
1805
                        if ($use_help && strpos($lang_file, '/') !== false)
 
1806
                        {
 
1807
                                $language_filename = $this->lang_path . substr($lang_file, 0, stripos($lang_file, '/') + 1) . 'help_' . substr($lang_file, stripos($lang_file, '/') + 1) . '.' . $phpEx;
 
1808
                        }
 
1809
                        else
 
1810
                        {
 
1811
                                $language_filename = $this->lang_path . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx;
 
1812
                        }
 
1813
 
 
1814
                        if ((@include $language_filename) === false)
 
1815
                        {
 
1816
                                trigger_error('Language file ' . basename($language_filename) . ' couldn\'t be opened.', E_USER_ERROR);
 
1817
                        }
 
1818
                }
 
1819
                else if ($use_db)
 
1820
                {
 
1821
                        // Get Database Language Strings
 
1822
                        // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
 
1823
                        // For example: help:faq, posting
 
1824
                }
 
1825
        }
 
1826
 
 
1827
        /**
 
1828
        * Format user date
 
1829
        */
 
1830
        function format_date($gmepoch, $format = false, $forcedate = false)
 
1831
        {
 
1832
                static $midnight;
 
1833
 
 
1834
                $lang_dates = $this->lang['datetime'];
 
1835
                $format = (!$format) ? $this->date_format : $format;
 
1836
 
 
1837
                // Short representation of month in format
 
1838
                if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
 
1839
                {
 
1840
                        $lang_dates['May'] = $lang_dates['May_short'];
 
1841
                }
 
1842
 
 
1843
                unset($lang_dates['May_short']);
 
1844
 
 
1845
                if (!$midnight)
 
1846
                {
 
1847
                        list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $this->timezone + $this->dst));
 
1848
                        $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst;
 
1849
                }
 
1850
 
 
1851
                if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate))
 
1852
                {
 
1853
                        return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
 
1854
                }
 
1855
 
 
1856
                if ($gmepoch > $midnight + 86400 && !$forcedate)
 
1857
                {
 
1858
                        $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 
1859
                        return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 
1860
                }
 
1861
                else if ($gmepoch > $midnight && !$forcedate)
 
1862
                {
 
1863
                        $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 
1864
                        return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 
1865
                }
 
1866
                else if ($gmepoch > $midnight - 86400 && !$forcedate)
 
1867
                {
 
1868
                        $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 
1869
                        return str_replace('||', $this->lang['datetime']['YESTERDAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 
1870
                }
 
1871
 
 
1872
                return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
 
1873
        }
 
1874
 
 
1875
        /**
 
1876
        * Get language id currently used by the user
 
1877
        */
 
1878
        function get_iso_lang_id()
 
1879
        {
 
1880
                global $config, $db;
 
1881
 
 
1882
                if (!empty($this->lang_id))
 
1883
                {
 
1884
                        return $this->lang_id;
 
1885
                }
 
1886
 
 
1887
                if (!$this->lang_name)
 
1888
                {
 
1889
                        $this->lang_name = $config['default_lang'];
 
1890
                }
 
1891
 
 
1892
                $sql = 'SELECT lang_id
 
1893
                        FROM ' . LANG_TABLE . "
 
1894
                        WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'";
 
1895
                $result = $db->sql_query($sql);
 
1896
                $this->lang_id = (int) $db->sql_fetchfield('lang_id');
 
1897
                $db->sql_freeresult($result);
 
1898
 
 
1899
                return $this->lang_id;
 
1900
        }
 
1901
 
 
1902
        /**
 
1903
        * Get users profile fields
 
1904
        */
 
1905
        function get_profile_fields($user_id)
 
1906
        {
 
1907
                global $db;
 
1908
 
 
1909
                if (isset($this->profile_fields))
 
1910
                {
 
1911
                        return;
 
1912
                }
 
1913
 
 
1914
                $sql = 'SELECT *
 
1915
                        FROM ' . PROFILE_FIELDS_DATA_TABLE . "
 
1916
                        WHERE user_id = $user_id";
 
1917
                $result = $db->sql_query_limit($sql, 1);
 
1918
                $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row;
 
1919
                $db->sql_freeresult($result);
 
1920
        }
 
1921
 
 
1922
        /**
 
1923
        * Specify/Get image
 
1924
        */
 
1925
        function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag')
 
1926
        {
 
1927
                static $imgs;
 
1928
                global $phpbb_root_path;
 
1929
 
 
1930
                $img_data = &$imgs[$img];
 
1931
 
 
1932
                if (empty($img_data))
 
1933
                {
 
1934
                        if (!isset($this->img_array[$img]))
 
1935
                        {
 
1936
                                // Do not fill the image to let designers decide what to do if the image is empty
 
1937
                                $img_data = '';
 
1938
                                return $img_data;
 
1939
                        }
 
1940
 
 
1941
                        $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'];
 
1942
                        $img_data['width'] = $this->img_array[$img]['image_width'];
 
1943
                        $img_data['height'] = $this->img_array[$img]['image_height'];
 
1944
                }
 
1945
 
 
1946
                $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt;
 
1947
 
 
1948
                switch ($type)
 
1949
                {
 
1950
                        case 'src':
 
1951
                                return $img_data['src'];
 
1952
                        break;
 
1953
 
 
1954
                        case 'width':
 
1955
                                return ($width === false) ? $img_data['width'] : $width;
 
1956
                        break;
 
1957
 
 
1958
                        case 'height':
 
1959
                                return $img_data['height'];
 
1960
                        break;
 
1961
 
 
1962
                        default:
 
1963
                                $use_width = ($width === false) ? $img_data['width'] : $width;
 
1964
 
 
1965
                                return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />';
 
1966
                        break;
 
1967
                }
 
1968
        }
 
1969
 
 
1970
        /**
 
1971
        * Get option bit field from user options
 
1972
        */
 
1973
        function optionget($key, $data = false)
 
1974
        {
 
1975
                if (!isset($this->keyvalues[$key]))
 
1976
                {
 
1977
                        $var = ($data) ? $data : $this->data['user_options'];
 
1978
                        $this->keyvalues[$key] = ($var & 1 << $this->keyoptions[$key]) ? true : false;
 
1979
                }
 
1980
 
 
1981
                return $this->keyvalues[$key];
 
1982
        }
 
1983
 
 
1984
        /**
 
1985
        * Set option bit field for user options
 
1986
        */
 
1987
        function optionset($key, $value, $data = false)
 
1988
        {
 
1989
                $var = ($data) ? $data : $this->data['user_options'];
 
1990
 
 
1991
                if ($value && !($var & 1 << $this->keyoptions[$key]))
 
1992
                {
 
1993
                        $var += 1 << $this->keyoptions[$key];
 
1994
                }
 
1995
                else if (!$value && ($var & 1 << $this->keyoptions[$key]))
 
1996
                {
 
1997
                        $var -= 1 << $this->keyoptions[$key];
 
1998
                }
 
1999
                else
 
2000
                {
 
2001
                        return ($data) ? $var : false;
 
2002
                }
 
2003
 
 
2004
                if (!$data)
 
2005
                {
 
2006
                        $this->data['user_options'] = $var;
 
2007
                        return true;
 
2008
                }
 
2009
                else
 
2010
                {
 
2011
                        return $var;
 
2012
                }
 
2013
        }
 
2014
}
 
2015
 
 
2016
?>