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