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

« back to all changes in this revision

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

  • Committer: matt.giuca
  • Date: 2009-01-12 00:36:24 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1074
Removed "prototypes" directory (very old and clearly no longer used).

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'