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

« back to all changes in this revision

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

  • Committer: mattgiuca
  • Date: 2008-07-15 07:19:34 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:875
Added "migrations" directory, which contains incremental database update
    scripts.
Updated users.sql, uniqueness key on offering table.
Added migration matching this update to the migrations directory. Mm handy!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
*
 
4
* @package phpBB3
 
5
* @version $Id: functions.php,v 1.647 2007/12/10 18:35:28 kellanved 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
// Common global functions
 
20
 
 
21
/**
 
22
* set_var
 
23
*
 
24
* Set variable, used by {@link request_var the request_var function}
 
25
*
 
26
* @access private
 
27
*/
 
28
function set_var(&$result, $var, $type, $multibyte = false)
 
29
{
 
30
        settype($var, $type);
 
31
        $result = $var;
 
32
 
 
33
        if ($type == 'string')
 
34
        {
 
35
                $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result), ENT_COMPAT, 'UTF-8'));
 
36
 
 
37
                if (!empty($result))
 
38
                {
 
39
                        // Make sure multibyte characters are wellformed
 
40
                        if ($multibyte)
 
41
                        {
 
42
                                if (!preg_match('/^./u', $result))
 
43
                                {
 
44
                                        $result = '';
 
45
                                }
 
46
                        }
 
47
                        else
 
48
                        {
 
49
                                // no multibyte, allow only ASCII (0-127)
 
50
                                $result = preg_replace('/[\x80-\xFF]/', '?', $result);
 
51
                        }
 
52
                }
 
53
 
 
54
                $result = (STRIP) ? stripslashes($result) : $result;
 
55
        }
 
56
}
 
57
 
 
58
/**
 
59
* request_var
 
60
*
 
61
* Used to get passed variable
 
62
*/
 
63
function request_var($var_name, $default, $multibyte = false, $cookie = false)
 
64
{
 
65
        if (!$cookie && isset($_COOKIE[$var_name]))
 
66
        {
 
67
                if (!isset($_GET[$var_name]) && !isset($_POST[$var_name]))
 
68
                {
 
69
                        return (is_array($default)) ? array() : $default;
 
70
                }
 
71
                $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name];
 
72
        }
 
73
 
 
74
        if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name])))
 
75
        {
 
76
                return (is_array($default)) ? array() : $default;
 
77
        }
 
78
 
 
79
        $var = $_REQUEST[$var_name];
 
80
        if (!is_array($default))
 
81
        {
 
82
                $type = gettype($default);
 
83
        }
 
84
        else
 
85
        {
 
86
                list($key_type, $type) = each($default);
 
87
                $type = gettype($type);
 
88
                $key_type = gettype($key_type);
 
89
                if ($type == 'array')
 
90
                {
 
91
                        reset($default);
 
92
                        $default = current($default);
 
93
                        list($sub_key_type, $sub_type) = each($default);
 
94
                        $sub_type = gettype($sub_type);
 
95
                        $sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type;
 
96
                        $sub_key_type = gettype($sub_key_type);
 
97
                }
 
98
        }
 
99
 
 
100
        if (is_array($var))
 
101
        {
 
102
                $_var = $var;
 
103
                $var = array();
 
104
 
 
105
                foreach ($_var as $k => $v)
 
106
                {
 
107
                        set_var($k, $k, $key_type);
 
108
                        if ($type == 'array' && is_array($v))
 
109
                        {
 
110
                                foreach ($v as $_k => $_v)
 
111
                                {
 
112
                                        if (is_array($_v))
 
113
                                        {
 
114
                                                $_v = null;
 
115
                                        }
 
116
                                        set_var($_k, $_k, $sub_key_type);
 
117
                                        set_var($var[$k][$_k], $_v, $sub_type, $multibyte);
 
118
                                }
 
119
                        }
 
120
                        else
 
121
                        {
 
122
                                if ($type == 'array' || is_array($v))
 
123
                                {
 
124
                                        $v = null;
 
125
                                }
 
126
                                set_var($var[$k], $v, $type, $multibyte);
 
127
                        }
 
128
                }
 
129
        }
 
130
        else
 
131
        {
 
132
                set_var($var, $var, $type, $multibyte);
 
133
        }
 
134
 
 
135
        return $var;
 
136
}
 
137
 
 
138
/**
 
139
* Set config value. Creates missing config entry.
 
140
*/
 
141
function set_config($config_name, $config_value, $is_dynamic = false)
 
142
{
 
143
        global $db, $cache, $config;
 
144
 
 
145
        $sql = 'UPDATE ' . CONFIG_TABLE . "
 
146
                SET config_value = '" . $db->sql_escape($config_value) . "'
 
147
                WHERE config_name = '" . $db->sql_escape($config_name) . "'";
 
148
        $db->sql_query($sql);
 
149
 
 
150
        if (!$db->sql_affectedrows() && !isset($config[$config_name]))
 
151
        {
 
152
                $sql = 'INSERT INTO ' . CONFIG_TABLE . ' ' . $db->sql_build_array('INSERT', array(
 
153
                        'config_name'   => $config_name,
 
154
                        'config_value'  => $config_value,
 
155
                        'is_dynamic'    => ($is_dynamic) ? 1 : 0));
 
156
                $db->sql_query($sql);
 
157
        }
 
158
 
 
159
        $config[$config_name] = $config_value;
 
160
 
 
161
        if (!$is_dynamic)
 
162
        {
 
163
                $cache->destroy('config');
 
164
        }
 
165
}
 
166
 
 
167
/**
 
168
* Generates an alphanumeric random string of given length
 
169
*/
 
170
function gen_rand_string($num_chars = 8)
 
171
{
 
172
        $rand_str = unique_id();
 
173
        $rand_str = str_replace('0', 'Z', strtoupper(base_convert($rand_str, 16, 35)));
 
174
 
 
175
        return substr($rand_str, 0, $num_chars);
 
176
}
 
177
 
 
178
/**
 
179
* Return unique id
 
180
* @param string $extra additional entropy
 
181
*/
 
182
function unique_id($extra = 'c')
 
183
{
 
184
        static $dss_seeded = false;
 
185
        global $config;
 
186
 
 
187
        $val = $config['rand_seed'] . microtime();
 
188
        $val = md5($val);
 
189
        $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
 
190
 
 
191
        if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))
 
192
        {
 
193
                set_config('rand_seed', $config['rand_seed'], true);
 
194
                set_config('rand_seed_last_update', time(), true);
 
195
                $dss_seeded = true;
 
196
        }
 
197
 
 
198
        return substr($val, 4, 16);
 
199
}
 
200
 
 
201
/**
 
202
* Determine whether we are approaching the maximum execution time. Should be called once
 
203
* at the beginning of the script in which it's used.
 
204
* @return       bool    Either true if the maximum execution time is nearly reached, or false
 
205
*                                       if some time is still left.
 
206
*/
 
207
function still_on_time($extra_time = 15)
 
208
{
 
209
        static $max_execution_time, $start_time;
 
210
 
 
211
        $time = explode(' ', microtime());
 
212
        $current_time = $time[0] + $time[1];
 
213
 
 
214
        if (empty($max_execution_time))
 
215
        {
 
216
                $max_execution_time = (function_exists('ini_get')) ? (int) @ini_get('max_execution_time') : (int) @get_cfg_var('max_execution_time');
 
217
 
 
218
                // If zero, then set to something higher to not let the user catch the ten seconds barrier.
 
219
                if ($max_execution_time === 0)
 
220
                {
 
221
                        $max_execution_time = 50 + $extra_time;
 
222
                }
 
223
 
 
224
                $max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50);
 
225
 
 
226
                // For debugging purposes
 
227
                // $max_execution_time = 10;
 
228
 
 
229
                global $starttime;
 
230
                $start_time = (empty($starttime)) ? $current_time : $starttime;
 
231
        }
 
232
 
 
233
        return (ceil($current_time - $start_time) < $max_execution_time) ? true : false;
 
234
}
 
235
 
 
236
/**
 
237
*
 
238
* @version Version 0.1 / $Id: functions.php,v 1.647 2007/12/10 18:35:28 kellanved Exp $
 
239
*
 
240
* Portable PHP password hashing framework.
 
241
*
 
242
* Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
 
243
* the public domain.
 
244
*
 
245
* There's absolutely no warranty.
 
246
*
 
247
* The homepage URL for this framework is:
 
248
*
 
249
*       http://www.openwall.com/phpass/
 
250
*
 
251
* Please be sure to update the Version line if you edit this file in any way.
 
252
* It is suggested that you leave the main version number intact, but indicate
 
253
* your project name (after the slash) and add your own revision information.
 
254
*
 
255
* Please do not change the "private" password hashing method implemented in
 
256
* here, thereby making your hashes incompatible.  However, if you must, please
 
257
* change the hash type identifier (the "$P$") to something different.
 
258
*
 
259
* Obviously, since this code is in the public domain, the above are not
 
260
* requirements (there can be none), but merely suggestions.
 
261
*
 
262
*
 
263
* Hash the password
 
264
*/
 
265
function phpbb_hash($password)
 
266
{
 
267
        $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
 
268
 
 
269
        $random_state = unique_id();
 
270
        $random = '';
 
271
        $count = 6;
 
272
 
 
273
        if (($fh = @fopen('/dev/urandom', 'rb')))
 
274
        {
 
275
                $random = fread($fh, $count);
 
276
                fclose($fh);
 
277
        }
 
278
 
 
279
        if (strlen($random) < $count)
 
280
        {
 
281
                $random = '';
 
282
 
 
283
                for ($i = 0; $i < $count; $i += 16)
 
284
                {
 
285
                        $random_state = md5(unique_id() . $random_state);
 
286
                        $random .= pack('H*', md5($random_state));
 
287
                }
 
288
                $random = substr($random, 0, $count);
 
289
        }
 
290
        
 
291
        $hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);
 
292
 
 
293
        if (strlen($hash) == 34)
 
294
        {
 
295
                return $hash;
 
296
        }
 
297
 
 
298
        return md5($password);
 
299
}
 
300
 
 
301
/**
 
302
* Check for correct password
 
303
*/
 
304
function phpbb_check_hash($password, $hash)
 
305
{
 
306
        $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
 
307
        if (strlen($hash) == 34)
 
308
        {
 
309
                return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
 
310
        }
 
311
 
 
312
        return (md5($password) === $hash) ? true : false;
 
313
}
 
314
 
 
315
/**
 
316
* Generate salt for hash generation
 
317
*/
 
318
function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6)
 
319
{
 
320
        if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
 
321
        {
 
322
                $iteration_count_log2 = 8;
 
323
        }
 
324
 
 
325
        $output = '$H$';
 
326
        $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
 
327
        $output .= _hash_encode64($input, 6, $itoa64);
 
328
 
 
329
        return $output;
 
330
}
 
331
 
 
332
/**
 
333
* Encode hash
 
334
*/
 
335
function _hash_encode64($input, $count, &$itoa64)
 
336
{
 
337
        $output = '';
 
338
        $i = 0;
 
339
 
 
340
        do
 
341
        {
 
342
                $value = ord($input[$i++]);
 
343
                $output .= $itoa64[$value & 0x3f];
 
344
 
 
345
                if ($i < $count)
 
346
                {
 
347
                        $value |= ord($input[$i]) << 8;
 
348
                }
 
349
 
 
350
                $output .= $itoa64[($value >> 6) & 0x3f];
 
351
 
 
352
                if ($i++ >= $count)
 
353
                {
 
354
                        break;
 
355
                }
 
356
 
 
357
                if ($i < $count)
 
358
                {
 
359
                        $value |= ord($input[$i]) << 16;
 
360
                }
 
361
 
 
362
                $output .= $itoa64[($value >> 12) & 0x3f];
 
363
                
 
364
                if ($i++ >= $count)
 
365
                {
 
366
                        break;
 
367
                }
 
368
 
 
369
                $output .= $itoa64[($value >> 18) & 0x3f];
 
370
        }
 
371
        while ($i < $count);
 
372
 
 
373
        return $output;
 
374
}
 
375
 
 
376
/**
 
377
* The crypt function/replacement
 
378
*/
 
379
function _hash_crypt_private($password, $setting, &$itoa64)
 
380
{
 
381
        $output = '*';
 
382
 
 
383
        // Check for correct hash
 
384
        if (substr($setting, 0, 3) != '$H$')
 
385
        {
 
386
                return $output;
 
387
        }
 
388
 
 
389
        $count_log2 = strpos($itoa64, $setting[3]);
 
390
 
 
391
        if ($count_log2 < 7 || $count_log2 > 30)
 
392
        {
 
393
                return $output;
 
394
        }
 
395
 
 
396
        $count = 1 << $count_log2;
 
397
        $salt = substr($setting, 4, 8);
 
398
 
 
399
        if (strlen($salt) != 8)
 
400
        {
 
401
                return $output;
 
402
        }
 
403
 
 
404
        /**
 
405
        * We're kind of forced to use MD5 here since it's the only
 
406
        * cryptographic primitive available in all versions of PHP
 
407
        * currently in use.  To implement our own low-level crypto
 
408
        * in PHP would result in much worse performance and
 
409
        * consequently in lower iteration counts and hashes that are
 
410
        * quicker to crack (by non-PHP code).
 
411
        */
 
412
        if (PHP_VERSION >= 5)
 
413
        {
 
414
                $hash = md5($salt . $password, true);
 
415
                do
 
416
                {
 
417
                        $hash = md5($hash . $password, true);
 
418
                }
 
419
                while (--$count);
 
420
        }
 
421
        else
 
422
        {
 
423
                $hash = pack('H*', md5($salt . $password));
 
424
                do
 
425
                {
 
426
                        $hash = pack('H*', md5($hash . $password));
 
427
                }
 
428
                while (--$count);
 
429
        }
 
430
 
 
431
        $output = substr($setting, 0, 12);
 
432
        $output .= _hash_encode64($hash, 16, $itoa64);
 
433
 
 
434
        return $output;
 
435
}
 
436
 
 
437
// Compatibility functions
 
438
 
 
439
if (!function_exists('array_combine'))
 
440
{
 
441
        /**
 
442
        * A wrapper for the PHP5 function array_combine()
 
443
        * @param array $keys contains keys for the resulting array
 
444
        * @param array $values contains values for the resulting array
 
445
        *
 
446
        * @return Returns an array by using the values from the keys array as keys and the
 
447
        *       values from the values array as the corresponding values. Returns false if the
 
448
        *       number of elements for each array isn't equal or if the arrays are empty.
 
449
        */
 
450
        function array_combine($keys, $values)
 
451
        {
 
452
                $keys = array_values($keys);
 
453
                $values = array_values($values);
 
454
 
 
455
                $n = sizeof($keys);
 
456
                $m = sizeof($values);
 
457
                if (!$n || !$m || ($n != $m))
 
458
                {
 
459
                        return false;
 
460
                }
 
461
 
 
462
                $combined = array();
 
463
                for ($i = 0; $i < $n; $i++)
 
464
                {
 
465
                        $combined[$keys[$i]] = $values[$i];
 
466
                }
 
467
                return $combined;
 
468
        }
 
469
}
 
470
 
 
471
if (!function_exists('str_split'))
 
472
{
 
473
        /**
 
474
        * A wrapper for the PHP5 function str_split()
 
475
        * @param array $string contains the string to be converted
 
476
        * @param array $split_length contains the length of each chunk
 
477
        *
 
478
        * @return  Converts a string to an array. If the optional split_length parameter is specified,
 
479
        *       the returned array will be broken down into chunks with each being split_length in length,
 
480
        *       otherwise each chunk will be one character in length. FALSE is returned if split_length is
 
481
        *       less than 1. If the split_length length exceeds the length of string, the entire string is
 
482
        *       returned as the first (and only) array element.
 
483
        */
 
484
        function str_split($string, $split_length = 1)
 
485
        {
 
486
                if ($split_length < 1)
 
487
                {
 
488
                        return false;
 
489
                }
 
490
                else if ($split_length >= strlen($string))
 
491
                {
 
492
                        return array($string);
 
493
                }
 
494
                else
 
495
                {
 
496
                        preg_match_all('#.{1,' . $split_length . '}#s', $string, $matches);
 
497
                        return $matches[0];
 
498
                }
 
499
        }
 
500
}
 
501
 
 
502
if (!function_exists('stripos'))
 
503
{
 
504
        /**
 
505
        * A wrapper for the PHP5 function stripos
 
506
        * Find position of first occurrence of a case-insensitive string
 
507
        *
 
508
        * @param string $haystack is the string to search in
 
509
        * @param string $needle is the string to search for
 
510
        *
 
511
        * @return mixed Returns the numeric position of the first occurrence of needle in the haystack string. Unlike strpos(), stripos() is case-insensitive.
 
512
        * Note that the needle may be a string of one or more characters.
 
513
        * If needle is not found, stripos() will return boolean FALSE.
 
514
        */
 
515
        function stripos($haystack, $needle)
 
516
        {
 
517
                if (preg_match('#' . preg_quote($needle, '#') . '#i', $haystack, $m))
 
518
                {
 
519
                        return strpos($haystack, $m[0]);
 
520
                }
 
521
 
 
522
                return false;
 
523
        }
 
524
}
 
525
 
 
526
if (!function_exists('realpath'))
 
527
{
 
528
        /**
 
529
        * Checks if a path ($path) is absolute or relative
 
530
        *
 
531
        * @param string $path Path to check absoluteness of
 
532
        * @return boolean
 
533
        */
 
534
        function is_absolute($path)
 
535
        {
 
536
                return ($path[0] == '/' || (DIRECTORY_SEPARATOR == '\\' && preg_match('#^[a-z]:/#i', $path))) ? true : false;
 
537
        }
 
538
 
 
539
        /**
 
540
        * @author Chris Smith <chris@project-minerva.org>
 
541
        * @copyright 2006 Project Minerva Team
 
542
        * @param string $path The path which we should attempt to resolve.
 
543
        * @return mixed
 
544
        */
 
545
        function phpbb_realpath($path)
 
546
        {
 
547
                // Now to perform funky shizzle
 
548
 
 
549
                // Switch to use UNIX slashes
 
550
                $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
 
551
                $path_prefix = '';
 
552
 
 
553
                // Determine what sort of path we have
 
554
                if (is_absolute($path))
 
555
                {
 
556
                        $absolute = true;
 
557
 
 
558
                        if ($path[0] == '/')
 
559
                        {
 
560
                                // Absolute path, *NIX style
 
561
                                $path_prefix = '';
 
562
                        }
 
563
                        else
 
564
                        {
 
565
                                // Absolute path, Windows style
 
566
                                // Remove the drive letter and colon
 
567
                                $path_prefix = $path[0] . ':';
 
568
                                $path = substr($path, 2);
 
569
                        }
 
570
                }
 
571
                else
 
572
                {
 
573
                        // Relative Path
 
574
                        // Prepend the current working directory
 
575
                        if (function_exists('getcwd'))
 
576
                        {
 
577
                                // This is the best method, hopefully it is enabled!
 
578
                                $path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path;
 
579
                                $absolute = true;
 
580
                                if (preg_match('#^[a-z]:#i', $path))
 
581
                                {
 
582
                                        $path_prefix = $path[0] . ':';
 
583
                                        $path = substr($path, 2);
 
584
                                }
 
585
                                else
 
586
                                {
 
587
                                        $path_prefix = '';
 
588
                                }
 
589
                        }
 
590
                        else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
 
591
                        {
 
592
                                // Warning: If chdir() has been used this will lie!
 
593
                                // Warning: This has some problems sometime (CLI can create them easily)
 
594
                                $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
 
595
                                $absolute = true;
 
596
                                $path_prefix = '';
 
597
                        }
 
598
                        else
 
599
                        {
 
600
                                // We have no way of getting the absolute path, just run on using relative ones.
 
601
                                $absolute = false;
 
602
                                $path_prefix = '.';
 
603
                        }
 
604
                }
 
605
 
 
606
                // Remove any repeated slashes
 
607
                $path = preg_replace('#/{2,}#', '/', $path);
 
608
 
 
609
                // Remove the slashes from the start and end of the path
 
610
                $path = trim($path, '/');
 
611
 
 
612
                // Break the string into little bits for us to nibble on
 
613
                $bits = explode('/', $path);
 
614
 
 
615
                // Remove any . in the path, renumber array for the loop below
 
616
                $bits = array_values(array_diff($bits, array('.')));
 
617
 
 
618
                // Lets get looping, run over and resolve any .. (up directory)
 
619
                for ($i = 0, $max = sizeof($bits); $i < $max; $i++)
 
620
                {
 
621
                        // @todo Optimise
 
622
                        if ($bits[$i] == '..' )
 
623
                        {
 
624
                                if (isset($bits[$i - 1]))
 
625
                                {
 
626
                                        if ($bits[$i - 1] != '..')
 
627
                                        {
 
628
                                                // We found a .. and we are able to traverse upwards, lets do it!
 
629
                                                unset($bits[$i]);
 
630
                                                unset($bits[$i - 1]);
 
631
                                                $i -= 2;
 
632
                                                $max -= 2;
 
633
                                                $bits = array_values($bits);
 
634
                                        }
 
635
                                }
 
636
                                else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
 
637
                                {
 
638
                                        // We have an absolute path trying to descend above the root of the filesystem
 
639
                                        // ... Error!
 
640
                                        return false;
 
641
                                }
 
642
                        }
 
643
                }
 
644
 
 
645
                // Prepend the path prefix
 
646
                array_unshift($bits, $path_prefix);
 
647
 
 
648
                $resolved = '';
 
649
 
 
650
                $max = sizeof($bits) - 1;
 
651
 
 
652
                // Check if we are able to resolve symlinks, Windows cannot.
 
653
                $symlink_resolve = (function_exists('readlink')) ? true : false;
 
654
 
 
655
                foreach ($bits as $i => $bit)
 
656
                {
 
657
                        if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit")))
 
658
                        {
 
659
                                // Path Exists
 
660
                                if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
 
661
                                {
 
662
                                        // Resolved a symlink.
 
663
                                        $resolved = $link . (($i == $max) ? '' : '/');
 
664
                                        continue;
 
665
                                }
 
666
                        }
 
667
                        else
 
668
                        {
 
669
                                // Something doesn't exist here!
 
670
                                // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
 
671
                                // return false;
 
672
                        }
 
673
                        $resolved .= $bit . (($i == $max) ? '' : '/');
 
674
                }
 
675
 
 
676
                // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
 
677
                // because we must be inside that basedir, the question is where...
 
678
                // @internal The slash in is_dir() gets around an open_basedir restriction
 
679
                if (!@file_exists($resolved) || (!is_dir($resolved . '/') && !is_file($resolved)))
 
680
                {
 
681
                        return false;
 
682
                }
 
683
 
 
684
                // Put the slashes back to the native operating systems slashes
 
685
                $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved);
 
686
 
 
687
                // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
 
688
                if (substr($resolved, -1) == DIRECTORY_SEPARATOR)
 
689
                {
 
690
                        return substr($resolved, 0, -1);
 
691
                }
 
692
 
 
693
                return $resolved; // We got here, in the end!
 
694
        }
 
695
}
 
696
else
 
697
{
 
698
        /**
 
699
        * A wrapper for realpath
 
700
        * @ignore
 
701
        */
 
702
        function phpbb_realpath($path)
 
703
        {
 
704
                $path = realpath($path);
 
705
 
 
706
                // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
 
707
                if (substr($path, -1) == DIRECTORY_SEPARATOR)
 
708
                {
 
709
                        return substr($path, 0, -1);
 
710
                }
 
711
 
 
712
                return $path;
 
713
        }
 
714
}
 
715
 
 
716
if (!function_exists('htmlspecialchars_decode'))
 
717
{
 
718
        /**
 
719
        * A wrapper for htmlspecialchars_decode
 
720
        * @ignore
 
721
        */
 
722
        function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT)
 
723
        {
 
724
                return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
 
725
        }
 
726
}
 
727
 
 
728
// functions used for building option fields
 
729
 
 
730
/**
 
731
* Pick a language, any language ...
 
732
*/
 
733
function language_select($default = '')
 
734
{
 
735
        global $db;
 
736
 
 
737
        $sql = 'SELECT lang_iso, lang_local_name
 
738
                FROM ' . LANG_TABLE . '
 
739
                ORDER BY lang_english_name';
 
740
        $result = $db->sql_query($sql);
 
741
 
 
742
        $lang_options = '';
 
743
        while ($row = $db->sql_fetchrow($result))
 
744
        {
 
745
                $selected = ($row['lang_iso'] == $default) ? ' selected="selected"' : '';
 
746
                $lang_options .= '<option value="' . $row['lang_iso'] . '"' . $selected . '>' . $row['lang_local_name'] . '</option>';
 
747
        }
 
748
        $db->sql_freeresult($result);
 
749
 
 
750
        return $lang_options;
 
751
}
 
752
 
 
753
/**
 
754
* Pick a template/theme combo,
 
755
*/
 
756
function style_select($default = '', $all = false)
 
757
{
 
758
        global $db;
 
759
 
 
760
        $sql_where = (!$all) ? 'WHERE style_active = 1 ' : '';
 
761
        $sql = 'SELECT style_id, style_name
 
762
                FROM ' . STYLES_TABLE . "
 
763
                $sql_where
 
764
                ORDER BY style_name";
 
765
        $result = $db->sql_query($sql);
 
766
 
 
767
        $style_options = '';
 
768
        while ($row = $db->sql_fetchrow($result))
 
769
        {
 
770
                $selected = ($row['style_id'] == $default) ? ' selected="selected"' : '';
 
771
                $style_options .= '<option value="' . $row['style_id'] . '"' . $selected . '>' . $row['style_name'] . '</option>';
 
772
        }
 
773
        $db->sql_freeresult($result);
 
774
 
 
775
        return $style_options;
 
776
}
 
777
 
 
778
/**
 
779
* Pick a timezone
 
780
*/
 
781
function tz_select($default = '', $truncate = false)
 
782
{
 
783
        global $user;
 
784
 
 
785
        $tz_select = '';
 
786
        foreach ($user->lang['tz_zones'] as $offset => $zone)
 
787
        {
 
788
                if ($truncate)
 
789
                {
 
790
                        $zone_trunc = truncate_string($zone, 50, false, '...');
 
791
                }
 
792
                else
 
793
                {
 
794
                        $zone_trunc = $zone;
 
795
                }
 
796
 
 
797
                if (is_numeric($offset))
 
798
                {
 
799
                        $selected = ($offset == $default) ? ' selected="selected"' : '';
 
800
                        $tz_select .= '<option title="'.$zone.'" value="' . $offset . '"' . $selected . '>' . $zone_trunc . '</option>';
 
801
                }
 
802
        }
 
803
 
 
804
        return $tz_select;
 
805
}
 
806
 
 
807
// Functions handling topic/post tracking/marking
 
808
 
 
809
/**
 
810
* Marks a topic/forum as read
 
811
* Marks a topic as posted to
 
812
*
 
813
* @param int $user_id can only be used with $mode == 'post'
 
814
*/
 
815
function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
 
816
{
 
817
        global $db, $user, $config;
 
818
 
 
819
        if ($mode == 'all')
 
820
        {
 
821
                if ($forum_id === false || !sizeof($forum_id))
 
822
                {
 
823
                        if ($config['load_db_lastread'] && $user->data['is_registered'])
 
824
                        {
 
825
                                // Mark all forums read (index page)
 
826
                                $db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}");
 
827
                                $db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}");
 
828
                                $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
 
829
                        }
 
830
                        else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
831
                        {
 
832
                                $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
 
833
                                $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
 
834
 
 
835
                                unset($tracking_topics['tf']);
 
836
                                unset($tracking_topics['t']);
 
837
                                unset($tracking_topics['f']);
 
838
                                $tracking_topics['l'] = base_convert(time() - $config['board_startdate'], 10, 36);
 
839
        
 
840
                                $user->set_cookie('track', tracking_serialize($tracking_topics), time() + 31536000);
 
841
                                $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking_topics)) : tracking_serialize($tracking_topics);
 
842
 
 
843
                                unset($tracking_topics);
 
844
 
 
845
                                if ($user->data['is_registered'])
 
846
                                {
 
847
                                        $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
 
848
                                }
 
849
                        }
 
850
                }
 
851
 
 
852
                return;
 
853
        }
 
854
        else if ($mode == 'topics')
 
855
        {
 
856
                // Mark all topics in forums read
 
857
                if (!is_array($forum_id))
 
858
                {
 
859
                        $forum_id = array($forum_id);
 
860
                }
 
861
 
 
862
                // Add 0 to forums array to mark global announcements correctly
 
863
                $forum_id[] = 0;
 
864
 
 
865
                if ($config['load_db_lastread'] && $user->data['is_registered'])
 
866
                {
 
867
                        $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE . "
 
868
                                WHERE user_id = {$user->data['user_id']}
 
869
                                        AND " . $db->sql_in_set('forum_id', $forum_id);
 
870
                        $db->sql_query($sql);
 
871
 
 
872
                        $sql = 'SELECT forum_id
 
873
                                FROM ' . FORUMS_TRACK_TABLE . "
 
874
                                WHERE user_id = {$user->data['user_id']}
 
875
                                        AND " . $db->sql_in_set('forum_id', $forum_id);
 
876
                        $result = $db->sql_query($sql);
 
877
 
 
878
                        $sql_update = array();
 
879
                        while ($row = $db->sql_fetchrow($result))
 
880
                        {
 
881
                                $sql_update[] = $row['forum_id'];
 
882
                        }
 
883
                        $db->sql_freeresult($result);
 
884
 
 
885
                        if (sizeof($sql_update))
 
886
                        {
 
887
                                $sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
 
888
                                        SET mark_time = ' . time() . "
 
889
                                        WHERE user_id = {$user->data['user_id']}
 
890
                                                AND " . $db->sql_in_set('forum_id', $sql_update);
 
891
                                $db->sql_query($sql);
 
892
                        }
 
893
 
 
894
                        if ($sql_insert = array_diff($forum_id, $sql_update))
 
895
                        {
 
896
                                $sql_ary = array();
 
897
                                foreach ($sql_insert as $f_id)
 
898
                                {
 
899
                                        $sql_ary[] = array(
 
900
                                                'user_id'       => (int) $user->data['user_id'],
 
901
                                                'forum_id'      => (int) $f_id,
 
902
                                                'mark_time'     => time()
 
903
                                        );
 
904
                                }
 
905
 
 
906
                                $db->sql_multi_insert(FORUMS_TRACK_TABLE, $sql_ary);
 
907
                        }
 
908
                }
 
909
                else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
910
                {
 
911
                        $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
 
912
                        $tracking = ($tracking) ? tracking_unserialize($tracking) : array();
 
913
 
 
914
                        foreach ($forum_id as $f_id)
 
915
                        {
 
916
                                $topic_ids36 = (isset($tracking['tf'][$f_id])) ? $tracking['tf'][$f_id] : array();
 
917
 
 
918
                                if (isset($tracking['tf'][$f_id]))
 
919
                                {
 
920
                                        unset($tracking['tf'][$f_id]);
 
921
                                }
 
922
 
 
923
                                foreach ($topic_ids36 as $topic_id36)
 
924
                                {
 
925
                                        unset($tracking['t'][$topic_id36]);
 
926
                                }
 
927
 
 
928
                                if (isset($tracking['f'][$f_id]))
 
929
                                {
 
930
                                        unset($tracking['f'][$f_id]);
 
931
                                }
 
932
 
 
933
                                $tracking['f'][$f_id] = base_convert(time() - $config['board_startdate'], 10, 36);
 
934
                        }
 
935
 
 
936
                        if (isset($tracking['tf']) && empty($tracking['tf']))
 
937
                        {
 
938
                                unset($tracking['tf']);
 
939
                        }
 
940
 
 
941
                        $user->set_cookie('track', tracking_serialize($tracking), time() + 31536000);
 
942
                        $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking);
 
943
 
 
944
                        unset($tracking);
 
945
                }
 
946
 
 
947
                return;
 
948
        }
 
949
        else if ($mode == 'topic')
 
950
        {
 
951
                if ($topic_id === false || $forum_id === false)
 
952
                {
 
953
                        return;
 
954
                }
 
955
 
 
956
                if ($config['load_db_lastread'] && $user->data['is_registered'])
 
957
                {
 
958
                        $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . '
 
959
                                SET mark_time = ' . (($post_time) ? $post_time : time()) . "
 
960
                                WHERE user_id = {$user->data['user_id']}
 
961
                                        AND topic_id = $topic_id";
 
962
                        $db->sql_query($sql);
 
963
 
 
964
                        // insert row
 
965
                        if (!$db->sql_affectedrows())
 
966
                        {
 
967
                                $db->sql_return_on_error(true);
 
968
 
 
969
                                $sql_ary = array(
 
970
                                        'user_id'               => (int) $user->data['user_id'],
 
971
                                        'topic_id'              => (int) $topic_id,
 
972
                                        'forum_id'              => (int) $forum_id,
 
973
                                        'mark_time'             => ($post_time) ? (int) $post_time : time(),
 
974
                                );
 
975
 
 
976
                                $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 
977
 
 
978
                                $db->sql_return_on_error(false);
 
979
                        }
 
980
                }
 
981
                else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
982
                {
 
983
                        $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
 
984
                        $tracking = ($tracking) ? tracking_unserialize($tracking) : array();
 
985
 
 
986
                        $topic_id36 = base_convert($topic_id, 10, 36);
 
987
 
 
988
                        if (!isset($tracking['t'][$topic_id36]))
 
989
                        {
 
990
                                $tracking['tf'][$forum_id][$topic_id36] = true;
 
991
                        }
 
992
 
 
993
                        $post_time = ($post_time) ? $post_time : time();
 
994
                        $tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36);
 
995
 
 
996
                        // If the cookie grows larger than 10000 characters we will remove the smallest value
 
997
                        // This can result in old topics being unread - but most of the time it should be accurate...
 
998
                        if (isset($_COOKIE[$config['cookie_name'] . '_track']) && strlen($_COOKIE[$config['cookie_name'] . '_track']) > 10000)
 
999
                        {
 
1000
                                //echo 'Cookie grown too large' . print_r($tracking, true);
 
1001
 
 
1002
                                // We get the ten most minimum stored time offsets and its associated topic ids
 
1003
                                $time_keys = array();
 
1004
                                for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++)
 
1005
                                {
 
1006
                                        $min_value = min($tracking['t']);
 
1007
                                        $m_tkey = array_search($min_value, $tracking['t']);
 
1008
                                        unset($tracking['t'][$m_tkey]);
 
1009
 
 
1010
                                        $time_keys[$m_tkey] = $min_value;
 
1011
                                }
 
1012
 
 
1013
                                // Now remove the topic ids from the array...
 
1014
                                foreach ($tracking['tf'] as $f_id => $topic_id_ary)
 
1015
                                {
 
1016
                                        foreach ($time_keys as $m_tkey => $min_value)
 
1017
                                        {
 
1018
                                                if (isset($topic_id_ary[$m_tkey]))
 
1019
                                                {
 
1020
                                                        $tracking['f'][$f_id] = $min_value;
 
1021
                                                        unset($tracking['tf'][$f_id][$m_tkey]);
 
1022
                                                }
 
1023
                                        }
 
1024
                                }
 
1025
 
 
1026
                                if ($user->data['is_registered'])
 
1027
                                {
 
1028
                                        $user->data['user_lastmark'] = intval(base_convert(max($time_keys) + $config['board_startdate'], 36, 10));
 
1029
                                        $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . $user->data['user_lastmark'] . " WHERE user_id = {$user->data['user_id']}");
 
1030
                                }
 
1031
                                else
 
1032
                                {
 
1033
                                        $tracking['l'] = max($time_keys);
 
1034
                                }
 
1035
                        }
 
1036
 
 
1037
                        $user->set_cookie('track', tracking_serialize($tracking), time() + 31536000);
 
1038
                        $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking);
 
1039
                }
 
1040
 
 
1041
                return;
 
1042
        }
 
1043
        else if ($mode == 'post')
 
1044
        {
 
1045
                if ($topic_id === false)
 
1046
                {
 
1047
                        return;
 
1048
                }
 
1049
 
 
1050
                $use_user_id = (!$user_id) ? $user->data['user_id'] : $user_id;
 
1051
 
 
1052
                if ($config['load_db_track'] && $use_user_id != ANONYMOUS)
 
1053
                {
 
1054
                        $db->sql_return_on_error(true);
 
1055
 
 
1056
                        $sql_ary = array(
 
1057
                                'user_id'               => (int) $use_user_id,
 
1058
                                'topic_id'              => (int) $topic_id,
 
1059
                                'topic_posted'  => 1
 
1060
                        );
 
1061
 
 
1062
                        $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 
1063
 
 
1064
                        $db->sql_return_on_error(false);
 
1065
                }
 
1066
 
 
1067
                return;
 
1068
        }
 
1069
}
 
1070
 
 
1071
/**
 
1072
* Get topic tracking info by using already fetched info
 
1073
*/
 
1074
function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
 
1075
{
 
1076
        global $config, $user;
 
1077
 
 
1078
        $last_read = array();
 
1079
 
 
1080
        if (!is_array($topic_ids))
 
1081
        {
 
1082
                $topic_ids = array($topic_ids);
 
1083
        }
 
1084
 
 
1085
        foreach ($topic_ids as $topic_id)
 
1086
        {
 
1087
                if (!empty($rowset[$topic_id]['mark_time']))
 
1088
                {
 
1089
                        $last_read[$topic_id] = $rowset[$topic_id]['mark_time'];
 
1090
                }
 
1091
        }
 
1092
 
 
1093
        $topic_ids = array_diff($topic_ids, array_keys($last_read));
 
1094
 
 
1095
        if (sizeof($topic_ids))
 
1096
        {
 
1097
                $mark_time = array();
 
1098
 
 
1099
                // Get global announcement info
 
1100
                if ($global_announce_list && sizeof($global_announce_list))
 
1101
                {
 
1102
                        if (!isset($forum_mark_time[0]))
 
1103
                        {
 
1104
                                global $db;
 
1105
 
 
1106
                                $sql = 'SELECT mark_time
 
1107
                                        FROM ' . FORUMS_TRACK_TABLE . "
 
1108
                                        WHERE user_id = {$user->data['user_id']}
 
1109
                                                AND forum_id = 0";
 
1110
                                $result = $db->sql_query($sql);
 
1111
                                $row = $db->sql_fetchrow($result);
 
1112
                                $db->sql_freeresult($result);
 
1113
 
 
1114
                                if ($row)
 
1115
                                {
 
1116
                                        $mark_time[0] = $row['mark_time'];
 
1117
                                }
 
1118
                        }
 
1119
                        else
 
1120
                        {
 
1121
                                if ($forum_mark_time[0] !== false)
 
1122
                                {
 
1123
                                        $mark_time[0] = $forum_mark_time[0];
 
1124
                                }
 
1125
                        }
 
1126
                }
 
1127
 
 
1128
                if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false)
 
1129
                {
 
1130
                        $mark_time[$forum_id] = $forum_mark_time[$forum_id];
 
1131
                }
 
1132
                        
 
1133
                $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark'];
 
1134
 
 
1135
                foreach ($topic_ids as $topic_id)
 
1136
                {
 
1137
                        if ($global_announce_list && isset($global_announce_list[$topic_id]))
 
1138
                        {
 
1139
                                $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
 
1140
                        }
 
1141
                        else
 
1142
                        {
 
1143
                                $last_read[$topic_id] = $user_lastmark;
 
1144
                        }
 
1145
                }
 
1146
        }
 
1147
 
 
1148
        return $last_read;
 
1149
}
 
1150
 
 
1151
/**
 
1152
* Get topic tracking info from db (for cookie based tracking only this function is used)
 
1153
*/
 
1154
function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false)
 
1155
{
 
1156
        global $config, $user;
 
1157
 
 
1158
        $last_read = array();
 
1159
 
 
1160
        if (!is_array($topic_ids))
 
1161
        {
 
1162
                $topic_ids = array($topic_ids);
 
1163
        }
 
1164
 
 
1165
        if ($config['load_db_lastread'] && $user->data['is_registered'])
 
1166
        {
 
1167
                global $db;
 
1168
 
 
1169
                $sql = 'SELECT topic_id, mark_time
 
1170
                        FROM ' . TOPICS_TRACK_TABLE . "
 
1171
                        WHERE user_id = {$user->data['user_id']}
 
1172
                                AND " . $db->sql_in_set('topic_id', $topic_ids);
 
1173
                $result = $db->sql_query($sql);
 
1174
 
 
1175
                while ($row = $db->sql_fetchrow($result))
 
1176
                {
 
1177
                        $last_read[$row['topic_id']] = $row['mark_time'];
 
1178
                }
 
1179
                $db->sql_freeresult($result);
 
1180
        
 
1181
                $topic_ids = array_diff($topic_ids, array_keys($last_read));
 
1182
 
 
1183
                if (sizeof($topic_ids))
 
1184
                {
 
1185
                        $sql = 'SELECT forum_id, mark_time
 
1186
                                FROM ' . FORUMS_TRACK_TABLE . "
 
1187
                                WHERE user_id = {$user->data['user_id']}
 
1188
                                        AND forum_id " .
 
1189
                                        (($global_announce_list && sizeof($global_announce_list)) ? "IN (0, $forum_id)" : "= $forum_id");
 
1190
                        $result = $db->sql_query($sql);
 
1191
                
 
1192
                        $mark_time = array();
 
1193
                        while ($row = $db->sql_fetchrow($result))
 
1194
                        {
 
1195
                                $mark_time[$row['forum_id']] = $row['mark_time'];
 
1196
                        }
 
1197
                        $db->sql_freeresult($result);
 
1198
 
 
1199
                        $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark'];
 
1200
 
 
1201
                        foreach ($topic_ids as $topic_id)
 
1202
                        {
 
1203
                                if ($global_announce_list && isset($global_announce_list[$topic_id]))
 
1204
                                {
 
1205
                                        $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
 
1206
                                }
 
1207
                                else
 
1208
                                {
 
1209
                                        $last_read[$topic_id] = $user_lastmark;
 
1210
                                }
 
1211
                        }
 
1212
                }
 
1213
        }
 
1214
        else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
1215
        {
 
1216
                global $tracking_topics;
 
1217
 
 
1218
                if (!isset($tracking_topics) || !sizeof($tracking_topics))
 
1219
                {
 
1220
                        $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
 
1221
                        $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
 
1222
                }
 
1223
 
 
1224
                if (!$user->data['is_registered'])
 
1225
                {
 
1226
                        $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0;
 
1227
                }
 
1228
                else
 
1229
                {
 
1230
                        $user_lastmark = $user->data['user_lastmark'];
 
1231
                }
 
1232
 
 
1233
                foreach ($topic_ids as $topic_id)
 
1234
                {
 
1235
                        $topic_id36 = base_convert($topic_id, 10, 36);
 
1236
 
 
1237
                        if (isset($tracking_topics['t'][$topic_id36]))
 
1238
                        {
 
1239
                                $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate'];
 
1240
                        }
 
1241
                }
 
1242
 
 
1243
                $topic_ids = array_diff($topic_ids, array_keys($last_read));
 
1244
 
 
1245
                if (sizeof($topic_ids))
 
1246
                {
 
1247
                        $mark_time = array();
 
1248
                        if ($global_announce_list && sizeof($global_announce_list))
 
1249
                        {
 
1250
                                if (isset($tracking_topics['f'][0]))
 
1251
                                {
 
1252
                                        $mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) + $config['board_startdate'];
 
1253
                                }
 
1254
                        }
 
1255
 
 
1256
                        if (isset($tracking_topics['f'][$forum_id]))
 
1257
                        {
 
1258
                                $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate'];
 
1259
                        }
 
1260
 
 
1261
                        $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user_lastmark;
 
1262
 
 
1263
                        foreach ($topic_ids as $topic_id)
 
1264
                        {
 
1265
                                if ($global_announce_list && isset($global_announce_list[$topic_id]))
 
1266
                                {
 
1267
                                        $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
 
1268
                                }
 
1269
                                else
 
1270
                                {
 
1271
                                        $last_read[$topic_id] = $user_lastmark;
 
1272
                                }
 
1273
                        }
 
1274
                }
 
1275
        }
 
1276
 
 
1277
        return $last_read;
 
1278
}
 
1279
 
 
1280
/**
 
1281
* Check for read forums and update topic tracking info accordingly
 
1282
*
 
1283
* @param int $forum_id the forum id to check
 
1284
* @param int $forum_last_post_time the forums last post time
 
1285
* @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled
 
1286
* @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time
 
1287
*
 
1288
* @return true if complete forum got marked read, else false.
 
1289
*/
 
1290
function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
 
1291
{
 
1292
        global $db, $tracking_topics, $user, $config;
 
1293
 
 
1294
        // Determine the users last forum mark time if not given.
 
1295
        if ($mark_time_forum === false)
 
1296
        {
 
1297
                if ($config['load_db_lastread'] && $user->data['is_registered'])
 
1298
                {
 
1299
                        $mark_time_forum = (!empty($f_mark_time)) ? $f_mark_time : $user->data['user_lastmark'];
 
1300
                }
 
1301
                else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
1302
                {
 
1303
                        $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
 
1304
                        $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
 
1305
 
 
1306
                        if (!$user->data['is_registered'])
 
1307
                        {
 
1308
                                $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
 
1309
                        }
 
1310
 
 
1311
                        $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark'];
 
1312
                }
 
1313
        }
 
1314
 
 
1315
        // Check the forum for any left unread topics.
 
1316
        // If there are none, we mark the forum as read.
 
1317
        if ($config['load_db_lastread'] && $user->data['is_registered'])
 
1318
        {
 
1319
                if ($mark_time_forum >= $forum_last_post_time)
 
1320
                {
 
1321
                        // We do not need to mark read, this happened before. Therefore setting this to true
 
1322
                        $row = true;
 
1323
                }
 
1324
                else
 
1325
                {
 
1326
                        $sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE . ' t
 
1327
                                LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')
 
1328
                                WHERE t.forum_id = ' . $forum_id . '
 
1329
                                        AND t.topic_last_post_time > ' . $mark_time_forum . '
 
1330
                                        AND t.topic_moved_id = 0
 
1331
                                        AND (tt.topic_id IS NULL OR tt.mark_time < t.topic_last_post_time)
 
1332
                                GROUP BY t.forum_id';
 
1333
                        $result = $db->sql_query_limit($sql, 1);
 
1334
                        $row = $db->sql_fetchrow($result);
 
1335
                        $db->sql_freeresult($result);
 
1336
                }
 
1337
        }
 
1338
        else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 
1339
        {
 
1340
                // Get information from cookie
 
1341
                $row = false;
 
1342
 
 
1343
                if (!isset($tracking_topics['tf'][$forum_id]))
 
1344
                {
 
1345
                        // We do not need to mark read, this happened before. Therefore setting this to true
 
1346
                        $row = true;
 
1347
                }
 
1348
                else
 
1349
                {
 
1350
                        $sql = 'SELECT topic_id
 
1351
                                FROM ' . TOPICS_TABLE . '
 
1352
                                WHERE forum_id = ' . $forum_id . '
 
1353
                                        AND topic_last_post_time > ' . $mark_time_forum . '
 
1354
                                        AND topic_moved_id = 0';
 
1355
                        $result = $db->sql_query($sql);
 
1356
 
 
1357
                        $check_forum = $tracking_topics['tf'][$forum_id];
 
1358
                        $unread = false;
 
1359
 
 
1360
                        while ($row = $db->sql_fetchrow($result))
 
1361
                        {
 
1362
                                if (!in_array(base_convert($row['topic_id'], 10, 36), array_keys($check_forum)))
 
1363
                                {
 
1364
                                        $unread = true;
 
1365
                                        break;
 
1366
                                }
 
1367
                        }
 
1368
                        $db->sql_freeresult($result);
 
1369
 
 
1370
                        $row = $unread;
 
1371
                }
 
1372
        }
 
1373
        else
 
1374
        {
 
1375
                $row = true;
 
1376
        }
 
1377
 
 
1378
        if (!$row)
 
1379
        {
 
1380
                markread('topics', $forum_id);
 
1381
                return true;
 
1382
        }
 
1383
 
 
1384
        return false;
 
1385
}
 
1386
 
 
1387
/**
 
1388
* Transform an array into a serialized format
 
1389
*/
 
1390
function tracking_serialize($input)
 
1391
{
 
1392
        $out = '';
 
1393
        foreach ($input as $key => $value)
 
1394
        {
 
1395
                if (is_array($value))
 
1396
                {
 
1397
                        $out .= $key . ':(' . tracking_serialize($value) . ');';
 
1398
                }
 
1399
                else
 
1400
                {
 
1401
                        $out .= $key . ':' . $value . ';';
 
1402
                }
 
1403
        }
 
1404
        return $out;
 
1405
}
 
1406
 
 
1407
/**
 
1408
* Transform a serialized array into an actual array
 
1409
*/
 
1410
function tracking_unserialize($string, $max_depth = 3)
 
1411
{
 
1412
        $n = strlen($string);
 
1413
        if ($n > 10010)
 
1414
        {
 
1415
                die('Invalid data supplied');
 
1416
        }
 
1417
        $data = $stack = array();
 
1418
        $key = '';
 
1419
        $mode = 0;
 
1420
        $level = &$data;
 
1421
        for ($i = 0; $i < $n; ++$i)
 
1422
        {
 
1423
                switch ($mode)
 
1424
                {
 
1425
                        case 0:
 
1426
                                switch ($string[$i])
 
1427
                                {
 
1428
                                        case ':':
 
1429
                                                $level[$key] = 0;
 
1430
                                                $mode = 1;
 
1431
                                        break;
 
1432
                                        case ')':
 
1433
                                                unset($level);
 
1434
                                                $level = array_pop($stack);
 
1435
                                                $mode = 3;
 
1436
                                        break;
 
1437
                                        default:
 
1438
                                                $key .= $string[$i];
 
1439
                                }
 
1440
                        break;
 
1441
 
 
1442
                        case 1:
 
1443
                                switch ($string[$i])
 
1444
                                {
 
1445
                                        case '(':
 
1446
                                                if (sizeof($stack) >= $max_depth)
 
1447
                                                {
 
1448
                                                        die('Invalid data supplied');
 
1449
                                                }
 
1450
                                                $stack[] = &$level;
 
1451
                                                $level[$key] = array();
 
1452
                                                $level = &$level[$key];
 
1453
                                                $key = '';
 
1454
                                                $mode = 0;
 
1455
                                        break;
 
1456
                                        default:
 
1457
                                                $level[$key] = $string[$i];
 
1458
                                                $mode = 2;
 
1459
                                        break;
 
1460
                                }
 
1461
                        break;
 
1462
                        
 
1463
                        case 2:
 
1464
                                switch ($string[$i])
 
1465
                                {
 
1466
                                        case ')':
 
1467
                                                unset($level);
 
1468
                                                $level = array_pop($stack);
 
1469
                                                $mode = 3;
 
1470
                                        break;
 
1471
                                        case ';':
 
1472
                                                $key = '';
 
1473
                                                $mode = 0;
 
1474
                                        break;
 
1475
                                        default:
 
1476
                                                $level[$key] .= $string[$i];
 
1477
                                        break;
 
1478
                                }
 
1479
                        break;
 
1480
                        
 
1481
                        case 3:
 
1482
                                switch ($string[$i])
 
1483
                                {
 
1484
                                        case ')':
 
1485
                                                unset($level);
 
1486
                                                $level = array_pop($stack);
 
1487
                                        break;
 
1488
                                        case ';':
 
1489
                                                $key = '';
 
1490
                                                $mode = 0;
 
1491
                                        break;
 
1492
                                        default:
 
1493
                                                die('Invalid data supplied');
 
1494
                                        break;
 
1495
                                }
 
1496
                        break;
 
1497
                }
 
1498
        }
 
1499
 
 
1500
        if (sizeof($stack) != 0 || ($mode != 0 && $mode != 3))
 
1501
        {
 
1502
                die('Invalid data supplied');
 
1503
        }
 
1504
        
 
1505
        return $level;
 
1506
}
 
1507
 
 
1508
// Pagination functions
 
1509
 
 
1510
/**
 
1511
* Pagination routine, generates page number sequence
 
1512
* tpl_prefix is for using different pagination blocks at one page
 
1513
*/
 
1514
function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '')
 
1515
{
 
1516
        global $template, $user;
 
1517
 
 
1518
        // Make sure $per_page is a valid value
 
1519
        $per_page = ($per_page <= 0) ? 1 : $per_page;
 
1520
 
 
1521
        $seperator = '<span class="page-sep">' . $user->lang['COMMA_SEPARATOR'] . '</span>';
 
1522
        $total_pages = ceil($num_items / $per_page);
 
1523
 
 
1524
        if ($total_pages == 1 || !$num_items)
 
1525
        {
 
1526
                return false;
 
1527
        }
 
1528
 
 
1529
        $on_page = floor($start_item / $per_page) + 1;
 
1530
        $url_delim = (strpos($base_url, '?') === false) ? '?' : '&amp;';
 
1531
 
 
1532
        $page_string = ($on_page == 1) ? '<strong>1</strong>' : '<a href="' . $base_url . '">1</a>';
 
1533
 
 
1534
        if ($total_pages > 5)
 
1535
        {
 
1536
                $start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
 
1537
                $end_cnt = max(min($total_pages, $on_page + 4), 6);
 
1538
 
 
1539
                $page_string .= ($start_cnt > 1) ? ' ... ' : $seperator;
 
1540
 
 
1541
                for ($i = $start_cnt + 1; $i < $end_cnt; $i++)
 
1542
                {
 
1543
                        $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
 
1544
                        if ($i < $end_cnt - 1)
 
1545
                        {
 
1546
                                $page_string .= $seperator;
 
1547
                        }
 
1548
                }
 
1549
 
 
1550
                $page_string .= ($end_cnt < $total_pages) ? ' ... ' : $seperator;
 
1551
        }
 
1552
        else
 
1553
        {
 
1554
                $page_string .= $seperator;
 
1555
 
 
1556
                for ($i = 2; $i < $total_pages; $i++)
 
1557
                {
 
1558
                        $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
 
1559
                        if ($i < $total_pages)
 
1560
                        {
 
1561
                                $page_string .= $seperator;
 
1562
                        }
 
1563
                }
 
1564
        }
 
1565
 
 
1566
        $page_string .= ($on_page == $total_pages) ? '<strong>' . $total_pages . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($total_pages - 1) * $per_page) . '">' . $total_pages . '</a>';
 
1567
 
 
1568
        if ($add_prevnext_text)
 
1569
        {
 
1570
                if ($on_page != 1)
 
1571
                {
 
1572
                        $page_string = '<a href="' . $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page) . '">' . $user->lang['PREVIOUS'] . '</a>&nbsp;&nbsp;' . $page_string;
 
1573
                }
 
1574
 
 
1575
                if ($on_page != $total_pages)
 
1576
                {
 
1577
                        $page_string .= '&nbsp;&nbsp;<a href="' . $base_url . "{$url_delim}start=" . ($on_page * $per_page) . '">' . $user->lang['NEXT'] . '</a>';
 
1578
                }
 
1579
        }
 
1580
 
 
1581
        $template->assign_vars(array(
 
1582
                $tpl_prefix . 'BASE_URL'                => $base_url,
 
1583
                'A_' . $tpl_prefix . 'BASE_URL' => addslashes($base_url),
 
1584
                $tpl_prefix . 'PER_PAGE'                => $per_page,
 
1585
 
 
1586
                $tpl_prefix . 'PREVIOUS_PAGE'   => ($on_page == 1) ? '' : $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page),
 
1587
                $tpl_prefix . 'NEXT_PAGE'               => ($on_page == $total_pages) ? '' : $base_url . "{$url_delim}start=" . ($on_page * $per_page),
 
1588
                $tpl_prefix . 'TOTAL_PAGES'             => $total_pages,
 
1589
        ));
 
1590
 
 
1591
        return $page_string;
 
1592
}
 
1593
 
 
1594
/**
 
1595
* Return current page (pagination)
 
1596
*/
 
1597
function on_page($num_items, $per_page, $start)
 
1598
{
 
1599
        global $template, $user;
 
1600
 
 
1601
        // Make sure $per_page is a valid value
 
1602
        $per_page = ($per_page <= 0) ? 1 : $per_page;
 
1603
 
 
1604
        $on_page = floor($start / $per_page) + 1;
 
1605
 
 
1606
        $template->assign_vars(array(
 
1607
                'ON_PAGE'               => $on_page)
 
1608
        );
 
1609
 
 
1610
        return sprintf($user->lang['PAGE_OF'], $on_page, max(ceil($num_items / $per_page), 1));
 
1611
}
 
1612
 
 
1613
// Server functions (building urls, redirecting...)
 
1614
 
 
1615
/**
 
1616
* Append session id to url.
 
1617
* This function supports hooks.
 
1618
*
 
1619
* @param string $url The url the session id needs to be appended to (can have params)
 
1620
* @param mixed $params String or array of additional url parameters
 
1621
* @param bool $is_amp Is url using &amp; (true) or & (false)
 
1622
* @param string $session_id Possibility to use a custom session id instead of the global one
 
1623
*
 
1624
* Examples:
 
1625
* <code>
 
1626
* append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&amp;f=2");
 
1627
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&amp;f=2');
 
1628
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false);
 
1629
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2));
 
1630
* </code>
 
1631
*
 
1632
*/
 
1633
function append_sid($url, $params = false, $is_amp = true, $session_id = false)
 
1634
{
 
1635
        global $_SID, $_EXTRA_URL, $phpbb_hook;
 
1636
 
 
1637
        // Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropiatly.
 
1638
        // They could mimick most of what is within this function
 
1639
        if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id))
 
1640
        {
 
1641
                if ($phpbb_hook->hook_return(__FUNCTION__))
 
1642
                {
 
1643
                        return $phpbb_hook->hook_return_result(__FUNCTION__);
 
1644
                }
 
1645
        }
 
1646
 
 
1647
        // Assign sid if session id is not specified
 
1648
        if ($session_id === false)
 
1649
        {
 
1650
                $session_id = $_SID;
 
1651
        }
 
1652
 
 
1653
        $amp_delim = ($is_amp) ? '&amp;' : '&';
 
1654
        $url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim;
 
1655
 
 
1656
        // Appending custom url parameter?
 
1657
        $append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : '';
 
1658
 
 
1659
        $anchor = '';
 
1660
        if (strpos($url, '#') !== false)
 
1661
        {
 
1662
                list($url, $anchor) = explode('#', $url, 2);
 
1663
                $anchor = '#' . $anchor;
 
1664
        }
 
1665
        else if (!is_array($params) && strpos($params, '#') !== false)
 
1666
        {
 
1667
                list($params, $anchor) = explode('#', $params, 2);
 
1668
                $anchor = '#' . $anchor;
 
1669
        }
 
1670
 
 
1671
        // Use the short variant if possible ;)
 
1672
        if ($params === false)
 
1673
        {
 
1674
                // Append session id
 
1675
                if (!$session_id)
 
1676
                {
 
1677
                        return $url . (($append_url) ? $url_delim . $append_url : '') . $anchor;
 
1678
                }
 
1679
                else
 
1680
                {
 
1681
                        return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id . $anchor;
 
1682
                }
 
1683
        }
 
1684
 
 
1685
        // Build string if parameters are specified as array
 
1686
        if (is_array($params))
 
1687
        {
 
1688
                $output = array();
 
1689
 
 
1690
                foreach ($params as $key => $item)
 
1691
                {
 
1692
                        if ($item === NULL)
 
1693
                        {
 
1694
                                continue;
 
1695
                        }
 
1696
 
 
1697
                        if ($key == '#')
 
1698
                        {
 
1699
                                $anchor = '#' . $item;
 
1700
                                continue;
 
1701
                        }
 
1702
 
 
1703
                        $output[] = $key . '=' . $item;
 
1704
                }
 
1705
 
 
1706
                $params = implode($amp_delim, $output);
 
1707
        }
 
1708
 
 
1709
        // Append session id and parameters (even if they are empty)
 
1710
        // If parameters are empty, the developer can still append his/her parameters without caring about the delimiter
 
1711
        return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ? '' : $amp_delim . 'sid=' . $session_id) . $anchor;
 
1712
}
 
1713
 
 
1714
/**
 
1715
* Generate board url (example: http://www.example.com/phpBB)
 
1716
* @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com)
 
1717
*/
 
1718
function generate_board_url($without_script_path = false)
 
1719
{
 
1720
        global $config, $user;
 
1721
 
 
1722
        $server_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
 
1723
        $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
 
1724
 
 
1725
        // Forcing server vars is the only way to specify/override the protocol
 
1726
        if ($config['force_server_vars'] || !$server_name)
 
1727
        {
 
1728
                $server_protocol = ($config['server_protocol']) ? $config['server_protocol'] : (($config['cookie_secure']) ? 'https://' : 'http://');
 
1729
                $server_name = $config['server_name'];
 
1730
                $server_port = (int) $config['server_port'];
 
1731
                $script_path = $config['script_path'];
 
1732
 
 
1733
                $url = $server_protocol . $server_name;
 
1734
        }
 
1735
        else
 
1736
        {
 
1737
                // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection
 
1738
                $cookie_secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 1 : 0;
 
1739
                $url = (($cookie_secure) ? 'https://' : 'http://') . $server_name;
 
1740
 
 
1741
                $script_path = $user->page['root_script_path'];
 
1742
        }
 
1743
 
 
1744
        if ($server_port && (($config['cookie_secure'] && $server_port <> 443) || (!$config['cookie_secure'] && $server_port <> 80)))
 
1745
        {
 
1746
                $url .= ':' . $server_port;
 
1747
        }
 
1748
 
 
1749
        if (!$without_script_path)
 
1750
        {
 
1751
                $url .= $script_path;
 
1752
        }
 
1753
 
 
1754
        // Strip / from the end
 
1755
        if (substr($url, -1, 1) == '/')
 
1756
        {
 
1757
                $url = substr($url, 0, -1);
 
1758
        }
 
1759
 
 
1760
        return $url;
 
1761
}
 
1762
 
 
1763
/**
 
1764
* Redirects the user to another page then exits the script nicely
 
1765
*/
 
1766
function redirect($url, $return = false)
 
1767
{
 
1768
        global $db, $cache, $config, $user, $phpbb_root_path;
 
1769
 
 
1770
        if (empty($user->lang))
 
1771
        {
 
1772
                $user->add_lang('common');
 
1773
        }
 
1774
 
 
1775
        if (!$return)
 
1776
        {
 
1777
                garbage_collection();
 
1778
        }
 
1779
 
 
1780
        // Make sure no &amp;'s are in, this will break the redirect
 
1781
        $url = str_replace('&amp;', '&', $url);
 
1782
 
 
1783
        // Determine which type of redirect we need to handle...
 
1784
        $url_parts = parse_url($url);
 
1785
 
 
1786
        if ($url_parts === false)
 
1787
        {
 
1788
                // Malformed url, redirect to current page...
 
1789
                $url = generate_board_url() . '/' . $user->page['page'];
 
1790
        }
 
1791
        else if (!empty($url_parts['scheme']) && !empty($url_parts['host']))
 
1792
        {
 
1793
                // Full URL
 
1794
        }
 
1795
        else if ($url[0] == '/')
 
1796
        {
 
1797
                // Absolute uri, prepend direct url...
 
1798
                $url = generate_board_url(true) . $url;
 
1799
        }
 
1800
        else
 
1801
        {
 
1802
                // Relative uri
 
1803
                $pathinfo = pathinfo($url);
 
1804
 
 
1805
                // Is the uri pointing to the current directory?
 
1806
                if ($pathinfo['dirname'] == '.')
 
1807
                {
 
1808
                        $url = str_replace('./', '', $url);
 
1809
 
 
1810
                        // Strip / from the beginning
 
1811
                        if ($url && substr($url, 0, 1) == '/')
 
1812
                        {
 
1813
                                $url = substr($url, 1);
 
1814
                        }
 
1815
 
 
1816
                        if ($user->page['page_dir'])
 
1817
                        {
 
1818
                                $url = generate_board_url() . '/' . $user->page['page_dir'] . '/' . $url;
 
1819
                        }
 
1820
                        else
 
1821
                        {
 
1822
                                $url = generate_board_url() . '/' . $url;
 
1823
                        }
 
1824
                }
 
1825
                else
 
1826
                {
 
1827
                        // Used ./ before, but $phpbb_root_path is working better with urls within another root path
 
1828
                        $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path)));
 
1829
                        $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
 
1830
                        $intersection = array_intersect_assoc($root_dirs, $page_dirs);
 
1831
 
 
1832
                        $root_dirs = array_diff_assoc($root_dirs, $intersection);
 
1833
                        $page_dirs = array_diff_assoc($page_dirs, $intersection);
 
1834
 
 
1835
                        $dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
 
1836
 
 
1837
                        // Strip / from the end
 
1838
                        if ($dir && substr($dir, -1, 1) == '/')
 
1839
                        {
 
1840
                                $dir = substr($dir, 0, -1);
 
1841
                        }
 
1842
 
 
1843
                        // Strip / from the beginning
 
1844
                        if ($dir && substr($dir, 0, 1) == '/')
 
1845
                        {
 
1846
                                $dir = substr($dir, 1);
 
1847
                        }
 
1848
 
 
1849
                        $url = str_replace($pathinfo['dirname'] . '/', '', $url);
 
1850
 
 
1851
                        // Strip / from the beginning
 
1852
                        if (substr($url, 0, 1) == '/')
 
1853
                        {
 
1854
                                $url = substr($url, 1);
 
1855
                        }
 
1856
 
 
1857
                        $url = $dir . '/' . $url;
 
1858
                        $url = generate_board_url() . '/' . $url;
 
1859
                }
 
1860
        }
 
1861
 
 
1862
        // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
 
1863
        if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false)
 
1864
        {
 
1865
                trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
 
1866
        }
 
1867
 
 
1868
        // Now, also check the protocol and for a valid url the last time...
 
1869
        $allowed_protocols = array('http', 'https', 'ftp', 'ftps');
 
1870
        $url_parts = parse_url($url);
 
1871
 
 
1872
        if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols))
 
1873
        {
 
1874
                trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
 
1875
        }
 
1876
 
 
1877
        if ($return)
 
1878
        {
 
1879
                return $url;
 
1880
        }
 
1881
 
 
1882
        // Redirect via an HTML form for PITA webservers
 
1883
        if (@preg_match('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE')))
 
1884
        {
 
1885
                header('Refresh: 0; URL=' . $url);
 
1886
 
 
1887
                echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
 
1888
                echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '" xml:lang="' . $user->lang['USER_LANG'] . '">';
 
1889
                echo '<head>';
 
1890
                echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
 
1891
                echo '<meta http-equiv="refresh" content="0; url=' . str_replace('&', '&amp;', $url) . '" />';
 
1892
                echo '<title>' . $user->lang['REDIRECT'] . '</title>';
 
1893
                echo '</head>';
 
1894
                echo '<body>';
 
1895
                echo '<div style="text-align: center;">' . sprintf($user->lang['URL_REDIRECT'], '<a href="' . str_replace('&', '&amp;', $url) . '">', '</a>') . '</div>';
 
1896
                echo '</body>';
 
1897
                echo '</html>';
 
1898
 
 
1899
                exit;
 
1900
        }
 
1901
 
 
1902
        // Behave as per HTTP/1.1 spec for others
 
1903
        header('Location: ' . $url);
 
1904
        exit;
 
1905
}
 
1906
 
 
1907
/**
 
1908
* Re-Apply session id after page reloads
 
1909
*/
 
1910
function reapply_sid($url)
 
1911
{
 
1912
        global $phpEx, $phpbb_root_path;
 
1913
 
 
1914
        if ($url === "index.$phpEx")
 
1915
        {
 
1916
                return append_sid("index.$phpEx");
 
1917
        }
 
1918
        else if ($url === "{$phpbb_root_path}index.$phpEx")
 
1919
        {
 
1920
                return append_sid("{$phpbb_root_path}index.$phpEx");
 
1921
        }
 
1922
 
 
1923
        // Remove previously added sid
 
1924
        if (strpos($url, '?sid=') !== false)
 
1925
        {
 
1926
                $url = preg_replace('/(\?)sid=[a-z0-9]+(&amp;|&)?/', '\1', $url);
 
1927
        }
 
1928
        else if (strpos($url, '&sid=') !== false)
 
1929
        {
 
1930
                $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
 
1931
        }
 
1932
        else if (strpos($url, '&amp;sid=') !== false)
 
1933
        {
 
1934
                $url = preg_replace('/&amp;sid=[a-z0-9]+(&amp;)?/', '\1', $url);
 
1935
        }
 
1936
 
 
1937
        return append_sid($url);
 
1938
}
 
1939
 
 
1940
/**
 
1941
* Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url
 
1942
*/
 
1943
function build_url($strip_vars = false)
 
1944
{
 
1945
        global $user, $phpbb_root_path;
 
1946
 
 
1947
        // Append SID
 
1948
        $redirect = append_sid($user->page['page'], false, false);
 
1949
 
 
1950
        // Add delimiter if not there...
 
1951
        if (strpos($redirect, '?') === false)
 
1952
        {
 
1953
                $redirect .= '?';
 
1954
        }
 
1955
 
 
1956
        // Strip vars...
 
1957
        if ($strip_vars !== false && strpos($redirect, '?') !== false)
 
1958
        {
 
1959
                if (!is_array($strip_vars))
 
1960
                {
 
1961
                        $strip_vars = array($strip_vars);
 
1962
                }
 
1963
 
 
1964
                $query = $_query = array();
 
1965
 
 
1966
                $args = substr($redirect, strpos($redirect, '?') + 1);
 
1967
                $args = ($args) ? explode('&', $args) : array();
 
1968
                $redirect = substr($redirect, 0, strpos($redirect, '?'));
 
1969
 
 
1970
                foreach ($args as $argument)
 
1971
                {
 
1972
                        $arguments = explode('=', $argument);
 
1973
                        $key = $arguments[0];
 
1974
                        unset($arguments[0]);
 
1975
 
 
1976
                        $query[$key] = implode('=', $arguments);
 
1977
                }
 
1978
 
 
1979
                // Strip the vars off
 
1980
                foreach ($strip_vars as $strip)
 
1981
                {
 
1982
                        if (isset($query[$strip]))
 
1983
                        {
 
1984
                                unset($query[$strip]);
 
1985
                        }
 
1986
                }
 
1987
        
 
1988
                // Glue the remaining parts together... already urlencoded
 
1989
                foreach ($query as $key => $value)
 
1990
                {
 
1991
                        $_query[] = $key . '=' . $value;
 
1992
                }
 
1993
                $query = implode('&', $_query);
 
1994
 
 
1995
                $redirect .= ($query) ? '?' . $query : '';
 
1996
        }
 
1997
 
 
1998
        return $phpbb_root_path . str_replace('&', '&amp;', $redirect);
 
1999
}
 
2000
 
 
2001
/**
 
2002
* Meta refresh assignment
 
2003
*/
 
2004
function meta_refresh($time, $url)
 
2005
{
 
2006
        global $template;
 
2007
 
 
2008
        $url = redirect($url, true);
 
2009
 
 
2010
        // For XHTML compatibility we change back & to &amp;
 
2011
        $template->assign_vars(array(
 
2012
                'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . str_replace('&', '&amp;', $url) . '" />')
 
2013
        );
 
2014
}
 
2015
 
 
2016
//Form validation
 
2017
 
 
2018
/**
 
2019
* Add a secret token to the form (requires the S_FORM_TOKEN template variable)
 
2020
* @param string  $form_name The name of the form; has to match the name used in check_form_key, otherwise no restrictions apply
 
2021
*/
 
2022
function add_form_key($form_name)
 
2023
{
 
2024
        global $config, $template, $user;
 
2025
        $now = time();
 
2026
        $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : '';
 
2027
        $token = sha1($now . $user->data['user_form_salt'] . $form_name . $token_sid);
 
2028
 
 
2029
        $s_fields = build_hidden_fields(array(
 
2030
                        'creation_time' => $now,
 
2031
                        'form_token'    => $token,
 
2032
        ));
 
2033
        $template->assign_vars(array(
 
2034
                        'S_FORM_TOKEN'  => $s_fields,
 
2035
        ));
 
2036
}
 
2037
 
 
2038
/**
 
2039
* Check the form key. Required for all altering actions not secured by confirm_box
 
2040
* @param string  $form_name The name of the form; has to match the name used in add_form_key, otherwise no restrictions apply
 
2041
* @param int $timespan The maximum acceptable age for a submitted form in seconds. Defaults to the config setting.
 
2042
* @param string $return_page The address for the return link
 
2043
* @param bool $trigger If true, the function will triger an error when encountering an invalid form
 
2044
* @param int $minimum_time The minimum acceptable age for a submitted form in seconds
 
2045
*/
 
2046
function check_form_key($form_name, $timespan = false, $return_page = '', $trigger = false, $minimum_time = false)
 
2047
{
 
2048
        global $config, $user;
 
2049
 
 
2050
        if ($timespan === false)
 
2051
        {
 
2052
                // we enforce a minimum value of half a minute here.
 
2053
                $timespan = ($config['form_token_lifetime'] == -1) ? -1 : max(30, $config['form_token_lifetime']);
 
2054
        }
 
2055
        if ($minimum_time === false)
 
2056
        {
 
2057
                $minimum_time = (int) $config['form_token_mintime'];
 
2058
        }
 
2059
        
 
2060
        if (isset($_POST['creation_time']) && isset($_POST['form_token']))
 
2061
        {
 
2062
                $creation_time  = abs(request_var('creation_time', 0));
 
2063
                $token = request_var('form_token', '');
 
2064
 
 
2065
                $diff = (time() - $creation_time);
 
2066
 
 
2067
                if (($diff >= $minimum_time) && (($diff <= $timespan) || $timespan == -1))
 
2068
                {
 
2069
                        $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : '';
 
2070
                        
 
2071
                        $key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid);
 
2072
                        if ($key === $token)
 
2073
                        {
 
2074
                                return true;
 
2075
                        }
 
2076
                }
 
2077
        }
 
2078
        if ($trigger)
 
2079
        {
 
2080
                trigger_error($user->lang['FORM_INVALID'] . $return_page);
 
2081
        }
 
2082
        return false;
 
2083
}
 
2084
 
 
2085
// Message/Login boxes
 
2086
 
 
2087
/**
 
2088
* Build Confirm box
 
2089
* @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
 
2090
* @param string $title Title/Message used for confirm box.
 
2091
*               message text is _CONFIRM appended to title.
 
2092
*               If title cannot be found in user->lang a default one is displayed
 
2093
*               If title_CONFIRM cannot be found in user->lang the text given is used.
 
2094
* @param string $hidden Hidden variables
 
2095
* @param string $html_body Template used for confirm box
 
2096
* @param string $u_action Custom form action
 
2097
*/
 
2098
function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
 
2099
{
 
2100
        global $user, $template, $db;
 
2101
        global $phpEx, $phpbb_root_path;
 
2102
 
 
2103
        if (isset($_POST['cancel']))
 
2104
        {
 
2105
                return false;
 
2106
        }
 
2107
 
 
2108
        $confirm = false;
 
2109
        if (isset($_POST['confirm']))
 
2110
        {
 
2111
                // language frontier
 
2112
                if ($_POST['confirm'] === $user->lang['YES'])
 
2113
                {
 
2114
                        $confirm = true;
 
2115
                }
 
2116
        }
 
2117
 
 
2118
        if ($check && $confirm)
 
2119
        {
 
2120
                $user_id = request_var('user_id', 0);
 
2121
                $session_id = request_var('sess', '');
 
2122
                $confirm_key = request_var('confirm_key', '');
 
2123
 
 
2124
                if ($user_id != $user->data['user_id'] || $session_id != $user->session_id || !$confirm_key || !$user->data['user_last_confirm_key'] || $confirm_key != $user->data['user_last_confirm_key'])
 
2125
                {
 
2126
                        return false;
 
2127
                }
 
2128
 
 
2129
                // Reset user_last_confirm_key
 
2130
                $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = ''
 
2131
                        WHERE user_id = " . $user->data['user_id'];
 
2132
                $db->sql_query($sql);
 
2133
 
 
2134
                return true;
 
2135
        }
 
2136
        else if ($check)
 
2137
        {
 
2138
                return false;
 
2139
        }
 
2140
 
 
2141
        $s_hidden_fields = build_hidden_fields(array(
 
2142
                'user_id'       => $user->data['user_id'],
 
2143
                'sess'          => $user->session_id,
 
2144
                'sid'           => $user->session_id)
 
2145
        );
 
2146
 
 
2147
        // generate activation key
 
2148
        $confirm_key = gen_rand_string(10);
 
2149
 
 
2150
        if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 
2151
        {
 
2152
                adm_page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
 
2153
        }
 
2154
        else
 
2155
        {
 
2156
                page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
 
2157
        }
 
2158
 
 
2159
        $template->set_filenames(array(
 
2160
                'body' => $html_body)
 
2161
        );
 
2162
 
 
2163
        // If activation key already exist, we better do not re-use the key (something very strange is going on...)
 
2164
        if (request_var('confirm_key', ''))
 
2165
        {
 
2166
                // This should not occur, therefore we cancel the operation to safe the user
 
2167
                return false;
 
2168
        }
 
2169
 
 
2170
        // re-add sid / transform & to &amp; for user->page (user->page is always using &)
 
2171
        $use_page = ($u_action) ? $phpbb_root_path . $u_action : $phpbb_root_path . str_replace('&', '&amp;', $user->page['page']);
 
2172
        $u_action = reapply_sid($use_page);
 
2173
        $u_action .= ((strpos($u_action, '?') === false) ? '?' : '&amp;') . 'confirm_key=' . $confirm_key;
 
2174
 
 
2175
        $template->assign_vars(array(
 
2176
                'MESSAGE_TITLE'         => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
 
2177
                'MESSAGE_TEXT'          => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
 
2178
 
 
2179
                'YES_VALUE'                     => $user->lang['YES'],
 
2180
                'S_CONFIRM_ACTION'      => $u_action,
 
2181
                'S_HIDDEN_FIELDS'       => $hidden . $s_hidden_fields)
 
2182
        );
 
2183
 
 
2184
        $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
 
2185
                WHERE user_id = " . $user->data['user_id'];
 
2186
        $db->sql_query($sql);
 
2187
 
 
2188
        if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 
2189
        {
 
2190
                adm_page_footer();
 
2191
        }
 
2192
        else
 
2193
        {
 
2194
                page_footer();
 
2195
        }
 
2196
}
 
2197
 
 
2198
/**
 
2199
* Generate login box or verify password
 
2200
*/
 
2201
function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
 
2202
{
 
2203
        global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
 
2204
 
 
2205
        $err = '';
 
2206
 
 
2207
        // Make sure user->setup() has been called
 
2208
        if (empty($user->lang))
 
2209
        {
 
2210
                $user->setup();
 
2211
        }
 
2212
 
 
2213
        // Print out error if user tries to authenticate as an administrator without having the privileges...
 
2214
        if ($admin && !$auth->acl_get('a_'))
 
2215
        {
 
2216
                // Not authd
 
2217
                // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
 
2218
                if ($user->data['is_registered'])
 
2219
                {
 
2220
                        add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
 
2221
                }
 
2222
                trigger_error('NO_AUTH_ADMIN');
 
2223
        }
 
2224
 
 
2225
        if (isset($_POST['login']))
 
2226
        {
 
2227
                // Get credential
 
2228
                if ($admin)
 
2229
                {
 
2230
                        $credential = request_var('credential', '');
 
2231
 
 
2232
                        if (strspn($credential, 'abcdef0123456789') !== strlen($credential) || strlen($credential) != 32)
 
2233
                        {
 
2234
                                if ($user->data['is_registered'])
 
2235
                                {
 
2236
                                        add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
 
2237
                                }
 
2238
                                trigger_error('NO_AUTH_ADMIN');
 
2239
                        }
 
2240
 
 
2241
                        $password       = request_var('password_' . $credential, '', true);
 
2242
                }
 
2243
                else
 
2244
                {
 
2245
                        $password       = request_var('password', '', true);
 
2246
                }
 
2247
 
 
2248
                $username       = request_var('username', '', true);
 
2249
                $autologin      = (!empty($_POST['autologin'])) ? true : false;
 
2250
                $viewonline = (!empty($_POST['viewonline'])) ? 0 : 1;
 
2251
                $admin          = ($admin) ? 1 : 0;
 
2252
                $viewonline = ($admin) ? $user->data['session_viewonline'] : $viewonline;
 
2253
 
 
2254
                // Check if the supplied username is equal to the one stored within the database if re-authenticating
 
2255
                if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username']))
 
2256
                {
 
2257
                        // We log the attempt to use a different username...
 
2258
                        add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
 
2259
                        trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
 
2260
                }
 
2261
 
 
2262
                // If authentication is successful we redirect user to previous page
 
2263
                $result = $auth->login($username, $password, $autologin, $viewonline, $admin);
 
2264
 
 
2265
                // If admin authentication and login, we will log if it was a success or not...
 
2266
                // We also break the operation on the first non-success login - it could be argued that the user already knows
 
2267
                if ($admin)
 
2268
                {
 
2269
                        if ($result['status'] == LOGIN_SUCCESS)
 
2270
                        {
 
2271
                                add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
 
2272
                        }
 
2273
                        else
 
2274
                        {
 
2275
                                // Only log the failed attempt if a real user tried to.
 
2276
                                // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
 
2277
                                if ($user->data['is_registered'])
 
2278
                                {
 
2279
                                        add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
 
2280
                                }
 
2281
                        }
 
2282
                }
 
2283
 
 
2284
                // The result parameter is always an array, holding the relevant information...
 
2285
                if ($result['status'] == LOGIN_SUCCESS)
 
2286
                {
 
2287
                        $redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx");
 
2288
                        $message = ($l_success) ? $l_success : $user->lang['LOGIN_REDIRECT'];
 
2289
                        $l_redirect = ($admin) ? $user->lang['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx" || $redirect === "index.$phpEx") ? $user->lang['RETURN_INDEX'] : $user->lang['RETURN_PAGE']);
 
2290
 
 
2291
                        // append/replace SID (may change during the session for AOL users)
 
2292
                        $redirect = reapply_sid($redirect);
 
2293
 
 
2294
                        // Special case... the user is effectively banned, but we allow founders to login
 
2295
                        if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != USER_FOUNDER)
 
2296
                        {
 
2297
                                return;
 
2298
                        }
 
2299
 
 
2300
                        meta_refresh(3, $redirect);
 
2301
                        trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>'));
 
2302
                }
 
2303
 
 
2304
                // Something failed, determine what...
 
2305
                if ($result['status'] == LOGIN_BREAK)
 
2306
                {
 
2307
                        trigger_error($result['error_msg'], E_USER_ERROR);
 
2308
                }
 
2309
 
 
2310
                // Special cases... determine
 
2311
                switch ($result['status'])
 
2312
                {
 
2313
                        case LOGIN_ERROR_ATTEMPTS:
 
2314
 
 
2315
                                // Show confirm image
 
2316
                                $sql = 'DELETE FROM ' . CONFIRM_TABLE . "
 
2317
                                        WHERE session_id = '" . $db->sql_escape($user->session_id) . "'
 
2318
                                                AND confirm_type = " . CONFIRM_LOGIN;
 
2319
                                $db->sql_query($sql);
 
2320
 
 
2321
                                // Generate code
 
2322
                                $code = gen_rand_string(mt_rand(5, 8));
 
2323
                                $confirm_id = md5(unique_id($user->ip));
 
2324
                                $seed = hexdec(substr(unique_id(), 4, 10));
 
2325
 
 
2326
                                // compute $seed % 0x7fffffff
 
2327
                                $seed -= 0x7fffffff * floor($seed / 0x7fffffff);
 
2328
 
 
2329
                                $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array(
 
2330
                                        'confirm_id'    => (string) $confirm_id,
 
2331
                                        'session_id'    => (string) $user->session_id,
 
2332
                                        'confirm_type'  => (int) CONFIRM_LOGIN,
 
2333
                                        'code'                  => (string) $code,
 
2334
                                        'seed'                  => (int) $seed)
 
2335
                                );
 
2336
                                $db->sql_query($sql);
 
2337
 
 
2338
                                $template->assign_vars(array(
 
2339
                                        'S_CONFIRM_CODE'                        => true,
 
2340
                                        'CONFIRM_ID'                            => $confirm_id,
 
2341
                                        'CONFIRM_IMAGE'                         => '<img src="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=confirm&amp;id=' . $confirm_id . '&amp;type=' . CONFIRM_LOGIN) . '" alt="" title="" />',
 
2342
                                        'L_LOGIN_CONFIRM_EXPLAIN'       => sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'),
 
2343
                                ));
 
2344
 
 
2345
                                $err = $user->lang[$result['error_msg']];
 
2346
 
 
2347
                        break;
 
2348
 
 
2349
                        case LOGIN_ERROR_PASSWORD_CONVERT:
 
2350
                                $err = sprintf(
 
2351
                                        $user->lang[$result['error_msg']],
 
2352
                                        ($config['email_enable']) ? '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') . '">' : '',
 
2353
                                        ($config['email_enable']) ? '</a>' : '',
 
2354
                                        ($config['board_contact']) ? '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">' : '',
 
2355
                                        ($config['board_contact']) ? '</a>' : ''
 
2356
                                );
 
2357
                        break;
 
2358
 
 
2359
                        // Username, password, etc...
 
2360
                        default:
 
2361
                                $err = $user->lang[$result['error_msg']];
 
2362
 
 
2363
                                // Assign admin contact to some error messages
 
2364
                                if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD')
 
2365
                                {
 
2366
                                        $err = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>');
 
2367
                                }
 
2368
                                
 
2369
                        break;
 
2370
                }
 
2371
        }
 
2372
 
 
2373
        if (!$redirect)
 
2374
        {
 
2375
                // We just use what the session code determined...
 
2376
                // If we are not within the admin directory we use the page dir...
 
2377
                $redirect = '';
 
2378
 
 
2379
                if (!$admin)
 
2380
                {
 
2381
                        $redirect .= ($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '';
 
2382
                }
 
2383
 
 
2384
                $redirect .= $user->page['page_name'] . (($user->page['query_string']) ? '?' . htmlspecialchars($user->page['query_string']) : '');
 
2385
        }
 
2386
 
 
2387
        // Assign credential for username/password pair
 
2388
        $credential = ($admin) ? md5(unique_id()) : false;
 
2389
 
 
2390
        $s_hidden_fields = array(
 
2391
                'redirect'      => $redirect,
 
2392
                'sid'           => $user->session_id,
 
2393
        );
 
2394
 
 
2395
        if ($admin)
 
2396
        {
 
2397
                $s_hidden_fields['credential'] = $credential;
 
2398
        }
 
2399
 
 
2400
        $s_hidden_fields = build_hidden_fields($s_hidden_fields);
 
2401
 
 
2402
        $template->assign_vars(array(
 
2403
                'LOGIN_ERROR'           => $err,
 
2404
                'LOGIN_EXPLAIN'         => $l_explain,
 
2405
 
 
2406
                'U_SEND_PASSWORD'               => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '',
 
2407
                'U_RESEND_ACTIVATION'   => ($config['require_activation'] != USER_ACTIVATION_NONE && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '',
 
2408
                'U_TERMS_USE'                   => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
 
2409
                'U_PRIVACY'                             => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
 
2410
 
 
2411
                'S_DISPLAY_FULL_LOGIN'  => ($s_display) ? true : false,
 
2412
                'S_LOGIN_ACTION'                => (!$admin) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx", false, true, $user->session_id), // Needs to stay index.$phpEx because we are within the admin directory
 
2413
                'S_HIDDEN_FIELDS'               => $s_hidden_fields,
 
2414
 
 
2415
                'S_ADMIN_AUTH'                  => $admin,
 
2416
                'USERNAME'                              => ($admin) ? $user->data['username'] : '',
 
2417
 
 
2418
                'USERNAME_CREDENTIAL'   => 'username',
 
2419
                'PASSWORD_CREDENTIAL'   => ($admin) ? 'password_' . $credential : 'password',
 
2420
        ));
 
2421
 
 
2422
        page_header($user->lang['LOGIN']);
 
2423
 
 
2424
        $template->set_filenames(array(
 
2425
                'body' => 'login_body.html')
 
2426
        );
 
2427
        make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
 
2428
 
 
2429
        page_footer();
 
2430
}
 
2431
 
 
2432
/**
 
2433
* Generate forum login box
 
2434
*/
 
2435
function login_forum_box($forum_data)
 
2436
{
 
2437
        global $db, $config, $user, $template, $phpEx;
 
2438
 
 
2439
        $password = request_var('password', '', true);
 
2440
 
 
2441
        $sql = 'SELECT forum_id
 
2442
                FROM ' . FORUMS_ACCESS_TABLE . '
 
2443
                WHERE forum_id = ' . $forum_data['forum_id'] . '
 
2444
                        AND user_id = ' . $user->data['user_id'] . "
 
2445
                        AND session_id = '" . $db->sql_escape($user->session_id) . "'";
 
2446
        $result = $db->sql_query($sql);
 
2447
        $row = $db->sql_fetchrow($result);
 
2448
        $db->sql_freeresult($result);
 
2449
 
 
2450
        if ($row)
 
2451
        {
 
2452
                return true;
 
2453
        }
 
2454
 
 
2455
        if ($password)
 
2456
        {
 
2457
                // Remove expired authorised sessions
 
2458
                $sql = 'SELECT f.session_id
 
2459
                        FROM ' . FORUMS_ACCESS_TABLE . ' f
 
2460
                        LEFT JOIN ' . SESSIONS_TABLE . ' s ON (f.session_id = s.session_id)
 
2461
                        WHERE s.session_id IS NULL';
 
2462
                $result = $db->sql_query($sql);
 
2463
 
 
2464
                if ($row = $db->sql_fetchrow($result))
 
2465
                {
 
2466
                        $sql_in = array();
 
2467
                        do
 
2468
                        {
 
2469
                                $sql_in[] = (string) $row['session_id'];
 
2470
                        }
 
2471
                        while ($row = $db->sql_fetchrow($result));
 
2472
 
 
2473
                        // Remove expired sessions
 
2474
                        $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE . '
 
2475
                                WHERE ' . $db->sql_in_set('session_id', $sql_in);
 
2476
                        $db->sql_query($sql);
 
2477
                }
 
2478
                $db->sql_freeresult($result);
 
2479
 
 
2480
                if (phpbb_check_hash($password, $forum_data['forum_password']))
 
2481
                {
 
2482
                        $sql_ary = array(
 
2483
                                'forum_id'              => (int) $forum_data['forum_id'],
 
2484
                                'user_id'               => (int) $user->data['user_id'],
 
2485
                                'session_id'    => (string) $user->session_id,
 
2486
                        );
 
2487
 
 
2488
                        $db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 
2489
 
 
2490
                        return true;
 
2491
                }
 
2492
 
 
2493
                $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']);
 
2494
        }
 
2495
 
 
2496
        page_header($user->lang['LOGIN']);
 
2497
 
 
2498
        $template->assign_vars(array(
 
2499
                'S_HIDDEN_FIELDS'               => build_hidden_fields(array('f' => $forum_data['forum_id'])))
 
2500
        );
 
2501
 
 
2502
        $template->set_filenames(array(
 
2503
                'body' => 'login_forum.html')
 
2504
        );
 
2505
        
 
2506
        page_footer();
 
2507
}
 
2508
 
 
2509
// Little helpers
 
2510
 
 
2511
/**
 
2512
* Little helper for the build_hidden_fields function
 
2513
*/
 
2514
function _build_hidden_fields($key, $value, $specialchar, $stripslashes)
 
2515
{
 
2516
        $hidden_fields = '';
 
2517
 
 
2518
        if (!is_array($value))
 
2519
        {
 
2520
                $value = ($stripslashes) ? stripslashes($value) : $value;
 
2521
                $value = ($specialchar) ? htmlspecialchars($value, ENT_COMPAT, 'UTF-8') : $value;
 
2522
 
 
2523
                $hidden_fields .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />' . "\n";
 
2524
        }
 
2525
        else
 
2526
        {
 
2527
                foreach ($value as $_key => $_value)
 
2528
                {
 
2529
                        $_key = ($stripslashes) ? stripslashes($_key) : $_key;
 
2530
                        $_key = ($specialchar) ? htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') : $_key;
 
2531
 
 
2532
                        $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar, $stripslashes);
 
2533
                }
 
2534
        }
 
2535
 
 
2536
        return $hidden_fields;
 
2537
}
 
2538
 
 
2539
/**
 
2540
* Build simple hidden fields from array
 
2541
*
 
2542
* @param array $field_ary an array of values to build the hidden field from
 
2543
* @param bool $specialchar if true, keys and values get specialchared
 
2544
* @param bool $stripslashes if true, keys and values get stripslashed
 
2545
*
 
2546
* @return string the hidden fields
 
2547
*/
 
2548
function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false)
 
2549
{
 
2550
        $s_hidden_fields = '';
 
2551
 
 
2552
        foreach ($field_ary as $name => $vars)
 
2553
        {
 
2554
                $name = ($stripslashes) ? stripslashes($name) : $name;
 
2555
                $name = ($specialchar) ? htmlspecialchars($name, ENT_COMPAT, 'UTF-8') : $name;
 
2556
 
 
2557
                $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar, $stripslashes);
 
2558
        }
 
2559
 
 
2560
        return $s_hidden_fields;
 
2561
}
 
2562
 
 
2563
/**
 
2564
* Parse cfg file
 
2565
*/
 
2566
function parse_cfg_file($filename, $lines = false)
 
2567
{
 
2568
        $parsed_items = array();
 
2569
 
 
2570
        if ($lines === false)
 
2571
        {
 
2572
                $lines = file($filename);
 
2573
        }
 
2574
 
 
2575
        foreach ($lines as $line)
 
2576
        {
 
2577
                $line = trim($line);
 
2578
 
 
2579
                if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false)
 
2580
                {
 
2581
                        continue;
 
2582
                }
 
2583
 
 
2584
                // Determine first occurrence, since in values the equal sign is allowed
 
2585
                $key = strtolower(trim(substr($line, 0, $delim_pos)));
 
2586
                $value = trim(substr($line, $delim_pos + 1));
 
2587
 
 
2588
                if (in_array($value, array('off', 'false', '0')))
 
2589
                {
 
2590
                        $value = false;
 
2591
                }
 
2592
                else if (in_array($value, array('on', 'true', '1')))
 
2593
                {
 
2594
                        $value = true;
 
2595
                }
 
2596
                else if (!trim($value))
 
2597
                {
 
2598
                        $value = '';
 
2599
                }
 
2600
                else if (($value[0] == "'" && $value[sizeof($value) - 1] == "'") || ($value[0] == '"' && $value[sizeof($value) - 1] == '"'))
 
2601
                {
 
2602
                        $value = substr($value, 1, sizeof($value)-2);
 
2603
                }
 
2604
        
 
2605
                $parsed_items[$key] = $value;
 
2606
        }
 
2607
        
 
2608
        return $parsed_items;
 
2609
}
 
2610
 
 
2611
/**
 
2612
* Add log event
 
2613
*/
 
2614
function add_log()
 
2615
{
 
2616
        global $db, $user;
 
2617
 
 
2618
        $args = func_get_args();
 
2619
 
 
2620
        $mode                   = array_shift($args);
 
2621
        $reportee_id    = ($mode == 'user') ? intval(array_shift($args)) : '';
 
2622
        $forum_id               = ($mode == 'mod') ? intval(array_shift($args)) : '';
 
2623
        $topic_id               = ($mode == 'mod') ? intval(array_shift($args)) : '';
 
2624
        $action                 = array_shift($args);
 
2625
        $data                   = (!sizeof($args)) ? '' : serialize($args);
 
2626
 
 
2627
        $sql_ary = array(
 
2628
                'user_id'               => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
 
2629
                'log_ip'                => $user->ip,
 
2630
                'log_time'              => time(),
 
2631
                'log_operation' => $action,
 
2632
                'log_data'              => $data,
 
2633
        );
 
2634
        
 
2635
        switch ($mode)
 
2636
        {
 
2637
                case 'admin':
 
2638
                        $sql_ary['log_type'] = LOG_ADMIN;
 
2639
                break;
 
2640
                
 
2641
                case 'mod':
 
2642
                        $sql_ary += array(
 
2643
                                'log_type'      => LOG_MOD,
 
2644
                                'forum_id'      => $forum_id,
 
2645
                                'topic_id'      => $topic_id
 
2646
                        );
 
2647
                break;
 
2648
 
 
2649
                case 'user':
 
2650
                        $sql_ary += array(
 
2651
                                'log_type'              => LOG_USERS,
 
2652
                                'reportee_id'   => $reportee_id
 
2653
                        );
 
2654
                break;
 
2655
 
 
2656
                case 'critical':
 
2657
                        $sql_ary['log_type'] = LOG_CRITICAL;
 
2658
                break;
 
2659
                
 
2660
                default:
 
2661
                        return false;
 
2662
        }
 
2663
 
 
2664
        $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 
2665
 
 
2666
        return $db->sql_nextid();
 
2667
}
 
2668
 
 
2669
/**
 
2670
* Return a nicely formatted backtrace (parts from the php manual by diz at ysagoon dot com)
 
2671
*/
 
2672
function get_backtrace()
 
2673
{
 
2674
        global $phpbb_root_path;
 
2675
 
 
2676
        $output = '<div style="font-family: monospace;">';
 
2677
        $backtrace = debug_backtrace();
 
2678
        $path = phpbb_realpath($phpbb_root_path);
 
2679
 
 
2680
        foreach ($backtrace as $number => $trace)
 
2681
        {
 
2682
                // We skip the first one, because it only shows this file/function
 
2683
                if ($number == 0)
 
2684
                {
 
2685
                        continue;
 
2686
                }
 
2687
 
 
2688
                // Strip the current directory from path
 
2689
                if (empty($trace['file']))
 
2690
                {
 
2691
                        $trace['file'] = '';
 
2692
                }
 
2693
                else
 
2694
                {
 
2695
                        $trace['file'] = str_replace(array($path, '\\'), array('', '/'), $trace['file']);
 
2696
                        $trace['file'] = substr($trace['file'], 1);
 
2697
                }
 
2698
                $args = array();
 
2699
 
 
2700
                // If include/require/include_once is not called, do not show arguments - they may contain sensible information
 
2701
                if (!in_array($trace['function'], array('include', 'require', 'include_once')))
 
2702
                {
 
2703
                        unset($trace['args']);
 
2704
                }
 
2705
                else
 
2706
                {
 
2707
                        // Path...
 
2708
                        if (!empty($trace['args'][0]))
 
2709
                        {
 
2710
                                $argument = htmlspecialchars($trace['args'][0]);
 
2711
                                $argument = str_replace(array($path, '\\'), array('', '/'), $argument);
 
2712
                                $argument = substr($argument, 1);
 
2713
                                $args[] = "'{$argument}'";
 
2714
                        }
 
2715
                }
 
2716
 
 
2717
                $trace['class'] = (!isset($trace['class'])) ? '' : $trace['class'];
 
2718
                $trace['type'] = (!isset($trace['type'])) ? '' : $trace['type'];
 
2719
 
 
2720
                $output .= '<br />';
 
2721
                $output .= '<b>FILE:</b> ' . htmlspecialchars($trace['file']) . '<br />';
 
2722
                $output .= '<b>LINE:</b> ' . ((!empty($trace['line'])) ? $trace['line'] : '') . '<br />';
 
2723
 
 
2724
                $output .= '<b>CALL:</b> ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']) . '(' . ((sizeof($args)) ? implode(', ', $args) : '') . ')<br />';
 
2725
        }
 
2726
        $output .= '</div>';
 
2727
        return $output;
 
2728
}
 
2729
 
 
2730
/**
 
2731
* This function returns a regular expression pattern for commonly used expressions
 
2732
* Use with / as delimiter for email mode and # for url modes
 
2733
* mode can be: email|bbcode_htm|url|url_inline|www_url|www_url_inline|relative_url|relative_url_inline|ipv4|ipv6
 
2734
*/
 
2735
function get_preg_expression($mode)
 
2736
{
 
2737
        switch ($mode)
 
2738
        {
 
2739
                case 'email':
 
2740
                        return '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+';
 
2741
                break;
 
2742
 
 
2743
                case 'bbcode_htm':
 
2744
                        return array(
 
2745
                                '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
 
2746
                                '#<!\-\- l \-\-><a (?:class="[\w-]+" )?href="(.*?)(?:(&amp;|\?)sid=[0-9a-f]{32})?">.*?</a><!\-\- l \-\->#',
 
2747
                                '#<!\-\- ([mw]) \-\-><a (?:class="[\w-]+" )?href="(.*?)">.*?</a><!\-\- \1 \-\->#',
 
2748
                                '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
 
2749
                                '#<!\-\- .*? \-\->#s',
 
2750
                                '#<.*?>#s',
 
2751
                        );
 
2752
                break;
 
2753
 
 
2754
                // Whoa these look impressive!
 
2755
                // The code to generate the following two regular expressions which match valid IPv4/IPv6 addresses
 
2756
                // can be found in the develop directory
 
2757
                case 'ipv4':
 
2758
                        return '#^(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$#';
 
2759
                break;
 
2760
 
 
2761
                case 'ipv6':
 
2762
                        return '#^(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){5}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:))$#i';
 
2763
                break;
 
2764
 
 
2765
                case 'url':
 
2766
                case 'url_inline':
 
2767
                        $inline = ($mode == 'url') ? ')' : '';
 
2768
                        $scheme = ($mode == 'url') ? '[a-z\d+\-.]' : '[a-z\d+]'; // avoid automatic parsing of "word" in "last word.http://..."
 
2769
                        // generated with regex generation file in the develop folder
 
2770
                        return "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
 
2771
                break;
 
2772
 
 
2773
                case 'www_url':
 
2774
                case 'www_url_inline':
 
2775
                        $inline = ($mode == 'www_url') ? ')' : '';
 
2776
                        return "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
 
2777
                break;
 
2778
 
 
2779
                case 'relative_url':
 
2780
                case 'relative_url_inline':
 
2781
                        $inline = ($mode == 'relative_url') ? ')' : '';
 
2782
                        return "(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
 
2783
                break;
 
2784
        }
 
2785
 
 
2786
        return '';
 
2787
}
 
2788
 
 
2789
/**
 
2790
* Returns the first block of the specified IPv6 address and as many additional
 
2791
* ones as specified in the length paramater.
 
2792
* If length is zero, then an empty string is returned.
 
2793
* If length is greater than 3 the complete IP will be returned
 
2794
*/
 
2795
function short_ipv6($ip, $length)
 
2796
{
 
2797
        if ($length < 1)
 
2798
        {
 
2799
                return '';
 
2800
        }
 
2801
 
 
2802
        // extend IPv6 addresses
 
2803
        $blocks = substr_count($ip, ':') + 1;
 
2804
        if ($blocks < 9)
 
2805
        {
 
2806
                $ip = str_replace('::', ':' . str_repeat('0000:', 9 - $blocks), $ip);
 
2807
        }
 
2808
        if ($ip[0] == ':')
 
2809
        {
 
2810
                $ip = '0000' . $ip;
 
2811
        }
 
2812
        if ($length < 4)
 
2813
        {
 
2814
                $ip = implode(':', array_slice(explode(':', $ip), 0, 1 + $length));
 
2815
        }
 
2816
 
 
2817
        return $ip;
 
2818
}
 
2819
 
 
2820
/**
 
2821
* Wrapper for php's checkdnsrr function.
 
2822
*
 
2823
* The windows failover is from the php manual
 
2824
* Please make sure to check the return value for === true and === false, since NULL could
 
2825
* be returned too.
 
2826
*
 
2827
* @return true if entry found, false if not, NULL if this function is not supported by this environment
 
2828
*/
 
2829
function phpbb_checkdnsrr($host, $type = '')
 
2830
{
 
2831
        $type = (!$type) ? 'MX' : $type;
 
2832
 
 
2833
        if (DIRECTORY_SEPARATOR == '\\')
 
2834
        {
 
2835
                if (!function_exists('exec'))
 
2836
                {
 
2837
                        return NULL;
 
2838
                }
 
2839
 
 
2840
                // @exec('nslookup -retry=1 -timout=1 -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output);
 
2841
                @exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output);
 
2842
 
 
2843
                // If output is empty, the nslookup failed
 
2844
                if (empty($output))
 
2845
                {
 
2846
                        return NULL;
 
2847
                }
 
2848
 
 
2849
                foreach ($output as $line)
 
2850
                {
 
2851
                        if (!trim($line))
 
2852
                        {
 
2853
                                continue;
 
2854
                        }
 
2855
 
 
2856
                        // Valid records begin with host name:
 
2857
                        if (strpos($line, $host) === 0)
 
2858
                        {
 
2859
                                return true;
 
2860
                        }
 
2861
                }
 
2862
 
 
2863
                return false;
 
2864
        }
 
2865
        else if (function_exists('checkdnsrr'))
 
2866
        {
 
2867
                return (checkdnsrr($host, $type)) ? true : false;
 
2868
        }
 
2869
 
 
2870
        return NULL;
 
2871
}
 
2872
 
 
2873
// Handler, header and footer
 
2874
 
 
2875
/**
 
2876
* Error and message handler, call with trigger_error if reqd
 
2877
*/
 
2878
function msg_handler($errno, $msg_text, $errfile, $errline)
 
2879
{
 
2880
        global $cache, $db, $auth, $template, $config, $user;
 
2881
        global $phpEx, $phpbb_root_path, $msg_title, $msg_long_text;
 
2882
 
 
2883
        // Do not display notices if we suppress them via @
 
2884
        if (error_reporting() == 0)
 
2885
        {
 
2886
                return;
 
2887
        }
 
2888
 
 
2889
        // Message handler is stripping text. In case we need it, we are possible to define long text...
 
2890
        if (isset($msg_long_text) && $msg_long_text && !$msg_text)
 
2891
        {
 
2892
                $msg_text = $msg_long_text;
 
2893
        }
 
2894
 
 
2895
        switch ($errno)
 
2896
        {
 
2897
                case E_NOTICE:
 
2898
                case E_WARNING:
 
2899
 
 
2900
                        // Check the error reporting level and return if the error level does not match
 
2901
                        // If DEBUG is defined the default level is E_ALL
 
2902
                        if (($errno & ((defined('DEBUG')) ? E_ALL : error_reporting())) == 0)
 
2903
                        {
 
2904
                                return;
 
2905
                        }
 
2906
 
 
2907
                        if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
 
2908
                        {
 
2909
                                // flush the content, else we get a white page if output buffering is on
 
2910
                                if ($config['gzip_compress'])
 
2911
                                {
 
2912
                                        if (@extension_loaded('zlib') && !headers_sent())
 
2913
                                        {
 
2914
                                                ob_flush();
 
2915
                                        }
 
2916
                                }
 
2917
 
 
2918
                                // remove complete path to installation, with the risk of changing backslashes meant to be there
 
2919
                                $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);
 
2920
                                $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text);
 
2921
 
 
2922
                                echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
 
2923
                        }
 
2924
 
 
2925
                        return;
 
2926
 
 
2927
                break;
 
2928
 
 
2929
                case E_USER_ERROR:
 
2930
 
 
2931
                        if (!empty($user) && !empty($user->lang))
 
2932
                        {
 
2933
                                $msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text;
 
2934
                                $msg_title = (!isset($msg_title)) ? $user->lang['GENERAL_ERROR'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title);
 
2935
 
 
2936
                                $l_return_index = sprintf($user->lang['RETURN_INDEX'], '<a href="' . $phpbb_root_path . '">', '</a>');
 
2937
                                $l_notify = '';
 
2938
 
 
2939
                                if (!empty($config['board_contact']))
 
2940
                                {
 
2941
                                        $l_notify = '<p>' . sprintf($user->lang['NOTIFY_ADMIN_EMAIL'], $config['board_contact']) . '</p>';
 
2942
                                }
 
2943
                        }
 
2944
                        else
 
2945
                        {
 
2946
                                $msg_title = 'General Error';
 
2947
                                $l_return_index = '<a href="' . $phpbb_root_path . '">Return to index page</a>';
 
2948
                                $l_notify = '';
 
2949
 
 
2950
                                if (!empty($config['board_contact']))
 
2951
                                {
 
2952
                                        $l_notify = '<p>Please notify the board administrator or webmaster: <a href="mailto:' . $config['board_contact'] . '">' . $config['board_contact'] . '</a></p>';
 
2953
                                }
 
2954
                        }
 
2955
 
 
2956
                        garbage_collection();
 
2957
 
 
2958
                        // Try to not call the adm page data...
 
2959
 
 
2960
                        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
 
2961
                        echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
 
2962
                        echo '<head>';
 
2963
                        echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
 
2964
                        echo '<title>' . $msg_title . '</title>';
 
2965
                        echo '<style type="text/css">' . "\n" . '<!--' . "\n";
 
2966
                        echo '* { margin: 0; padding: 0; } html { font-size: 100%; height: 100%; margin-bottom: 1px; background-color: #E4EDF0; } body { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; color: #536482; background: #E4EDF0; font-size: 62.5%; margin: 0; } ';
 
2967
                        echo 'a:link, a:active, a:visited { color: #006699; text-decoration: none; } a:hover { color: #DD6900; text-decoration: underline; } ';
 
2968
                        echo '#wrap { padding: 0 20px 15px 20px; min-width: 615px; } #page-header { text-align: right; height: 40px; } #page-footer { clear: both; font-size: 1em; text-align: center; } ';
 
2969
                        echo '.panel { margin: 4px 0; background-color: #FFFFFF; border: solid 1px  #A9B8C2; } ';
 
2970
                        echo '#errorpage #page-header a { font-weight: bold; line-height: 6em; } #errorpage #content { padding: 10px; } #errorpage #content h1 { line-height: 1.2em; margin-bottom: 0; color: #DF075C; } ';
 
2971
                        echo '#errorpage #content div { margin-top: 20px; margin-bottom: 5px; border-bottom: 1px solid #CCCCCC; padding-bottom: 5px; color: #333333; font: bold 1.2em "Lucida Grande", Arial, Helvetica, sans-serif; text-decoration: none; line-height: 120%; text-align: left; } ';
 
2972
                        echo "\n" . '//-->' . "\n";
 
2973
                        echo '</style>';
 
2974
                        echo '</head>';
 
2975
                        echo '<body id="errorpage">';
 
2976
                        echo '<div id="wrap">';
 
2977
                        echo '  <div id="page-header">';
 
2978
                        echo '          ' . $l_return_index;
 
2979
                        echo '  </div>';
 
2980
                        echo '  <div id="acp">';
 
2981
                        echo '  <div class="panel">';
 
2982
                        echo '          <div id="content">';
 
2983
                        echo '                  <h1>' . $msg_title . '</h1>';
 
2984
                        
 
2985
                        echo '                  <div>' . $msg_text . '</div>';
 
2986
                        
 
2987
                        echo $l_notify;
 
2988
 
 
2989
                        echo '          </div>';
 
2990
                        echo '  </div>';
 
2991
                        echo '  </div>';
 
2992
                        echo '  <div id="page-footer">';
 
2993
                        echo '          Powered by phpBB &copy; 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>';
 
2994
                        echo '  </div>';
 
2995
                        echo '</div>';
 
2996
                        echo '</body>';
 
2997
                        echo '</html>';
 
2998
                        
 
2999
                        exit_handler();
 
3000
                break;
 
3001
 
 
3002
                case E_USER_WARNING:
 
3003
                case E_USER_NOTICE:
 
3004
 
 
3005
                        define('IN_ERROR_HANDLER', true);
 
3006
 
 
3007
                        if (empty($user->data))
 
3008
                        {
 
3009
                                $user->session_begin();
 
3010
                        }
 
3011
 
 
3012
                        // We re-init the auth array to get correct results on login/logout
 
3013
                        $auth->acl($user->data);
 
3014
 
 
3015
                        if (empty($user->lang))
 
3016
                        {
 
3017
                                $user->setup();
 
3018
                        }
 
3019
 
 
3020
                        $msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text;
 
3021
                        $msg_title = (!isset($msg_title)) ? $user->lang['INFORMATION'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title);
 
3022
 
 
3023
                        if (!defined('HEADER_INC'))
 
3024
                        {
 
3025
                                if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 
3026
                                {
 
3027
                                        adm_page_header($msg_title);
 
3028
                                }
 
3029
                                else
 
3030
                                {
 
3031
                                        page_header($msg_title);
 
3032
                                }
 
3033
                        }
 
3034
 
 
3035
                        $template->set_filenames(array(
 
3036
                                'body' => 'message_body.html')
 
3037
                        );
 
3038
 
 
3039
                        $template->assign_vars(array(
 
3040
                                'MESSAGE_TITLE'         => $msg_title,
 
3041
                                'MESSAGE_TEXT'          => $msg_text,
 
3042
                                'S_USER_WARNING'        => ($errno == E_USER_WARNING) ? true : false,
 
3043
                                'S_USER_NOTICE'         => ($errno == E_USER_NOTICE) ? true : false)
 
3044
                        );
 
3045
 
 
3046
                        // We do not want the cron script to be called on error messages
 
3047
                        define('IN_CRON', true);
 
3048
                        
 
3049
                        if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 
3050
                        {
 
3051
                                adm_page_footer();
 
3052
                        }
 
3053
                        else
 
3054
                        {
 
3055
                                page_footer();
 
3056
                        }
 
3057
 
 
3058
                        exit_handler();
 
3059
                break;
 
3060
        }
 
3061
 
 
3062
        // If we notice an error not handled here we pass this back to PHP by returning false
 
3063
        // This may not work for all php versions
 
3064
        return false;
 
3065
}
 
3066
 
 
3067
/**
 
3068
* Generate page header
 
3069
*/
 
3070
function page_header($page_title = '', $display_online_list = true)
 
3071
{
 
3072
        global $db, $config, $template, $SID, $_SID, $user, $auth, $phpEx, $phpbb_root_path;
 
3073
 
 
3074
        if (defined('HEADER_INC'))
 
3075
        {
 
3076
                return;
 
3077
        }
 
3078
        
 
3079
        define('HEADER_INC', true);
 
3080
 
 
3081
        // gzip_compression
 
3082
        if ($config['gzip_compress'])
 
3083
        {
 
3084
                if (@extension_loaded('zlib') && !headers_sent())
 
3085
                {
 
3086
                        ob_start('ob_gzhandler');
 
3087
                }
 
3088
        }
 
3089
 
 
3090
        // Generate logged in/logged out status
 
3091
        if ($user->data['user_id'] != ANONYMOUS)
 
3092
        {
 
3093
                $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout', true, $user->session_id);
 
3094
                $l_login_logout = sprintf($user->lang['LOGOUT_USER'], $user->data['username']);
 
3095
        }
 
3096
        else
 
3097
        {
 
3098
                $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login');
 
3099
                $l_login_logout = $user->lang['LOGIN'];
 
3100
        }
 
3101
 
 
3102
        // Last visit date/time
 
3103
        $s_last_visit = ($user->data['user_id'] != ANONYMOUS) ? $user->format_date($user->data['session_last_visit']) : '';
 
3104
 
 
3105
        // Get users online list ... if required
 
3106
        $l_online_users = $online_userlist = $l_online_record = '';
 
3107
 
 
3108
        if ($config['load_online'] && $config['load_online_time'] && $display_online_list)
 
3109
        {
 
3110
                $logged_visible_online = $logged_hidden_online = $guests_online = $prev_user_id = 0;
 
3111
                $prev_session_ip = $reading_sql = '';
 
3112
 
 
3113
                if (!empty($_REQUEST['f']))
 
3114
                {
 
3115
                        $f = request_var('f', 0);
 
3116
 
 
3117
                        $reading_sql = ' AND s.session_page ' . $db->sql_like_expression("{$db->any_char}_f_={$f}x{$db->any_char}");
 
3118
                }
 
3119
 
 
3120
                // Get number of online guests
 
3121
                if (!$config['load_online_guests'])
 
3122
                {
 
3123
                        if ($db->sql_layer === 'sqlite')
 
3124
                        {
 
3125
                                $sql = 'SELECT COUNT(session_ip) as num_guests
 
3126
                                        FROM (
 
3127
                                                SELECT DISTINCT s.session_ip
 
3128
                                                        FROM ' . SESSIONS_TABLE . ' s
 
3129
                                                        WHERE s.session_user_id = ' . ANONYMOUS . '
 
3130
                                                                AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) .
 
3131
                                                                $reading_sql .
 
3132
                                        ')';
 
3133
                        }
 
3134
                        else
 
3135
                        {
 
3136
                                $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests
 
3137
                                        FROM ' . SESSIONS_TABLE . ' s
 
3138
                                        WHERE s.session_user_id = ' . ANONYMOUS . '
 
3139
                                                AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) .
 
3140
                                        $reading_sql;
 
3141
                        }
 
3142
                        $result = $db->sql_query($sql);
 
3143
                        $guests_online = (int) $db->sql_fetchfield('num_guests');
 
3144
                        $db->sql_freeresult($result);
 
3145
                }
 
3146
 
 
3147
                $sql = 'SELECT u.username, u.username_clean, u.user_id, u.user_type, u.user_allow_viewonline, u.user_colour, s.session_ip, s.session_viewonline
 
3148
                        FROM ' . USERS_TABLE . ' u, ' . SESSIONS_TABLE . ' s
 
3149
                        WHERE s.session_time >= ' . (time() - (intval($config['load_online_time']) * 60)) .
 
3150
                                $reading_sql .
 
3151
                                ((!$config['load_online_guests']) ? ' AND s.session_user_id <> ' . ANONYMOUS : '') . '
 
3152
                                AND u.user_id = s.session_user_id
 
3153
                        ORDER BY u.username_clean ASC, s.session_ip ASC';
 
3154
                $result = $db->sql_query($sql);
 
3155
 
 
3156
                while ($row = $db->sql_fetchrow($result))
 
3157
                {
 
3158
                        // User is logged in and therefore not a guest
 
3159
                        if ($row['user_id'] != ANONYMOUS)
 
3160
                        {
 
3161
                                // Skip multiple sessions for one user
 
3162
                                if ($row['user_id'] != $prev_user_id)
 
3163
                                {
 
3164
                                        if ($row['session_viewonline'])
 
3165
                                        {
 
3166
                                                $logged_visible_online++;
 
3167
                                        }
 
3168
                                        else
 
3169
                                        {
 
3170
                                                $row['username'] = '<em>' . $row['username'] . '</em>';
 
3171
                                                $logged_hidden_online++;
 
3172
                                        }
 
3173
 
 
3174
                                        if (($row['session_viewonline']) || $auth->acl_get('u_viewonline'))
 
3175
                                        {
 
3176
                                                $user_online_link = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']);
 
3177
                                                $online_userlist .= ($online_userlist != '') ? ', ' . $user_online_link : $user_online_link;
 
3178
                                        }
 
3179
                                }
 
3180
 
 
3181
                                $prev_user_id = $row['user_id'];
 
3182
                        }
 
3183
                        else
 
3184
                        {
 
3185
                                // Skip multiple sessions for one user
 
3186
                                if ($row['session_ip'] != $prev_session_ip)
 
3187
                                {
 
3188
                                        $guests_online++;
 
3189
                                }
 
3190
                        }
 
3191
 
 
3192
                        $prev_session_ip = $row['session_ip'];
 
3193
                }
 
3194
                $db->sql_freeresult($result);
 
3195
 
 
3196
                if (!$online_userlist)
 
3197
                {
 
3198
                        $online_userlist = $user->lang['NO_ONLINE_USERS'];
 
3199
                }
 
3200
 
 
3201
                if (empty($_REQUEST['f']))
 
3202
                {
 
3203
                        $online_userlist = $user->lang['REGISTERED_USERS'] . ' ' . $online_userlist;
 
3204
                }
 
3205
                else
 
3206
                {
 
3207
                        $l_online = ($guests_online == 1) ? $user->lang['BROWSING_FORUM_GUEST'] : $user->lang['BROWSING_FORUM_GUESTS'];
 
3208
                        $online_userlist = sprintf($l_online, $online_userlist, $guests_online);
 
3209
                }
 
3210
 
 
3211
                $total_online_users = $logged_visible_online + $logged_hidden_online + $guests_online;
 
3212
 
 
3213
                if ($total_online_users > $config['record_online_users'])
 
3214
                {
 
3215
                        set_config('record_online_users', $total_online_users, true);
 
3216
                        set_config('record_online_date', time(), true);
 
3217
                }
 
3218
 
 
3219
                // Build online listing
 
3220
                $vars_online = array(
 
3221
                        'ONLINE'        => array('total_online_users', 'l_t_user_s'),
 
3222
                        'REG'           => array('logged_visible_online', 'l_r_user_s'),
 
3223
                        'HIDDEN'        => array('logged_hidden_online', 'l_h_user_s'),
 
3224
                        'GUEST'         => array('guests_online', 'l_g_user_s')
 
3225
                );
 
3226
 
 
3227
                foreach ($vars_online as $l_prefix => $var_ary)
 
3228
                {
 
3229
                        switch (${$var_ary[0]})
 
3230
                        {
 
3231
                                case 0:
 
3232
                                        ${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_ZERO_TOTAL'];
 
3233
                                break;
 
3234
 
 
3235
                                case 1:
 
3236
                                        ${$var_ary[1]} = $user->lang[$l_prefix . '_USER_TOTAL'];
 
3237
                                break;
 
3238
 
 
3239
                                default:
 
3240
                                        ${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_TOTAL'];
 
3241
                                break;
 
3242
                        }
 
3243
                }
 
3244
                unset($vars_online);
 
3245
 
 
3246
                $l_online_users = sprintf($l_t_user_s, $total_online_users);
 
3247
                $l_online_users .= sprintf($l_r_user_s, $logged_visible_online);
 
3248
                $l_online_users .= sprintf($l_h_user_s, $logged_hidden_online);
 
3249
                $l_online_users .= sprintf($l_g_user_s, $guests_online);
 
3250
 
 
3251
                $l_online_record = sprintf($user->lang['RECORD_ONLINE_USERS'], $config['record_online_users'], $user->format_date($config['record_online_date']));
 
3252
 
 
3253
                $l_online_time = ($config['load_online_time'] == 1) ? 'VIEW_ONLINE_TIME' : 'VIEW_ONLINE_TIMES';
 
3254
                $l_online_time = sprintf($user->lang[$l_online_time], $config['load_online_time']);
 
3255
        }
 
3256
        else
 
3257
        {
 
3258
                $l_online_time = '';
 
3259
        }
 
3260
 
 
3261
        $l_privmsgs_text = $l_privmsgs_text_unread = '';
 
3262
        $s_privmsg_new = false;
 
3263
 
 
3264
        // Obtain number of new private messages if user is logged in
 
3265
        if (isset($user->data['is_registered']) && $user->data['is_registered'])
 
3266
        {
 
3267
                if ($user->data['user_new_privmsg'])
 
3268
                {
 
3269
                        $l_message_new = ($user->data['user_new_privmsg'] == 1) ? $user->lang['NEW_PM'] : $user->lang['NEW_PMS'];
 
3270
                        $l_privmsgs_text = sprintf($l_message_new, $user->data['user_new_privmsg']);
 
3271
 
 
3272
                        if (!$user->data['user_last_privmsg'] || $user->data['user_last_privmsg'] > $user->data['session_last_visit'])
 
3273
                        {
 
3274
                                $sql = 'UPDATE ' . USERS_TABLE . '
 
3275
                                        SET user_last_privmsg = ' . $user->data['session_last_visit'] . '
 
3276
                                        WHERE user_id = ' . $user->data['user_id'];
 
3277
                                $db->sql_query($sql);
 
3278
 
 
3279
                                $s_privmsg_new = true;
 
3280
                        }
 
3281
                        else
 
3282
                        {
 
3283
                                $s_privmsg_new = false;
 
3284
                        }
 
3285
                }
 
3286
                else
 
3287
                {
 
3288
                        $l_privmsgs_text = $user->lang['NO_NEW_PM'];
 
3289
                        $s_privmsg_new = false;
 
3290
                }
 
3291
 
 
3292
                $l_privmsgs_text_unread = '';
 
3293
 
 
3294
                if ($user->data['user_unread_privmsg'] && $user->data['user_unread_privmsg'] != $user->data['user_new_privmsg'])
 
3295
                {
 
3296
                        $l_message_unread = ($user->data['user_unread_privmsg'] == 1) ? $user->lang['UNREAD_PM'] : $user->lang['UNREAD_PMS'];
 
3297
                        $l_privmsgs_text_unread = sprintf($l_message_unread, $user->data['user_unread_privmsg']);
 
3298
                }
 
3299
        }
 
3300
 
 
3301
        // Which timezone?
 
3302
        $tz = ($user->data['user_id'] != ANONYMOUS) ? strval(doubleval($user->data['user_timezone'])) : strval(doubleval($config['board_timezone']));
 
3303
        
 
3304
        // The following assigns all _common_ variables that may be used at any point in a template.
 
3305
        $template->assign_vars(array(
 
3306
                'SITENAME'                                              => $config['sitename'],
 
3307
                'SITE_DESCRIPTION'                              => $config['site_desc'],
 
3308
                'PAGE_TITLE'                                    => $page_title,
 
3309
                'SCRIPT_NAME'                                   => str_replace('.' . $phpEx, '', $user->page['page_name']),
 
3310
                'LAST_VISIT_DATE'                               => sprintf($user->lang['YOU_LAST_VISIT'], $s_last_visit),
 
3311
                'LAST_VISIT_YOU'                                => $s_last_visit,
 
3312
                'CURRENT_TIME'                                  => sprintf($user->lang['CURRENT_TIME'], $user->format_date(time(), false, true)),
 
3313
                'TOTAL_USERS_ONLINE'                    => $l_online_users,
 
3314
                'LOGGED_IN_USER_LIST'                   => $online_userlist,
 
3315
                'RECORD_USERS'                                  => $l_online_record,
 
3316
                'PRIVATE_MESSAGE_INFO'                  => $l_privmsgs_text,
 
3317
                'PRIVATE_MESSAGE_INFO_UNREAD'   => $l_privmsgs_text_unread,
 
3318
 
 
3319
                'S_USER_NEW_PRIVMSG'                    => $user->data['user_new_privmsg'],
 
3320
                'S_USER_UNREAD_PRIVMSG'                 => $user->data['user_unread_privmsg'],
 
3321
 
 
3322
                'SID'                           => $SID,
 
3323
                '_SID'                          => $_SID,
 
3324
                'SESSION_ID'            => $user->session_id,
 
3325
                'ROOT_PATH'                     => $phpbb_root_path,
 
3326
 
 
3327
                'L_LOGIN_LOGOUT'        => $l_login_logout,
 
3328
                'L_INDEX'                       => $user->lang['FORUM_INDEX'],
 
3329
                'L_ONLINE_EXPLAIN'      => $l_online_time,
 
3330
 
 
3331
                'U_PRIVATEMSGS'                 => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox'),
 
3332
                'U_RETURN_INBOX'                => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox'),
 
3333
                'U_POPUP_PM'                    => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=popup'),
 
3334
                'UA_POPUP_PM'                   => addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=popup')),
 
3335
                'U_MEMBERLIST'                  => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
 
3336
                'U_MEMBERSLIST'                 => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
 
3337
                'U_VIEWONLINE'                  => ($auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? append_sid("{$phpbb_root_path}viewonline.$phpEx") : '',
 
3338
                'U_LOGIN_LOGOUT'                => $u_login_logout,
 
3339
                'U_INDEX'                               => append_sid("{$phpbb_root_path}index.$phpEx"),
 
3340
                'U_SEARCH'                              => append_sid("{$phpbb_root_path}search.$phpEx"),
 
3341
                'U_REGISTER'                    => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
 
3342
                'U_PROFILE'                             => append_sid("{$phpbb_root_path}ucp.$phpEx"),
 
3343
                'U_MODCP'                               => append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id),
 
3344
                'U_FAQ'                                 => append_sid("{$phpbb_root_path}faq.$phpEx"),
 
3345
                'U_SEARCH_SELF'                 => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'),
 
3346
                'U_SEARCH_NEW'                  => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'),
 
3347
                'U_SEARCH_UNANSWERED'   => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
 
3348
                'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
 
3349
                'U_DELETE_COOKIES'              => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
 
3350
                'U_TEAM'                                => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'),
 
3351
                'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
 
3352
 
 
3353
                'S_USER_LOGGED_IN'              => ($user->data['user_id'] != ANONYMOUS) ? true : false,
 
3354
                'S_AUTOLOGIN_ENABLED'   => ($config['allow_autologin']) ? true : false,
 
3355
                'S_BOARD_DISABLED'              => ($config['board_disable']) ? true : false,
 
3356
                'S_REGISTERED_USER'             => $user->data['is_registered'],
 
3357
                'S_IS_BOT'                              => $user->data['is_bot'],
 
3358
                'S_USER_PM_POPUP'               => $user->optionget('popuppm'),
 
3359
                'S_USER_LANG'                   => $user->lang['USER_LANG'],
 
3360
                'S_USER_BROWSER'                => (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'],
 
3361
                'S_USERNAME'                    => $user->data['username'],
 
3362
                'S_CONTENT_DIRECTION'   => $user->lang['DIRECTION'],
 
3363
                'S_CONTENT_FLOW_BEGIN'  => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
 
3364
                'S_CONTENT_FLOW_END'    => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
 
3365
                'S_CONTENT_ENCODING'    => 'UTF-8',
 
3366
                'S_TIMEZONE'                    => ($user->data['user_dst'] || ($user->data['user_id'] == ANONYMOUS && $config['board_dst'])) ? sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], $user->lang['tz']['dst']) : sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], ''),
 
3367
                'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ? 1 : 0,
 
3368
                'S_DISPLAY_SEARCH'              => (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1),
 
3369
                'S_DISPLAY_PM'                  => ($config['allow_privmsg'] && $user->data['is_registered'] && ($auth->acl_get('u_readpm') || $auth->acl_get('u_sendpm'))) ? true : false,
 
3370
                'S_DISPLAY_MEMBERLIST'  => (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0,
 
3371
                'S_NEW_PM'                              => ($s_privmsg_new) ? 1 : 0,
 
3372
 
 
3373
                'T_THEME_PATH'                  => "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme',
 
3374
                'T_TEMPLATE_PATH'               => "{$phpbb_root_path}styles/" . $user->theme['template_path'] . '/template',
 
3375
                'T_IMAGESET_PATH'               => "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset',
 
3376
                'T_IMAGESET_LANG_PATH'  => "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'],
 
3377
                'T_IMAGES_PATH'                 => "{$phpbb_root_path}images/",
 
3378
                'T_SMILIES_PATH'                => "{$phpbb_root_path}{$config['smilies_path']}/",
 
3379
                'T_AVATAR_PATH'                 => "{$phpbb_root_path}{$config['avatar_path']}/",
 
3380
                'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
 
3381
                'T_ICONS_PATH'                  => "{$phpbb_root_path}{$config['icons_path']}/",
 
3382
                'T_RANKS_PATH'                  => "{$phpbb_root_path}{$config['ranks_path']}/",
 
3383
                'T_UPLOAD_PATH'                 => "{$phpbb_root_path}{$config['upload_path']}/",
 
3384
                'T_STYLESHEET_LINK'             => (!$user->theme['theme_storedb']) ? "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&amp;id=" . $user->theme['style_id'] . '&amp;lang=' . $user->data['user_lang'],
 
3385
                'T_STYLESHEET_NAME'             => $user->theme['theme_name'],
 
3386
 
 
3387
                'SITE_LOGO_IMG'                 => $user->img('site_logo'))
 
3388
        );
 
3389
 
 
3390
        // application/xhtml+xml not used because of IE
 
3391
        header('Content-type: text/html; charset=UTF-8');
 
3392
 
 
3393
        header('Cache-Control: private, no-cache="set-cookie"');
 
3394
        header('Expires: 0');
 
3395
        header('Pragma: no-cache');
 
3396
 
 
3397
        return;
 
3398
}
 
3399
 
 
3400
/**
 
3401
* Generate page footer
 
3402
*/
 
3403
function page_footer($run_cron = true)
 
3404
{
 
3405
        global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx;
 
3406
 
 
3407
        // Output page creation time
 
3408
        if (defined('DEBUG'))
 
3409
        {
 
3410
                $mtime = explode(' ', microtime());
 
3411
                $totaltime = $mtime[0] + $mtime[1] - $starttime;
 
3412
 
 
3413
                if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report'))
 
3414
                {
 
3415
                        $db->sql_report('display');
 
3416
                }
 
3417
 
 
3418
                $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress']) ? 'On' : 'Off') . (($user->load) ? ' | Load : ' . $user->load : ''), $totaltime);
 
3419
 
 
3420
                if ($auth->acl_get('a_') && defined('DEBUG_EXTRA'))
 
3421
                {
 
3422
                        if (function_exists('memory_get_usage'))
 
3423
                        {
 
3424
                                if ($memory_usage = memory_get_usage())
 
3425
                                {
 
3426
                                        global $base_memory_usage;
 
3427
                                        $memory_usage -= $base_memory_usage;
 
3428
                                        $memory_usage = ($memory_usage >= 1048576) ? round((round($memory_usage / 1048576 * 100) / 100), 2) . ' ' . $user->lang['MB'] : (($memory_usage >= 1024) ? round((round($memory_usage / 1024 * 100) / 100), 2) . ' ' . $user->lang['KB'] : $memory_usage . ' ' . $user->lang['BYTES']);
 
3429
 
 
3430
                                        $debug_output .= ' | Memory Usage: ' . $memory_usage;
 
3431
                                }
 
3432
                        }
 
3433
 
 
3434
                        $debug_output .= ' | <a href="' . build_url() . '&amp;explain=1">Explain</a>';
 
3435
                }
 
3436
        }
 
3437
 
 
3438
        $template->assign_vars(array(
 
3439
                'DEBUG_OUTPUT'                  => (defined('DEBUG')) ? $debug_output : '',
 
3440
                'TRANSLATION_INFO'              => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '',
 
3441
 
 
3442
                'U_ACP' => ($auth->acl_get('a_') && $user->data['is_registered']) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '')
 
3443
        );
 
3444
 
 
3445
        // Call cron-type script
 
3446
        if (!defined('IN_CRON') && $run_cron && !$config['board_disable'])
 
3447
        {
 
3448
                $cron_type = '';
 
3449
        
 
3450
                if (time() - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx))
 
3451
                {
 
3452
                        // Process email queue
 
3453
                        $cron_type = 'queue';
 
3454
                }
 
3455
                else if (method_exists($cache, 'tidy') && time() - $config['cache_gc'] > $config['cache_last_gc'])
 
3456
                {
 
3457
                        // Tidy the cache
 
3458
                        $cron_type = 'tidy_cache';
 
3459
                }
 
3460
                else if (time() - $config['warnings_gc'] > $config['warnings_last_gc'])
 
3461
                {
 
3462
                        $cron_type = 'tidy_warnings';
 
3463
                }
 
3464
                else if (time() - $config['database_gc'] > $config['database_last_gc'])
 
3465
                {
 
3466
                        // Tidy the database
 
3467
                        $cron_type = 'tidy_database';
 
3468
                }
 
3469
                else if (time() - $config['search_gc'] > $config['search_last_gc'])
 
3470
                {
 
3471
                        // Tidy the search
 
3472
                        $cron_type = 'tidy_search';
 
3473
                }
 
3474
                else if (time() - $config['session_gc'] > $config['session_last_gc'])
 
3475
                {
 
3476
                        $cron_type = 'tidy_sessions';
 
3477
                }
 
3478
 
 
3479
                if ($cron_type)
 
3480
                {
 
3481
                        $template->assign_var('RUN_CRON_TASK', '<img src="' . append_sid($phpbb_root_path . 'cron.' . $phpEx, 'cron_type=' . $cron_type) . '" width="1" height="1" alt="cron" />');
 
3482
                }
 
3483
        }
 
3484
 
 
3485
        $template->display('body');
 
3486
 
 
3487
        garbage_collection();
 
3488
        exit_handler();
 
3489
}
 
3490
 
 
3491
/**
 
3492
* Closing the cache object and the database
 
3493
* Cool function name, eh? We might want to add operations to it later
 
3494
*/
 
3495
function garbage_collection()
 
3496
{
 
3497
        global $cache, $db;
 
3498
 
 
3499
        // Unload cache, must be done before the DB connection if closed
 
3500
        if (!empty($cache))
 
3501
        {
 
3502
                $cache->unload();
 
3503
        }
 
3504
 
 
3505
        // Close our DB connection.
 
3506
        if (!empty($db))
 
3507
        {
 
3508
                $db->sql_close();
 
3509
        }
 
3510
}
 
3511
 
 
3512
/**
 
3513
* Handler for exit calls in phpBB.
 
3514
* This function supports hooks.
 
3515
*
 
3516
* Note: This function is called after the template has been outputted.
 
3517
*/
 
3518
function exit_handler()
 
3519
{
 
3520
        global $phpbb_hook;
 
3521
 
 
3522
        if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__))
 
3523
        {
 
3524
                if ($phpbb_hook->hook_return(__FUNCTION__))
 
3525
                {
 
3526
                        return $phpbb_hook->hook_return_result(__FUNCTION__);
 
3527
                }
 
3528
        }
 
3529
 
 
3530
        exit;
 
3531
}
 
3532
 
 
3533
/**
 
3534
* Handler for init calls in phpBB. This function is called in user::setup();
 
3535
* This function supports hooks.
 
3536
*/
 
3537
function phpbb_user_session_handler()
 
3538
{
 
3539
        global $phpbb_hook;
 
3540
 
 
3541
        if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__))
 
3542
        {
 
3543
                if ($phpbb_hook->hook_return(__FUNCTION__))
 
3544
                {
 
3545
                        return $phpbb_hook->hook_return_result(__FUNCTION__);
 
3546
                }
 
3547
        }
 
3548
 
 
3549
        return;
 
3550
}
 
3551
 
 
3552
?>
 
 
b'\\ No newline at end of file'