[ Index ] |
PHP Cross Reference of MyBB |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * MyBB 1.6 4 * Copyright 2010 MyBB Group, All Rights Reserved 5 * 6 * Website: http://mybb.com 7 * License: http://mybb.com/about/license 8 * 9 * $Id$ 10 */ 11 12 /** 13 * Outputs a page directly to the browser, parsing anything which needs to be parsed. 14 * 15 * @param string The contents of the page. 16 */ 17 function output_page($contents) 18 { 19 global $db, $lang, $theme, $plugins, $mybb; 20 global $debug, $templatecache, $templatelist, $maintimer, $globaltime, $parsetime; 21 22 $contents = parse_page($contents); 23 $totaltime = $maintimer->stop(); 24 25 if($mybb->usergroup['cancp'] == 1) 26 { 27 if($mybb->settings['extraadmininfo'] != 0) 28 { 29 $phptime = $maintimer->format($maintimer->totaltime - $db->query_time); 30 $query_time = $maintimer->format($db->query_time); 31 32 if($maintimer->totaltime > 0) 33 { 34 $percentphp = number_format((($phptime/$maintimer->totaltime) * 100), 2); 35 $percentsql = number_format((($query_time/$maintimer->totaltime) * 100), 2); 36 } 37 else 38 { 39 // if we've got a super fast script... all we can do is assume something 40 $percentphp = 0; 41 $percentsql = 0; 42 } 43 44 $phpversion = PHP_VERSION; 45 46 $serverload = get_server_load(); 47 48 if(my_strpos(getenv("REQUEST_URI"), "?")) 49 { 50 $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "&debug=1"; 51 } 52 else 53 { 54 $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "?debug=1"; 55 } 56 57 if($mybb->settings['gzipoutput'] != 0) 58 { 59 $gzipen = "Enabled"; 60 } 61 else 62 { 63 $gzipen = "Disabled"; 64 } 65 66 $memory_usage = get_memory_usage(); 67 68 if($memory_usage) 69 { 70 $memory_usage = " / Memory Usage: ".get_friendly_size($memory_usage); 71 } 72 else 73 { 74 $memory_usage = ''; 75 } 76 // MySQLi is still MySQL, so present it that way to the user 77 $database_server = $db->short_title; 78 79 if($database_server == 'MySQLi') 80 { 81 $database_server = 'MySQL'; 82 } 83 $other = "PHP version: $phpversion / Server Load: $serverload / GZip Compression: $gzipen"; 84 $debugstuff = "Generated in $totaltime seconds ($percentphp% PHP / $percentsql% ".$database_server.")<br />SQL Queries: $db->query_count / Global Parsing Time: $globaltime$memory_usage<br />$other<br />[<a href=\"$debuglink\" target=\"_blank\">advanced details</a>]<br />"; 85 $contents = str_replace("<debugstuff>", $debugstuff, $contents); 86 } 87 88 if($mybb->debug_mode == true) 89 { 90 debug_page(); 91 } 92 } 93 94 $contents = str_replace("<debugstuff>", "", $contents); 95 $contents = $plugins->run_hooks("pre_output_page", $contents); 96 97 if($mybb->settings['gzipoutput'] == 1) 98 { 99 $contents = gzip_encode($contents, $mybb->settings['gziplevel']); 100 } 101 102 @header("Content-type: text/html; charset={$lang->settings['charset']}"); 103 104 echo $contents; 105 106 $plugins->run_hooks("post_output_page"); 107 } 108 109 /** 110 * Adds a function or class to the list of code to run on shutdown. 111 * 112 * @param mixed The name of the function. 113 * @param mixed An array of arguments for the function 114 * @return boolean True if function exists, otherwise false. 115 */ 116 function add_shutdown($name, $arguments=array()) 117 { 118 global $shutdown_functions; 119 120 if(!is_array($shutdown_functions)) 121 { 122 $shutdown_functions = array(); 123 } 124 125 if(!is_array($arguments)) 126 { 127 $arguments = array($arguments); 128 } 129 130 if(is_array($name) && method_exists($name[0], $name[1])) 131 { 132 $shutdown_functions[] = array('function' => $name, 'arguments' => $arguments); 133 return true; 134 } 135 else if(!is_array($name) && function_exists($name)) 136 { 137 $shutdown_functions[] = array('function' => $name, 'arguments' => $arguments); 138 return true; 139 } 140 141 return false; 142 } 143 144 /** 145 * Runs the shutdown items after the page has been sent to the browser. 146 * 147 */ 148 function run_shutdown() 149 { 150 global $config, $db, $cache, $plugins, $error_handler, $shutdown_functions, $shutdown_queries, $done_shutdown, $mybb; 151 152 if($done_shutdown == true || !$config || $error_handler->has_errors) 153 { 154 return; 155 } 156 157 // Missing the core? Build 158 if(!is_object($mybb)) 159 { 160 require_once MYBB_ROOT."inc/class_core.php"; 161 $mybb = new MyBB; 162 163 // Load the settings 164 require MYBB_ROOT."inc/settings.php"; 165 $mybb->settings = &$settings; 166 } 167 168 169 // If our DB has been deconstructed already (bad PHP 5.2.0), reconstruct 170 if(!is_object($db)) 171 { 172 if(!isset($config) || empty($config['database']['type'])) 173 { 174 require MYBB_ROOT."inc/config.php"; 175 } 176 177 if(isset($config)) 178 { 179 require_once MYBB_ROOT."inc/db_".$config['database']['type'].".php"; 180 switch($config['database']['type']) 181 { 182 case "sqlite": 183 $db = new DB_SQLite; 184 break; 185 case "pgsql": 186 $db = new DB_PgSQL; 187 break; 188 case "mysqli": 189 $db = new DB_MySQLi; 190 break; 191 default: 192 $db = new DB_MySQL; 193 } 194 195 196 $db->connect($config['database']); 197 define("TABLE_PREFIX", $config['database']['table_prefix']); 198 $db->set_table_prefix(TABLE_PREFIX); 199 } 200 } 201 202 // Cache object deconstructed? reconstruct 203 if(!is_object($cache)) 204 { 205 require_once MYBB_ROOT."inc/class_datacache.php"; 206 $cache = new datacache; 207 $cache->cache(); 208 } 209 210 // And finally.. plugins 211 if(!is_object($plugins) && !defined("NO_PLUGINS") && !($mybb->settings['no_plugins'] == 1)) 212 { 213 require_once MYBB_ROOT."inc/class_plugins.php"; 214 $plugins = new pluginSystem; 215 $plugins->load(); 216 } 217 218 // We have some shutdown queries needing to be run 219 if(is_array($shutdown_queries)) 220 { 221 // Loop through and run them all 222 foreach($shutdown_queries as $query) 223 { 224 $db->query($query); 225 } 226 } 227 228 // Run any shutdown functions if we have them 229 if(is_array($shutdown_functions)) 230 { 231 foreach($shutdown_functions as $function) 232 { 233 call_user_func_array($function['function'], $function['arguments']); 234 } 235 } 236 237 $done_shutdown = true; 238 } 239 240 /** 241 * Sends a specified amount of messages from the mail queue 242 * 243 * @param int The number of messages to send (Defaults to 10) 244 */ 245 function send_mail_queue($count=10) 246 { 247 global $db, $cache, $plugins; 248 249 $plugins->run_hooks("send_mail_queue_start"); 250 251 // Check to see if the mail queue has messages needing to be sent 252 $mailcache = $cache->read("mailqueue"); 253 if($mailcache['queue_size'] > 0 && ($mailcache['locked'] == 0 || $mailcache['locked'] < TIME_NOW-300)) 254 { 255 // Lock the queue so no other messages can be sent whilst these are (for popular boards) 256 $cache->update_mailqueue(0, TIME_NOW); 257 258 // Fetch emails for this page view - and send them 259 $query = $db->simple_select("mailqueue", "*", "", array("order_by" => "mid", "order_dir" => "asc", "limit_start" => 0, "limit" => $count)); 260 261 while($email = $db->fetch_array($query)) 262 { 263 // Delete the message from the queue 264 $db->delete_query("mailqueue", "mid='{$email['mid']}'"); 265 266 if($db->affected_rows() == 1) 267 { 268 my_mail($email['mailto'], $email['subject'], $email['message'], $email['mailfrom'], "", $email['headers'], true); 269 } 270 } 271 // Update the mailqueue cache and remove the lock 272 $cache->update_mailqueue(TIME_NOW, 0); 273 } 274 275 $plugins->run_hooks("send_mail_queue_end"); 276 } 277 278 /** 279 * Parses the contents of a page before outputting it. 280 * 281 * @param string The contents of the page. 282 * @return string The parsed page. 283 */ 284 function parse_page($contents) 285 { 286 global $lang, $theme, $mybb, $htmldoctype, $archive_url, $error_handler; 287 288 $contents = str_replace('<navigation>', build_breadcrumb(1), $contents); 289 $contents = str_replace('<archive_url>', $archive_url, $contents); 290 291 if($htmldoctype) 292 { 293 $contents = $htmldoctype.$contents; 294 } 295 else 296 { 297 $contents = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".$contents; 298 } 299 300 $contents = str_replace("<html", "<html xmlns=\"http://www.w3.org/1999/xhtml\"", $contents); 301 302 if($lang->settings['rtl'] == 1) 303 { 304 $contents = str_replace("<html", "<html dir=\"rtl\"", $contents); 305 } 306 307 if($lang->settings['htmllang']) 308 { 309 $contents = str_replace("<html", "<html xml:lang=\"".$lang->settings['htmllang']."\" lang=\"".$lang->settings['htmllang']."\"", $contents); 310 } 311 312 if($error_handler->warnings) 313 { 314 $contents = str_replace("<body>", "<body>\n".$error_handler->show_warnings(), $contents); 315 } 316 317 return $contents; 318 } 319 320 /** 321 * Turn a unix timestamp in to a "friendly" date/time format for the user. 322 * 323 * @param string A date format according to PHP's date structure. 324 * @param int The unix timestamp the date should be generated for. 325 * @param int The offset in hours that should be applied to times. (timezones) 326 * @param int Whether or not to use today/yesterday formatting. 327 * @param boolean Whether or not to use the adodb time class for < 1970 or > 2038 times 328 * @return string The formatted timestamp. 329 */ 330 function my_date($format, $stamp="", $offset="", $ty=1, $adodb=false) 331 { 332 global $mybb, $lang, $mybbadmin, $plugins; 333 334 // If the stamp isn't set, use TIME_NOW 335 if(empty($stamp)) 336 { 337 $stamp = TIME_NOW; 338 } 339 340 if(!$offset && $offset != '0') 341 { 342 if(isset($mybb->user['uid']) && $mybb->user['uid'] != 0 && array_key_exists("timezone", $mybb->user)) 343 { 344 $offset = $mybb->user['timezone']; 345 $dstcorrection = $mybb->user['dst']; 346 } 347 elseif(defined("IN_ADMINCP")) 348 { 349 $offset = $mybbadmin['timezone']; 350 $dstcorrection = $mybbadmin['dst']; 351 } 352 else 353 { 354 $offset = $mybb->settings['timezoneoffset']; 355 $dstcorrection = $mybb->settings['dstcorrection']; 356 } 357 358 // If DST correction is enabled, add an additional hour to the timezone. 359 if($dstcorrection == 1) 360 { 361 ++$offset; 362 if(my_substr($offset, 0, 1) != "-") 363 { 364 $offset = "+".$offset; 365 } 366 } 367 } 368 369 if($offset == "-") 370 { 371 $offset = 0; 372 } 373 374 if($adodb == true && function_exists('adodb_date')) 375 { 376 $date = adodb_date($format, $stamp + ($offset * 3600)); 377 } 378 else 379 { 380 $date = gmdate($format, $stamp + ($offset * 3600)); 381 } 382 383 if($mybb->settings['dateformat'] == $format && $ty) 384 { 385 $stamp = TIME_NOW; 386 387 if($adodb == true && function_exists('adodb_date')) 388 { 389 $todaysdate = adodb_date($format, $stamp + ($offset * 3600)); 390 $yesterdaysdate = adodb_date($format, ($stamp - 86400) + ($offset * 3600)); 391 } 392 else 393 { 394 $todaysdate = gmdate($format, $stamp + ($offset * 3600)); 395 $yesterdaysdate = gmdate($format, ($stamp - 86400) + ($offset * 3600)); 396 } 397 398 if($todaysdate == $date) 399 { 400 $date = $lang->today; 401 } 402 else if($yesterdaysdate == $date) 403 { 404 $date = $lang->yesterday; 405 } 406 } 407 408 if(is_object($plugins)) 409 { 410 $date = $plugins->run_hooks("my_date", $date); 411 } 412 413 return $date; 414 } 415 416 /** 417 * Sends an email using PHP's mail function, formatting it appropriately. 418 * 419 * @param string Address the email should be addressed to. 420 * @param string The subject of the email being sent. 421 * @param string The message being sent. 422 * @param string The from address of the email, if blank, the board name will be used. 423 * @param string The chracter set being used to send this email. 424 * @param boolean Do we wish to keep the connection to the mail server alive to send more than one message (SMTP only) 425 * @param string The format of the email to be sent (text or html). text is default 426 * @param string The text message of the email if being sent in html format, for email clients that don't support html 427 * @param string The email address to return to. Defaults to admin return email address. 428 */ 429 function my_mail($to, $subject, $message, $from="", $charset="", $headers="", $keep_alive=false, $format="text", $message_text="", $return_email="") 430 { 431 global $mybb; 432 static $mail; 433 434 // Does our object not exist? Create it 435 if(!is_object($mail)) 436 { 437 require_once MYBB_ROOT."inc/class_mailhandler.php"; 438 439 if($mybb->settings['mail_handler'] == 'smtp') 440 { 441 require_once MYBB_ROOT."inc/mailhandlers/smtp.php"; 442 $mail = new SmtpMail(); 443 } 444 else 445 { 446 require_once MYBB_ROOT."inc/mailhandlers/php.php"; 447 $mail = new PhpMail(); 448 } 449 } 450 451 // Using SMTP based mail 452 if($mybb->settings['mail_handler'] == 'smtp') 453 { 454 if($keep_alive == true) 455 { 456 $mail->keep_alive = true; 457 } 458 } 459 460 // Using PHP based mail() 461 else 462 { 463 if($mybb->settings['mail_parameters'] != '') 464 { 465 $mail->additional_parameters = $mybb->settings['mail_parameters']; 466 } 467 } 468 469 // Build and send 470 $mail->build_message($to, $subject, $message, $from, $charset, $headers, $format, $message_text, $return_email); 471 return $mail->send(); 472 } 473 474 /** 475 * Generates a unique code for POST requests to prevent XSS/CSRF attacks 476 * 477 * @return string The generated code 478 */ 479 function generate_post_check() 480 { 481 global $mybb, $session; 482 if($mybb->user['uid']) 483 { 484 return md5($mybb->user['loginkey'].$mybb->user['salt'].$mybb->user['regdate']); 485 } 486 // Guests get a special string 487 else 488 { 489 return md5($session->useragent.$mybb->config['database']['username'].$mybb->settings['internal']['encryption_key']); 490 } 491 } 492 493 /** 494 * Verifies a POST check code is valid, if not shows an error (silently returns false on silent parameter) 495 * 496 * @param string The incoming POST check code 497 * @param boolean Silent mode or not (silent mode will not show the error to the user but returns false) 498 */ 499 function verify_post_check($code, $silent=false) 500 { 501 global $lang; 502 if(generate_post_check() != $code) 503 { 504 if($silent == true) 505 { 506 return false; 507 } 508 else 509 { 510 if(defined("IN_ADMINCP")) 511 { 512 return false; 513 } 514 else 515 { 516 error($lang->invalid_post_code); 517 } 518 } 519 } 520 else 521 { 522 return true; 523 } 524 } 525 526 /** 527 * Return a parent list for the specified forum. 528 * 529 * @param int The forum id to get the parent list for. 530 * @return string The comma-separated parent list. 531 */ 532 function get_parent_list($fid) 533 { 534 global $forum_cache; 535 static $forumarraycache; 536 537 if($forumarraycache[$fid]) 538 { 539 return $forumarraycache[$fid]['parentlist']; 540 } 541 elseif($forum_cache[$fid]) 542 { 543 return $forum_cache[$fid]['parentlist']; 544 } 545 else 546 { 547 cache_forums(); 548 return $forum_cache[$fid]['parentlist']; 549 } 550 } 551 552 /** 553 * Build a parent list of a specific forum, suitable for querying 554 * 555 * @param int The forum ID 556 * @param string The column name to add to the query 557 * @param string The joiner for each forum for querying (OR | AND | etc) 558 * @param string The parent list of the forum - if you have it 559 * @return string The query string generated 560 */ 561 function build_parent_list($fid, $column="fid", $joiner="OR", $parentlist="") 562 { 563 if(!$parentlist) 564 { 565 $parentlist = get_parent_list($fid); 566 } 567 568 $parentsexploded = explode(",", $parentlist); 569 $builtlist = "("; 570 $sep = ''; 571 572 foreach($parentsexploded as $key => $val) 573 { 574 $builtlist .= "$sep$column='$val'"; 575 $sep = " $joiner "; 576 } 577 578 $builtlist .= ")"; 579 580 return $builtlist; 581 } 582 583 /** 584 * Load the forum cache in to memory 585 * 586 * @param boolean True to force a reload of the cache 587 */ 588 function cache_forums($force=false) 589 { 590 global $forum_cache, $cache; 591 592 if($force == true) 593 { 594 $forum_cache = $cache->read("forums", 1); 595 return $forum_cache; 596 } 597 598 if(!$forum_cache) 599 { 600 $forum_cache = $cache->read("forums"); 601 if(!$forum_cache) 602 { 603 $cache->update_forums(); 604 $forum_cache = $cache->read("forums", 1); 605 } 606 } 607 return $forum_cache; 608 } 609 610 /** 611 * Generate an array of all child and descendant forums for a specific forum. 612 * 613 * @param int The forum ID 614 * @param return Array of descendants 615 */ 616 function get_child_list($fid) 617 { 618 static $forums_by_parent; 619 620 $forums = array(); 621 if(!is_array($forums_by_parent)) 622 { 623 $forum_cache = cache_forums(); 624 foreach($forum_cache as $forum) 625 { 626 if($forum['active'] != 0) 627 { 628 $forums_by_parent[$forum['pid']][$forum['fid']] = $forum; 629 } 630 } 631 } 632 if(!is_array($forums_by_parent[$fid])) 633 { 634 return; 635 } 636 637 foreach($forums_by_parent[$fid] as $forum) 638 { 639 $forums[] = $forum['fid']; 640 $children = get_child_list($forum['fid']); 641 if(is_array($children)) 642 { 643 $forums = array_merge($forums, $children); 644 } 645 } 646 return $forums; 647 } 648 649 /** 650 * Produce a friendly error message page 651 * 652 * @param string The error message to be shown 653 * @param string The title of the message shown in the title of the page and the error table 654 */ 655 function error($error="", $title="") 656 { 657 global $header, $footer, $theme, $headerinclude, $db, $templates, $lang, $mybb, $plugins; 658 659 $error = $plugins->run_hooks("error", $error); 660 if(!$error) 661 { 662 $error = $lang->unknown_error; 663 } 664 665 // AJAX error message? 666 if($mybb->input['ajax']) 667 { 668 // Send our headers. 669 @header("Content-type: text/html; charset={$lang->settings['charset']}"); 670 echo "<error>{$error}</error>\n"; 671 exit; 672 } 673 674 if(!$title) 675 { 676 $title = $mybb->settings['bbname']; 677 } 678 679 $timenow = my_date($mybb->settings['dateformat'], TIME_NOW) . " " . my_date($mybb->settings['timeformat'], TIME_NOW); 680 reset_breadcrumb(); 681 add_breadcrumb($lang->error); 682 683 eval("\$errorpage = \"".$templates->get("error")."\";"); 684 output_page($errorpage); 685 686 exit; 687 } 688 689 /** 690 * Produce an error message for displaying inline on a page 691 * 692 * @param array Array of errors to be shown 693 * @param string The title of the error message 694 * @return string The inline error HTML 695 */ 696 function inline_error($errors, $title="") 697 { 698 global $theme, $mybb, $db, $lang, $templates; 699 700 if(!$title) 701 { 702 $title = $lang->please_correct_errors; 703 } 704 705 if(!is_array($errors)) 706 { 707 $errors = array($errors); 708 } 709 710 // AJAX error message? 711 if($mybb->input['ajax']) 712 { 713 $error = implode("\n\n", $errors); 714 // Send our headers. 715 @header("Content-type: text/html; charset={$lang->settings['charset']}"); 716 echo "<error>{$error}</error>\n"; 717 exit; 718 } 719 720 foreach($errors as $error) 721 { 722 $errorlist .= "<li>".$error."</li>\n"; 723 } 724 725 eval("\$errors = \"".$templates->get("error_inline")."\";"); 726 727 return $errors; 728 } 729 730 /** 731 * Presents the user with a "no permission" page 732 */ 733 function error_no_permission() 734 { 735 global $mybb, $theme, $templates, $db, $lang, $plugins, $session; 736 737 $time = TIME_NOW; 738 $plugins->run_hooks("no_permission"); 739 740 $noperm_array = array ( 741 "nopermission" => '1', 742 "location1" => 0, 743 "location2" => 0 744 ); 745 746 $db->update_query("sessions", $noperm_array, "sid='{$session->sid}'", 1); 747 748 if($mybb->input['ajax']) 749 { 750 // Send our headers. 751 header("Content-type: text/html; charset={$lang->settings['charset']}"); 752 echo "<error>{$lang->error_nopermission_user_ajax}</error>\n"; 753 exit; 754 } 755 756 if($mybb->user['uid']) 757 { 758 $lang->error_nopermission_user_username = $lang->sprintf($lang->error_nopermission_user_username, $mybb->user['username']); 759 eval("\$errorpage = \"".$templates->get("error_nopermission_loggedin")."\";"); 760 } 761 else 762 { 763 // Redirect to where the user came from 764 $redirect_url = $_SERVER['PHP_SELF']; 765 if($_SERVER['QUERY_STRING']) 766 { 767 $redirect_url .= '?'.$_SERVER['QUERY_STRING']; 768 } 769 770 $redirect_url = htmlspecialchars_uni($redirect_url); 771 772 switch($mybb->settings['username_method']) 773 { 774 case 0: 775 $lang_username = $lang->username; 776 break; 777 case 1: 778 $lang_username = $lang->username1; 779 break; 780 case 2: 781 $lang_username = $lang->username2; 782 break; 783 default: 784 $lang_username = $lang->username; 785 break; 786 } 787 eval("\$errorpage = \"".$templates->get("error_nopermission")."\";"); 788 } 789 790 error($errorpage); 791 } 792 793 /** 794 * Redirect the user to a given URL with a given message 795 * 796 * @param string The URL to redirect the user to 797 * @param string The redirection message to be shown 798 */ 799 function redirect($url, $message="", $title="") 800 { 801 global $header, $footer, $mybb, $theme, $headerinclude, $templates, $lang, $plugins; 802 803 $redirect_args = array('url' => &$url, 'message' => &$message, 'title' => &$title); 804 805 $plugins->run_hooks("redirect", $redirect_args); 806 807 if($mybb->input['ajax']) 808 { 809 // Send our headers. 810 @header("Content-type: text/html; charset={$lang->settings['charset']}"); 811 echo "<script type=\"text/javascript\">\n"; 812 if($message != "") 813 { 814 echo 'alert("'.addslashes($message).'");'; 815 } 816 $url = str_replace("#", "&#", $url); 817 $url = htmlspecialchars_decode($url); 818 $url = str_replace(array("\n","\r",";"), "", $url); 819 echo 'window.location = "'.addslashes($url).'";'."\n"; 820 echo "</script>\n"; 821 exit; 822 } 823 824 if(!$message) 825 { 826 $message = $lang->redirect; 827 } 828 829 $time = TIME_NOW; 830 $timenow = my_date($mybb->settings['dateformat'], $time) . " " . my_date($mybb->settings['timeformat'], $time); 831 832 if(!$title) 833 { 834 $title = $mybb->settings['bbname']; 835 } 836 837 // Show redirects only if both ACP and UCP settings are enabled, or ACP is enabled, and user is a guest. 838 if($mybb->settings['redirects'] == 1 && ($mybb->user['showredirect'] != 0 || !$mybb->user['uid'])) 839 { 840 $url = str_replace("&", "&", $url); 841 $url = htmlspecialchars_uni($url); 842 843 eval("\$redirectpage = \"".$templates->get("redirect")."\";"); 844 output_page($redirectpage); 845 } 846 else 847 { 848 $url = htmlspecialchars_decode($url); 849 $url = str_replace(array("\n","\r",";"), "", $url); 850 851 run_shutdown(); 852 853 if(my_substr($url, 0, 7) !== 'http://' && my_substr($url, 0, 8) !== 'https://' && my_substr($url, 0, 1) !== '/') 854 { 855 header("Location: {$mybb->settings['bburl']}/{$url}"); 856 } 857 else 858 { 859 header("Location: {$url}"); 860 } 861 } 862 863 exit; 864 } 865 866 /** 867 * Generate a listing of page - pagination 868 * 869 * @param int The number of items 870 * @param int The number of items to be shown per page 871 * @param int The current page number 872 * @param string The URL to have page numbers tacked on to (If {page} is specified, the value will be replaced with the page #) 873 * @return string The generated pagination 874 */ 875 function multipage($count, $perpage, $page, $url, $breadcrumb=false) 876 { 877 global $theme, $templates, $lang, $mybb; 878 879 if($count <= $perpage) 880 { 881 return; 882 } 883 884 $url = str_replace("&", "&", $url); 885 $url = htmlspecialchars_uni($url); 886 887 $pages = ceil($count / $perpage); 888 889 $prevpage = ''; 890 if($page > 1) 891 { 892 $prev = $page-1; 893 $page_url = fetch_page_url($url, $prev); 894 eval("\$prevpage = \"".$templates->get("multipage_prevpage")."\";"); 895 } 896 897 // Maximum number of "page bits" to show 898 if(!$mybb->settings['maxmultipagelinks']) 899 { 900 $mybb->settings['maxmultipagelinks'] = 5; 901 } 902 903 $from = $page-floor($mybb->settings['maxmultipagelinks']/2); 904 $to = $page+floor($mybb->settings['maxmultipagelinks']/2); 905 906 if($from <= 0) 907 { 908 $from = 1; 909 $to = $from+$mybb->settings['maxmultipagelinks']-1; 910 } 911 912 if($to > $pages) 913 { 914 $to = $pages; 915 $from = $pages-$mybb->settings['maxmultipagelinks']+1; 916 if($from <= 0) 917 { 918 $from = 1; 919 } 920 } 921 922 if($to == 0) 923 { 924 $to = $pages; 925 } 926 927 $start = ''; 928 if($from > 1) 929 { 930 if($from-1 == 1) 931 { 932 $lang->multipage_link_start = ''; 933 } 934 935 $page_url = fetch_page_url($url, 1); 936 eval("\$start = \"".$templates->get("multipage_start")."\";"); 937 } 938 939 $mppage = ''; 940 for($i = $from; $i <= $to; ++$i) 941 { 942 $page_url = fetch_page_url($url, $i); 943 if($page == $i) 944 { 945 if($breadcrumb == true) 946 { 947 eval("\$mppage .= \"".$templates->get("multipage_page_link_current")."\";"); 948 } 949 else 950 { 951 eval("\$mppage .= \"".$templates->get("multipage_page_current")."\";"); 952 } 953 } 954 else 955 { 956 eval("\$mppage .= \"".$templates->get("multipage_page")."\";"); 957 } 958 } 959 960 $end = ''; 961 if($to < $pages) 962 { 963 if($to+1 == $pages) 964 { 965 $lang->multipage_link_end = ''; 966 } 967 968 $page_url = fetch_page_url($url, $pages); 969 eval("\$end = \"".$templates->get("multipage_end")."\";"); 970 } 971 972 $nextpage = ''; 973 if($page < $pages) 974 { 975 $next = $page+1; 976 $page_url = fetch_page_url($url, $next); 977 eval("\$nextpage = \"".$templates->get("multipage_nextpage")."\";"); 978 } 979 980 $lang->multipage_pages = $lang->sprintf($lang->multipage_pages, $pages); 981 982 if($breadcrumb == true) 983 { 984 eval("\$multipage = \"".$templates->get("multipage_breadcrumb")."\";"); 985 } 986 else 987 { 988 eval("\$multipage = \"".$templates->get("multipage")."\";"); 989 } 990 991 return $multipage; 992 } 993 994 /** 995 * Generate a page URL for use by the multipage function 996 * 997 * @param string The URL being passed 998 * @param int The page number 999 */ 1000 function fetch_page_url($url, $page) 1001 { 1002 if($page <= 1) 1003 { 1004 $find = array( 1005 "-page-{page}", 1006 "&page={page}", 1007 "{page}" 1008 ); 1009 1010 // Remove "Page 1" to the defacto URL 1011 $url = str_replace($find, array("", "", $page), $url); 1012 return $url; 1013 } 1014 else if(strpos($url, "{page}") === false) 1015 { 1016 // If no page identifier is specified we tack it on to the end of the URL 1017 if(strpos($url, "?") === false) 1018 { 1019 $url .= "?"; 1020 } 1021 else 1022 { 1023 $url .= "&"; 1024 } 1025 1026 $url .= "page=$page"; 1027 } 1028 else 1029 { 1030 $url = str_replace("{page}", $page, $url); 1031 } 1032 1033 return $url; 1034 } 1035 1036 /** 1037 * Fetch the permissions for a specific user 1038 * 1039 * @param int The user ID 1040 * @return array Array of user permissions for the specified user 1041 */ 1042 function user_permissions($uid=0) 1043 { 1044 global $mybb, $cache, $groupscache, $user_cache; 1045 1046 // If no user id is specified, assume it is the current user 1047 if($uid == 0) 1048 { 1049 $uid = $mybb->user['uid']; 1050 } 1051 1052 // User id does not match current user, fetch permissions 1053 if($uid != $mybb->user['uid']) 1054 { 1055 // We've already cached permissions for this user, return them. 1056 if($user_cache[$uid]['permissions']) 1057 { 1058 return $user_cache[$uid]['permissions']; 1059 } 1060 1061 // This user was not already cached, fetch their user information. 1062 if(!$user_cache[$uid]) 1063 { 1064 $user_cache[$uid] = get_user($uid); 1065 } 1066 1067 // Collect group permissions. 1068 $gid = $user_cache[$uid]['usergroup'].",".$user_cache[$uid]['additionalgroups']; 1069 $groupperms = usergroup_permissions($gid); 1070 1071 // Store group permissions in user cache. 1072 $user_cache[$uid]['permissions'] = $groupperms; 1073 return $groupperms; 1074 } 1075 // This user is the current user, return their permissions 1076 else 1077 { 1078 return $mybb->usergroup; 1079 } 1080 } 1081 1082 /** 1083 * Fetch the usergroup permissions for a specic group or series of groups combined 1084 * 1085 * @param mixed A list of groups (Can be a single integer, or a list of groups separated by a comma) 1086 * @return array Array of permissions generated for the groups 1087 */ 1088 function usergroup_permissions($gid=0) 1089 { 1090 global $cache, $groupscache, $grouppermignore, $groupzerogreater; 1091 1092 if(!is_array($groupscache)) 1093 { 1094 $groupscache = $cache->read("usergroups"); 1095 } 1096 1097 $groups = explode(",", $gid); 1098 1099 1100 if(count($groups) == 1) 1101 { 1102 return $groupscache[$gid]; 1103 } 1104 1105 foreach($groups as $gid) 1106 { 1107 if(trim($gid) == "" || !$groupscache[$gid]) 1108 { 1109 continue; 1110 } 1111 1112 foreach($groupscache[$gid] as $perm => $access) 1113 { 1114 if(!in_array($perm, $grouppermignore)) 1115 { 1116 if(isset($usergroup[$perm])) 1117 { 1118 $permbit = $usergroup[$perm]; 1119 } 1120 else 1121 { 1122 $permbit = ""; 1123 } 1124 1125 // 0 represents unlimited for numerical group permissions (i.e. private message limit) so take that into account. 1126 if(in_array($perm, $groupzerogreater) && ($access == 0 || $permbit === 0)) 1127 { 1128 $usergroup[$perm] = 0; 1129 continue; 1130 } 1131 1132 if($access > $permbit || ($access == "yes" && $permbit == "no") || !$permbit) // Keep yes/no for compatibility? 1133 { 1134 $usergroup[$perm] = $access; 1135 } 1136 } 1137 } 1138 } 1139 1140 return $usergroup; 1141 } 1142 1143 /** 1144 * Fetch the display group properties for a specific display group 1145 * 1146 * @param int The group ID to fetch the display properties for 1147 * @return array Array of display properties for the group 1148 */ 1149 function usergroup_displaygroup($gid) 1150 { 1151 global $cache, $groupscache, $displaygroupfields; 1152 1153 if(!is_array($groupscache)) 1154 { 1155 $groupscache = $cache->read("usergroups"); 1156 } 1157 1158 $displaygroup = array(); 1159 $group = $groupscache[$gid]; 1160 1161 foreach($displaygroupfields as $field) 1162 { 1163 $displaygroup[$field] = $group[$field]; 1164 } 1165 1166 return $displaygroup; 1167 } 1168 1169 /** 1170 * Build the forum permissions for a specific forum, user or group 1171 * 1172 * @param int The forum ID to build permissions for (0 builds for all forums) 1173 * @param int The user to build the permissions for (0 will select the uid automatically) 1174 * @param int The group of the user to build permissions for (0 will fetch it) 1175 * @return array Forum permissions for the specific forum or forums 1176 */ 1177 function forum_permissions($fid=0, $uid=0, $gid=0) 1178 { 1179 global $db, $cache, $groupscache, $forum_cache, $fpermcache, $mybb, $usercache, $cached_forum_permissions_permissions, $cached_forum_permissions; 1180 1181 if($uid == 0) 1182 { 1183 $uid = $mybb->user['uid']; 1184 } 1185 1186 if(!$gid || $gid == 0) // If no group, we need to fetch it 1187 { 1188 if($uid != 0 && $uid != $mybb->user['uid']) 1189 { 1190 if(!$usercache[$uid]) 1191 { 1192 $query = $db->simple_select("users", "*", "uid='$uid'"); 1193 $usercache[$uid] = $db->fetch_array($query); 1194 } 1195 1196 $gid = $usercache[$uid]['usergroup'].",".$usercache[$uid]['additionalgroups']; 1197 $groupperms = usergroup_permissions($gid); 1198 } 1199 else 1200 { 1201 $gid = $mybb->user['usergroup']; 1202 1203 if(isset($mybb->user['additionalgroups'])) 1204 { 1205 $gid .= ",".$mybb->user['additionalgroups']; 1206 } 1207 1208 $groupperms = $mybb->usergroup; 1209 } 1210 } 1211 1212 if(!is_array($forum_cache)) 1213 { 1214 $forum_cache = cache_forums(); 1215 1216 if(!$forum_cache) 1217 { 1218 return false; 1219 } 1220 } 1221 1222 if(!is_array($fpermcache)) 1223 { 1224 $fpermcache = $cache->read("forumpermissions"); 1225 } 1226 1227 if($fid) // Fetch the permissions for a single forum 1228 { 1229 if(!$cached_forum_permissions_permissions[$gid][$fid]) 1230 { 1231 $cached_forum_permissions_permissions[$gid][$fid] = fetch_forum_permissions($fid, $gid, $groupperms); 1232 } 1233 return $cached_forum_permissions_permissions[$gid][$fid]; 1234 } 1235 else 1236 { 1237 if(!$cached_forum_permissions[$gid]) 1238 { 1239 foreach($forum_cache as $forum) 1240 { 1241 $cached_forum_permissions[$gid][$forum['fid']] = fetch_forum_permissions($forum['fid'], $gid, $groupperms); 1242 } 1243 } 1244 return $cached_forum_permissions[$gid]; 1245 } 1246 } 1247 1248 /** 1249 * Fetches the permissions for a specific forum/group applying the inheritance scheme. 1250 * Called by forum_permissions() 1251 * 1252 * @param int The forum ID 1253 * @param string A comma separated list of usergroups 1254 * @param array Group permissions 1255 * @return array Permissions for this forum 1256 */ 1257 function fetch_forum_permissions($fid, $gid, $groupperms) 1258 { 1259 global $groupscache, $forum_cache, $fpermcache, $mybb, $fpermfields; 1260 1261 $groups = explode(",", $gid); 1262 1263 if(empty($fpermcache[$fid])) // This forum has no custom or inherited permissions so lets just return the group permissions 1264 { 1265 return $groupperms; 1266 } 1267 1268 $current_permissions = array(); 1269 $only_view_own_threads = 1; 1270 1271 foreach($groups as $gid) 1272 { 1273 if($groupscache[$gid]) 1274 { 1275 $level_permissions = $fpermcache[$fid][$gid]; 1276 1277 // If our permissions arn't inherited we need to figure them out 1278 if(empty($level_permissions)) 1279 { 1280 $parents = explode(',', $forum_cache[$fid]['parentlist']); 1281 rsort($parents); 1282 if(!empty($parents)) 1283 { 1284 foreach($parents as $parent_id) 1285 { 1286 if(!empty($fpermcache[$parent_id][$gid])) 1287 { 1288 $level_permissions = $fpermcache[$parent_id][$gid]; 1289 break; 1290 } 1291 } 1292 1293 // If we STILL don't have forum permissions we use the usergroup itself 1294 if(empty($level_permissions)) 1295 { 1296 $level_permissions = $groupscache[$gid]; 1297 } 1298 } 1299 } 1300 1301 foreach($level_permissions as $permission => $access) 1302 { 1303 if($access >= $current_permissions[$permission] || ($access == "yes" && $current_permissions[$permission] == "no") || !$current_permissions[$permission]) 1304 { 1305 $current_permissions[$permission] = $access; 1306 } 1307 } 1308 1309 if($level_permissions["canview"] && !$level_permissions["canonlyviewownthreads"]) 1310 { 1311 $only_view_own_threads = 0; 1312 } 1313 } 1314 } 1315 1316 // Figure out if we can view more than our own threads 1317 if($only_view_own_threads == 0) 1318 { 1319 $current_permissions["canonlyviewownthreads"] = 0; 1320 } 1321 1322 if(count($current_permissions) == 0) 1323 { 1324 $current_permissions = $groupperms; 1325 } 1326 return $current_permissions; 1327 } 1328 1329 /** 1330 * Check the password given on a certain forum for validity 1331 * 1332 * @param int The forum ID 1333 * @param boolean The Parent ID 1334 */ 1335 function check_forum_password($fid, $pid=0) 1336 { 1337 global $mybb, $header, $footer, $headerinclude, $theme, $templates, $lang, $forum_cache; 1338 1339 $showform = true; 1340 1341 if(!is_array($forum_cache)) 1342 { 1343 $forum_cache = cache_forums(); 1344 if(!$forum_cache) 1345 { 1346 return false; 1347 } 1348 } 1349 1350 // Loop through each of parent forums to ensure we have a password for them too 1351 $parents = explode(',', $forum_cache[$fid]['parentlist']); 1352 rsort($parents); 1353 if(!empty($parents)) 1354 { 1355 foreach($parents as $parent_id) 1356 { 1357 if($parent_id == $fid || $parent_id == $pid) 1358 { 1359 continue; 1360 } 1361 1362 if($forum_cache[$parent_id]['password'] != "") 1363 { 1364 check_forum_password($parent_id, $fid); 1365 } 1366 } 1367 } 1368 1369 $password = $forum_cache[$fid]['password']; 1370 if($password) 1371 { 1372 if($mybb->input['pwverify'] && $pid == 0) 1373 { 1374 if($password == $mybb->input['pwverify']) 1375 { 1376 my_setcookie("forumpass[$fid]", md5($mybb->user['uid'].$mybb->input['pwverify']), null, true); 1377 $showform = false; 1378 } 1379 else 1380 { 1381 eval("\$pwnote = \"".$templates->get("forumdisplay_password_wrongpass")."\";"); 1382 $showform = true; 1383 } 1384 } 1385 else 1386 { 1387 if(!$mybb->cookies['forumpass'][$fid] || ($mybb->cookies['forumpass'][$fid] && md5($mybb->user['uid'].$password) != $mybb->cookies['forumpass'][$fid])) 1388 { 1389 $showform = true; 1390 } 1391 else 1392 { 1393 $showform = false; 1394 } 1395 } 1396 } 1397 else 1398 { 1399 $showform = false; 1400 } 1401 1402 if($showform) 1403 { 1404 if($pid) 1405 { 1406 header("Location: ".$mybb->settings['bburl']."/".get_forum_link($fid)); 1407 } 1408 else 1409 { 1410 $_SERVER['REQUEST_URI'] = htmlspecialchars_uni($_SERVER['REQUEST_URI']); 1411 eval("\$pwform = \"".$templates->get("forumdisplay_password")."\";"); 1412 output_page($pwform); 1413 } 1414 exit; 1415 } 1416 } 1417 1418 /** 1419 * Return the permissions for a moderator in a specific forum 1420 * 1421 * @param fid The forum ID 1422 * @param uid The user ID to fetch permissions for (0 assumes current logged in user) 1423 * @param string The parent list for the forum (if blank, will be fetched) 1424 * @return array Array of moderator permissions for the specific forum 1425 */ 1426 function get_moderator_permissions($fid, $uid="0", $parentslist="") 1427 { 1428 global $mybb, $cache, $db; 1429 static $modpermscache; 1430 1431 if($uid < 1) 1432 { 1433 $uid = $mybb->user['uid']; 1434 } 1435 1436 if($uid == 0) 1437 { 1438 return false; 1439 } 1440 1441 if(isset($modpermscache[$fid][$uid])) 1442 { 1443 return $modpermscache[$fid][$uid]; 1444 } 1445 1446 if(!$parentslist) 1447 { 1448 $parentslist = explode(',', get_parent_list($fid)); 1449 } 1450 1451 // Get user groups 1452 $perms = array(); 1453 $user = get_user($uid); 1454 1455 $groups = array($user['usergroup']); 1456 1457 if(!empty($user['additionalgroups'])) 1458 { 1459 $extra_groups = explode(",", $user['additionalgroups']); 1460 1461 foreach($extra_groups as $extra_group) 1462 { 1463 $groups[] = $extra_group; 1464 } 1465 } 1466 1467 $mod_cache = $cache->read("moderators"); 1468 1469 foreach($mod_cache as $fid => $forum) 1470 { 1471 if(!is_array($forum) || !in_array($fid, $parentslist)) 1472 { 1473 // No perms or we're not after this forum 1474 continue; 1475 } 1476 1477 // User settings override usergroup settings 1478 if(is_array($forum['users'][$uid])) 1479 { 1480 $perm = $forum['users'][$uid]; 1481 foreach($perm as $action => $value) 1482 { 1483 if(strpos($action, "can") === false) 1484 { 1485 continue; 1486 } 1487 1488 // Figure out the user permissions 1489 if($value == 0) 1490 { 1491 // The user doesn't have permission to set this action 1492 $perms[$action] = 0; 1493 } 1494 else 1495 { 1496 $perms[$action] = max($perm[$action], $perms[$action]); 1497 } 1498 } 1499 } 1500 1501 foreach($groups as $group) 1502 { 1503 if(!is_array($forum['usergroups'][$group])) 1504 { 1505 // There are no permissions set for this group 1506 continue; 1507 } 1508 1509 $perm = $forum['usergroups'][$group]; 1510 foreach($perm as $action => $value) 1511 { 1512 if(strpos($action, "can") === false) 1513 { 1514 continue; 1515 } 1516 1517 $perms[$action] = max($perm[$action], $perms[$action]); 1518 } 1519 } 1520 } 1521 1522 $modpermscache[$fid][$uid] = $perms; 1523 1524 return $perms; 1525 } 1526 1527 /** 1528 * Checks if a moderator has permissions to perform an action in a specific forum 1529 * 1530 * @param int The forum ID (0 assumes global) 1531 * @param string The action tyring to be performed. (blank assumes any action at all) 1532 * @param int The user ID (0 assumes current user) 1533 * @return bool Returns true if the user has permission, false if they do not 1534 */ 1535 function is_moderator($fid="0", $action="", $uid="0") 1536 { 1537 global $mybb, $cache; 1538 1539 if($uid == 0) 1540 { 1541 $uid = $mybb->user['uid']; 1542 } 1543 1544 if($uid == 0) 1545 { 1546 return false; 1547 } 1548 1549 $user_perms = user_permissions($uid); 1550 if($user_perms['issupermod'] == 1) 1551 { 1552 return true; 1553 } 1554 else 1555 { 1556 if(!$fid) 1557 { 1558 $modcache = $cache->read('moderators'); 1559 if(!empty($modcache)) 1560 { 1561 foreach($modcache as $modusers) 1562 { 1563 if(isset($modusers['users'][$uid]) && $modusers['users'][$uid]['mid']) 1564 { 1565 return true; 1566 } 1567 elseif(isset($modusers['usergroups'][$user_perms['gid']])) 1568 { 1569 // Moderating usergroup 1570 return true; 1571 } 1572 } 1573 } 1574 return false; 1575 } 1576 else 1577 { 1578 $modperms = get_moderator_permissions($fid, $uid); 1579 1580 if(!$action && $modperms) 1581 { 1582 return true; 1583 } 1584 else 1585 { 1586 if($modperms[$action] == 1) 1587 { 1588 return true; 1589 } 1590 else 1591 { 1592 return false; 1593 } 1594 } 1595 } 1596 } 1597 } 1598 1599 /** 1600 * Generate a list of the posticons. 1601 * 1602 * @return string The template of posticons. 1603 */ 1604 function get_post_icons() 1605 { 1606 global $mybb, $cache, $icon, $theme, $templates, $lang; 1607 1608 $listed = 0; 1609 if($mybb->input['icon']) 1610 { 1611 $icon = $mybb->input['icon']; 1612 } 1613 1614 $iconlist = ''; 1615 $no_icons_checked = " checked=\"checked\""; 1616 // read post icons from cache, and sort them accordingly 1617 $posticons_cache = $cache->read("posticons"); 1618 $posticons = array(); 1619 foreach($posticons_cache as $posticon) 1620 { 1621 $posticons[$posticon['name']] = $posticon; 1622 } 1623 krsort($posticons); 1624 1625 foreach($posticons as $dbicon) 1626 { 1627 $dbicon['path'] = htmlspecialchars_uni($dbicon['path']); 1628 $dbicon['name'] = htmlspecialchars_uni($dbicon['name']); 1629 1630 if($icon == $dbicon['iid']) 1631 { 1632 $iconlist .= "<label><input type=\"radio\" name=\"icon\" value=\"".$dbicon['iid']."\" checked=\"checked\" /> <img src=\"".$dbicon['path']."\" alt=\"".$dbicon['name']."\" /></label>"; 1633 $no_icons_checked = ""; 1634 } 1635 else 1636 { 1637 $iconlist .= "<label><input type=\"radio\" name=\"icon\" value=\"".$dbicon['iid']."\" /> <img src=\"".$dbicon['path']."\" alt=\"".$dbicon['name']."\" /></label>"; 1638 } 1639 1640 ++$listed; 1641 if($listed == 10) 1642 { 1643 $iconlist .= "<br />"; 1644 $listed = 0; 1645 } 1646 } 1647 1648 eval("\$posticons = \"".$templates->get("posticons")."\";"); 1649 1650 return $posticons; 1651 } 1652 1653 /** 1654 * MyBB setcookie() wrapper. 1655 * 1656 * @param string The cookie identifier. 1657 * @param string The cookie value. 1658 * @param int The timestamp of the expiry date. 1659 * @param boolean True if setting a HttpOnly cookie (supported by IE, Opera 9, Konqueror) 1660 */ 1661 function my_setcookie($name, $value="", $expires="", $httponly=false) 1662 { 1663 global $mybb; 1664 1665 if(!$mybb->settings['cookiepath']) 1666 { 1667 $mybb->settings['cookiepath'] = "/"; 1668 } 1669 1670 if($expires == -1) 1671 { 1672 $expires = 0; 1673 } 1674 elseif($expires == "" || $expires == null) 1675 { 1676 $expires = TIME_NOW + (60*60*24*365); // Make the cookie expire in a years time 1677 } 1678 else 1679 { 1680 $expires = TIME_NOW + intval($expires); 1681 } 1682 1683 $mybb->settings['cookiepath'] = str_replace(array("\n","\r"), "", $mybb->settings['cookiepath']); 1684 $mybb->settings['cookiedomain'] = str_replace(array("\n","\r"), "", $mybb->settings['cookiedomain']); 1685 $mybb->settings['cookieprefix'] = str_replace(array("\n","\r", " "), "", $mybb->settings['cookieprefix']); 1686 1687 // Versions of PHP prior to 5.2 do not support HttpOnly cookies and IE is buggy when specifying a blank domain so set the cookie manually 1688 $cookie = "Set-Cookie: {$mybb->settings['cookieprefix']}{$name}=".urlencode($value); 1689 1690 if($expires > 0) 1691 { 1692 $cookie .= "; expires=".@gmdate('D, d-M-Y H:i:s \\G\\M\\T', $expires); 1693 } 1694 1695 if(!empty($mybb->settings['cookiepath'])) 1696 { 1697 $cookie .= "; path={$mybb->settings['cookiepath']}"; 1698 } 1699 1700 if(!empty($mybb->settings['cookiedomain'])) 1701 { 1702 $cookie .= "; domain={$mybb->settings['cookiedomain']}"; 1703 } 1704 1705 if($httponly == true) 1706 { 1707 $cookie .= "; HttpOnly"; 1708 } 1709 1710 $mybb->cookies[$name] = $value; 1711 1712 header($cookie, false); 1713 } 1714 1715 /** 1716 * Unset a cookie set by MyBB. 1717 * 1718 * @param string The cookie identifier. 1719 */ 1720 function my_unsetcookie($name) 1721 { 1722 global $mybb; 1723 1724 $expires = -3600; 1725 my_setcookie($name, "", $expires); 1726 1727 unset($mybb->cookies[$name]); 1728 } 1729 1730 /** 1731 * Get the contents from a serialised cookie array. 1732 * 1733 * @param string The cookie identifier. 1734 * @param int The cookie content id. 1735 * @return array|boolean The cookie id's content array or false when non-existent. 1736 */ 1737 function my_get_array_cookie($name, $id) 1738 { 1739 global $mybb; 1740 1741 if(!isset($mybb->cookies['mybb'][$name])) 1742 { 1743 return false; 1744 } 1745 1746 $cookie = my_unserialize($mybb->cookies['mybb'][$name]); 1747 1748 if(is_array($cookie) && isset($cookie[$id])) 1749 { 1750 return $cookie[$id]; 1751 } 1752 else 1753 { 1754 return 0; 1755 } 1756 } 1757 1758 /** 1759 * Set a serialised cookie array. 1760 * 1761 * @param string The cookie identifier. 1762 * @param int The cookie content id. 1763 * @param string The value to set the cookie to. 1764 */ 1765 function my_set_array_cookie($name, $id, $value, $expires="") 1766 { 1767 global $mybb; 1768 1769 $cookie = $mybb->cookies['mybb']; 1770 $newcookie = my_unserialize($cookie[$name]); 1771 1772 $newcookie[$id] = $value; 1773 $newcookie = serialize($newcookie); 1774 my_setcookie("mybb[$name]", addslashes($newcookie), $expires); 1775 1776 // Make sure our current viarables are up-to-date as well 1777 $mybb->cookies['mybb'][$name] = $newcookie; 1778 } 1779 1780 /** 1781 * Verifies that data passed is an array 1782 * 1783 * @param array Data to unserialize 1784 * @return array Unserialized data array 1785 */ 1786 function my_unserialize($data) 1787 { 1788 $array = unserialize($data); 1789 1790 if(!is_array($array)) 1791 { 1792 $array = array(); 1793 } 1794 1795 return $array; 1796 } 1797 1798 /** 1799 * Returns the serverload of the system. 1800 * 1801 * @return int The serverload of the system. 1802 */ 1803 function get_server_load() 1804 { 1805 global $lang; 1806 1807 $serverload = array(); 1808 1809 // DIRECTORY_SEPARATOR checks if running windows 1810 if(DIRECTORY_SEPARATOR != '\\') 1811 { 1812 if(function_exists("sys_getloadavg")) 1813 { 1814 // sys_getloadavg() will return an array with [0] being load within the last minute. 1815 $serverload = sys_getloadavg(); 1816 $serverload[0] = round($serverload[0], 4); 1817 } 1818 else if(@file_exists("/proc/loadavg") && $load = @file_get_contents("/proc/loadavg")) 1819 { 1820 $serverload = explode(" ", $load); 1821 $serverload[0] = round($serverload[0], 4); 1822 } 1823 if(!is_numeric($serverload[0])) 1824 { 1825 if(@ini_get('safe_mode') == 'On') 1826 { 1827 return $lang->unknown; 1828 } 1829 1830 // Suhosin likes to throw a warning if exec is disabled then die - weird 1831 if($func_blacklist = @ini_get('suhosin.executor.func.blacklist')) 1832 { 1833 if(strpos(",".$func_blacklist.",", 'exec') !== false) 1834 { 1835 return $lang->unknown; 1836 } 1837 } 1838 // PHP disabled functions? 1839 if($func_blacklist = @ini_get('disable_functions')) 1840 { 1841 if(strpos(",".$func_blacklist.",", 'exec') !== false) 1842 { 1843 return $lang->unknown; 1844 } 1845 } 1846 1847 $load = @exec("uptime"); 1848 $load = explode("load average: ", $load); 1849 $serverload = explode(",", $load[1]); 1850 if(!is_array($serverload)) 1851 { 1852 return $lang->unknown; 1853 } 1854 } 1855 } 1856 else 1857 { 1858 return $lang->unknown; 1859 } 1860 1861 $returnload = trim($serverload[0]); 1862 1863 return $returnload; 1864 } 1865 1866 /** 1867 * Returns the amount of memory allocated to the script. 1868 * 1869 * @return int The amount of memory allocated to the script. 1870 */ 1871 function get_memory_usage() 1872 { 1873 if(function_exists('memory_get_peak_usage')) 1874 { 1875 return memory_get_peak_usage(true); 1876 } 1877 elseif(function_exists('memory_get_usage')) 1878 { 1879 return memory_get_usage(true); 1880 } 1881 return false; 1882 } 1883 1884 /** 1885 * Updates the forum statistics with specific values (or addition/subtraction of the previous value) 1886 * 1887 * @param array Array of items being updated (numthreads,numposts,numusers) 1888 */ 1889 function update_stats($changes=array()) 1890 { 1891 global $cache, $db; 1892 1893 $stats = $cache->read("stats"); 1894 1895 $counters = array('numthreads','numunapprovedthreads','numposts','numunapprovedposts','numusers'); 1896 $update = array(); 1897 foreach($counters as $counter) 1898 { 1899 if(array_key_exists($counter, $changes)) 1900 { 1901 // Adding or subtracting from previous value? 1902 if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") 1903 { 1904 if(intval($changes[$counter]) != 0) 1905 { 1906 $new_stats[$counter] = $stats[$counter] + $changes[$counter]; 1907 } 1908 } 1909 else 1910 { 1911 $new_stats[$counter] = $changes[$counter]; 1912 } 1913 // Less than 0? That's bad 1914 if($new_stats[$counter] < 0) 1915 { 1916 $new_stats[$counter] = 0; 1917 } 1918 } 1919 } 1920 1921 // Fetch latest user if the user count is changing 1922 if(array_key_exists('numusers', $changes)) 1923 { 1924 $query = $db->simple_select("users", "uid, username", "", array('order_by' => 'regdate', 'order_dir' => 'DESC', 'limit' => 1)); 1925 $lastmember = $db->fetch_array($query); 1926 $new_stats['lastuid'] = $lastmember['uid']; 1927 $new_stats['lastusername'] = $lastmember['username']; 1928 } 1929 1930 if(empty($new_stats)) 1931 { 1932 return; 1933 } 1934 1935 if(is_array($stats)) 1936 { 1937 $stats = array_merge($stats, $new_stats); 1938 } 1939 else 1940 { 1941 $stats = $new_stats; 1942 } 1943 1944 // Update stats row for today in the database 1945 $todays_stats = array( 1946 "dateline" => mktime(0, 0, 0, date("m"), date("j"), date("Y")), 1947 "numusers" => $stats['numusers'], 1948 "numthreads" => $stats['numthreads'], 1949 "numposts" => $stats['numposts'] 1950 ); 1951 $db->replace_query("stats", $todays_stats, "dateline"); 1952 1953 $cache->update("stats", $stats, "dateline"); 1954 } 1955 1956 /** 1957 * Updates the forum counters with a specific value (or addition/subtraction of the previous value) 1958 * 1959 * @param int The forum ID 1960 * @param array Array of items being updated (threads, posts, unapprovedthreads, unapprovedposts) and their value (ex, 1, +1, -1) 1961 */ 1962 function update_forum_counters($fid, $changes=array()) 1963 { 1964 global $db, $cache; 1965 1966 $update_query = array(); 1967 1968 $counters = array('threads','unapprovedthreads','posts','unapprovedposts'); 1969 1970 // Fetch above counters for this forum 1971 $query = $db->simple_select("forums", implode(",", $counters), "fid='{$fid}'"); 1972 $forum = $db->fetch_array($query); 1973 1974 foreach($counters as $counter) 1975 { 1976 if(array_key_exists($counter, $changes)) 1977 { 1978 // Adding or subtracting from previous value? 1979 if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") 1980 { 1981 $update_query[$counter] = $forum[$counter] + $changes[$counter]; 1982 } 1983 else 1984 { 1985 $update_query[$counter] = $changes[$counter]; 1986 } 1987 1988 // Less than 0? That's bad 1989 if(!$update_query[$counter]) 1990 { 1991 $update_query[$counter] = 0; 1992 } 1993 } 1994 } 1995 1996 // Only update if we're actually doing something 1997 if(count($update_query) > 0) 1998 { 1999 $db->update_query("forums", $update_query, "fid='".intval($fid)."'"); 2000 } 2001 2002 // Guess we should update the statistics too? 2003 if(isset($update_query['threads']) || isset($update_query['posts']) || isset($update_query['unapprovedthreads']) || isset($update_query['unapprovedposts'])) 2004 { 2005 $new_stats = array(); 2006 if(array_key_exists('threads', $update_query)) 2007 { 2008 $threads_diff = $update_query['threads'] - $forum['threads']; 2009 if($threads_diff > -1) 2010 { 2011 $new_stats['numthreads'] = "+{$threads_diff}"; 2012 } 2013 else 2014 { 2015 $new_stats['numthreads'] = "{$threads_diff}"; 2016 } 2017 } 2018 2019 if(array_key_exists('unapprovedthreads', $update_query)) 2020 { 2021 $unapprovedthreads_diff = $update_query['unapprovedthreads'] - $forum['unapprovedthreads']; 2022 if($unapprovedthreads_diff > -1) 2023 { 2024 $new_stats['numunapprovedthreads'] = "+{$unapprovedthreads_diff}"; 2025 } 2026 else 2027 { 2028 $new_stats['numunapprovedthreads'] = "{$unapprovedthreads_diff}"; 2029 } 2030 } 2031 2032 if(array_key_exists('posts', $update_query)) 2033 { 2034 $posts_diff = $update_query['posts'] - $forum['posts']; 2035 if($posts_diff > -1) 2036 { 2037 $new_stats['numposts'] = "+{$posts_diff}"; 2038 } 2039 else 2040 { 2041 $new_stats['numposts'] = "{$posts_diff}"; 2042 } 2043 } 2044 2045 if(array_key_exists('unapprovedposts', $update_query)) 2046 { 2047 $unapprovedposts_diff = $update_query['unapprovedposts'] - $forum['unapprovedposts']; 2048 if($unapprovedposts_diff > -1) 2049 { 2050 $new_stats['numunapprovedposts'] = "+{$unapprovedposts_diff}"; 2051 } 2052 else 2053 { 2054 $new_stats['numunapprovedposts'] = "{$unapprovedposts_diff}"; 2055 } 2056 } 2057 update_stats($new_stats); 2058 } 2059 2060 // Update last post info 2061 update_forum_lastpost($fid); 2062 2063 $cache->update_forums(); 2064 } 2065 2066 /** 2067 * Update the last post information for a specific forum 2068 * 2069 * @param int The forum ID 2070 */ 2071 function update_forum_lastpost($fid) 2072 { 2073 global $db; 2074 2075 // Fetch the last post for this forum 2076 $query = $db->query(" 2077 SELECT tid, lastpost, lastposter, lastposteruid, subject 2078 FROM ".TABLE_PREFIX."threads 2079 WHERE fid='{$fid}' AND visible='1' AND closed NOT LIKE 'moved|%' 2080 ORDER BY lastpost DESC 2081 LIMIT 0, 1 2082 "); 2083 $lastpost = $db->fetch_array($query); 2084 2085 $updated_forum = array( 2086 "lastpost" => intval($lastpost['lastpost']), 2087 "lastposter" => $db->escape_string($lastpost['lastposter']), 2088 "lastposteruid" => intval($lastpost['lastposteruid']), 2089 "lastposttid" => intval($lastpost['tid']), 2090 "lastpostsubject" => $db->escape_string($lastpost['subject']) 2091 ); 2092 2093 $db->update_query("forums", $updated_forum, "fid='{$fid}'"); 2094 } 2095 2096 /** 2097 * Updates the thread counters with a specific value (or addition/subtraction of the previous value) 2098 * 2099 * @param int The thread ID 2100 * @param array Array of items being updated (replies, unapprovedposts, attachmentcount) and their value (ex, 1, +1, -1) 2101 */ 2102 function update_thread_counters($tid, $changes=array()) 2103 { 2104 global $db; 2105 2106 $update_query = array(); 2107 2108 $counters = array('replies','unapprovedposts','attachmentcount', 'attachmentcount'); 2109 2110 // Fetch above counters for this thread 2111 $query = $db->simple_select("threads", implode(",", $counters), "tid='{$tid}'"); 2112 $thread = $db->fetch_array($query); 2113 2114 foreach($counters as $counter) 2115 { 2116 if(array_key_exists($counter, $changes)) 2117 { 2118 // Adding or subtracting from previous value? 2119 if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") 2120 { 2121 $update_query[$counter] = $thread[$counter] + $changes[$counter]; 2122 } 2123 else 2124 { 2125 $update_query[$counter] = $changes[$counter]; 2126 } 2127 2128 // Less than 0? That's bad 2129 if($update_query[$counter] < 0) 2130 { 2131 $update_query[$counter] = 0; 2132 } 2133 } 2134 } 2135 2136 $db->free_result($query); 2137 2138 // Only update if we're actually doing something 2139 if(count($update_query) > 0) 2140 { 2141 $db->update_query("threads", $update_query, "tid='".intval($tid)."'"); 2142 } 2143 2144 unset($update_query, $thread); 2145 2146 update_thread_data($tid); 2147 } 2148 2149 /** 2150 * Update the first post and lastpost data for a specific thread 2151 * 2152 * @param int The thread ID 2153 */ 2154 function update_thread_data($tid) 2155 { 2156 global $db; 2157 2158 $thread = get_thread($tid); 2159 2160 // If this is a moved thread marker, don't update it - we need it to stay as it is 2161 if(strpos($thread['closed'], 'moved|') !== false) 2162 { 2163 return false; 2164 } 2165 2166 $query = $db->query(" 2167 SELECT u.uid, u.username, p.username AS postusername, p.dateline 2168 FROM ".TABLE_PREFIX."posts p 2169 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 2170 WHERE p.tid='$tid' AND p.visible='1' 2171 ORDER BY p.dateline DESC 2172 LIMIT 1" 2173 ); 2174 $lastpost = $db->fetch_array($query); 2175 2176 $db->free_result($query); 2177 2178 $query = $db->query(" 2179 SELECT u.uid, u.username, p.username AS postusername, p.dateline 2180 FROM ".TABLE_PREFIX."posts p 2181 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 2182 WHERE p.tid='$tid' 2183 ORDER BY p.dateline ASC 2184 LIMIT 1 2185 "); 2186 $firstpost = $db->fetch_array($query); 2187 2188 $db->free_result($query); 2189 2190 if(!$firstpost['username']) 2191 { 2192 $firstpost['username'] = $firstpost['postusername']; 2193 } 2194 2195 if(!$lastpost['username']) 2196 { 2197 $lastpost['username'] = $lastpost['postusername']; 2198 } 2199 2200 if(!$lastpost['dateline']) 2201 { 2202 $lastpost['username'] = $firstpost['username']; 2203 $lastpost['uid'] = $firstpost['uid']; 2204 $lastpost['dateline'] = $firstpost['dateline']; 2205 } 2206 2207 $lastpost['username'] = $db->escape_string($lastpost['username']); 2208 $firstpost['username'] = $db->escape_string($firstpost['username']); 2209 2210 $update_array = array( 2211 'username' => $firstpost['username'], 2212 'uid' => intval($firstpost['uid']), 2213 'dateline' => intval($firstpost['dateline']), 2214 'lastpost' => intval($lastpost['dateline']), 2215 'lastposter' => $lastpost['username'], 2216 'lastposteruid' => intval($lastpost['uid']), 2217 ); 2218 $db->update_query("threads", $update_array, "tid='{$tid}'"); 2219 2220 unset($firstpost, $lastpost, $update_array); 2221 } 2222 2223 function update_forum_count($fid) 2224 { 2225 die("Deprecated function call: update_forum_count"); 2226 } 2227 function update_thread_count($tid) 2228 { 2229 die("Deprecated function call: update_thread_count"); 2230 } 2231 function update_thread_attachment_count($tid) 2232 { 2233 die("Deprecated function call: update_thread_attachment_count"); 2234 } 2235 2236 /** 2237 * Deletes a thread from the database 2238 * 2239 * @param int The thread ID 2240 */ 2241 function delete_thread($tid) 2242 { 2243 global $moderation; 2244 2245 if(!is_object($moderation)) 2246 { 2247 require_once MYBB_ROOT."inc/class_moderation.php"; 2248 $moderation = new Moderation; 2249 } 2250 2251 return $moderation->delete_thread($tid); 2252 } 2253 2254 /** 2255 * Deletes a post from the database 2256 * 2257 * @param int The thread ID 2258 */ 2259 function delete_post($pid, $tid="") 2260 { 2261 global $moderation; 2262 2263 if(!is_object($moderation)) 2264 { 2265 require_once MYBB_ROOT."inc/class_moderation.php"; 2266 $moderation = new Moderation; 2267 } 2268 2269 return $moderation->delete_post($pid); 2270 } 2271 2272 /** 2273 * Builds a forum jump menu 2274 * 2275 * @param int The parent forum to start with 2276 * @param int The selected item ID 2277 * @param int If we need to add select boxes to this cal or not 2278 * @param int The current depth of forums we're at 2279 * @param int Whether or not to show extra items such as User CP, Forum home 2280 * @param boolean Ignore the showinjump setting and show all forums (for moderation pages) 2281 * @param array Array of permissions 2282 * @param string The name of the forum jump 2283 * @return string Forum jump items 2284 */ 2285 function build_forum_jump($pid="0", $selitem="", $addselect="1", $depth="", $showextras="1", $showall=false, $permissions="", $name="fid") 2286 { 2287 global $forum_cache, $jumpfcache, $permissioncache, $mybb, $selecteddone, $forumjump, $forumjumpbits, $gobutton, $theme, $templates, $lang; 2288 2289 $pid = intval($pid); 2290 $jumpsel['default'] = ''; 2291 2292 if($permissions) 2293 { 2294 $permissions = $mybb->usergroup; 2295 } 2296 2297 if(!is_array($jumpfcache)) 2298 { 2299 if(!is_array($forum_cache)) 2300 { 2301 cache_forums(); 2302 } 2303 2304 foreach($forum_cache as $fid => $forum) 2305 { 2306 if($forum['active'] != 0) 2307 { 2308 $jumpfcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; 2309 } 2310 } 2311 } 2312 2313 if(!is_array($permissioncache)) 2314 { 2315 $permissioncache = forum_permissions(); 2316 } 2317 2318 if(isset($jumpfcache[$pid]) && is_array($jumpfcache[$pid])) 2319 { 2320 foreach($jumpfcache[$pid] as $main) 2321 { 2322 foreach($main as $forum) 2323 { 2324 $perms = $permissioncache[$forum['fid']]; 2325 2326 if($forum['fid'] != "0" && ($perms['canview'] != 0 || $mybb->settings['hideprivateforums'] == 0) && $forum['linkto'] == '' && ($forum['showinjump'] != 0 || $showall == true)) 2327 { 2328 $optionselected = ""; 2329 2330 if($selitem == $forum['fid']) 2331 { 2332 $optionselected = "selected=\"selected\""; 2333 $selecteddone = 1; 2334 } 2335 2336 $forum['name'] = htmlspecialchars_uni(strip_tags($forum['name'])); 2337 2338 eval("\$forumjumpbits .= \"".$templates->get("forumjump_bit")."\";"); 2339 2340 if($forum_cache[$forum['fid']]) 2341 { 2342 $newdepth = $depth."--"; 2343 $forumjumpbits .= build_forum_jump($forum['fid'], $selitem, 0, $newdepth, $showextras, $showall); 2344 } 2345 } 2346 } 2347 } 2348 } 2349 2350 if($addselect) 2351 { 2352 if(!$selecteddone) 2353 { 2354 if(!$selitem) 2355 { 2356 $selitem = "default"; 2357 } 2358 2359 $jumpsel[$selitem] = 'selected="selected"'; 2360 } 2361 2362 if($showextras == 0) 2363 { 2364 $template = "special"; 2365 } 2366 else 2367 { 2368 $template = "advanced"; 2369 2370 if(strpos(FORUM_URL, '.html') !== false) 2371 { 2372 $forum_link = "'".str_replace('{fid}', "'+this.options[this.selectedIndex].value+'", FORUM_URL)."'"; 2373 } 2374 else 2375 { 2376 $forum_link = "'".str_replace('{fid}', "'+this.options[this.selectedIndex].value", FORUM_URL); 2377 } 2378 } 2379 2380 eval("\$forumjump = \"".$templates->get("forumjump_".$template)."\";"); 2381 } 2382 2383 return $forumjump; 2384 } 2385 2386 /** 2387 * Returns the extension of a file. 2388 * 2389 * @param string The filename. 2390 * @return string The extension of the file. 2391 */ 2392 function get_extension($file) 2393 { 2394 return my_strtolower(my_substr(strrchr($file, "."), 1)); 2395 } 2396 2397 /** 2398 * Generates a random string. 2399 * 2400 * @param int The length of the string to generate. 2401 * @return string The random string. 2402 */ 2403 function random_str($length="8") 2404 { 2405 $set = array("a","A","b","B","c","C","d","D","e","E","f","F","g","G","h","H","i","I","j","J","k","K","l","L","m","M","n","N","o","O","p","P","q","Q","r","R","s","S","t","T","u","U","v","V","w","W","x","X","y","Y","z","Z","1","2","3","4","5","6","7","8","9"); 2406 $str = ''; 2407 2408 for($i = 1; $i <= $length; ++$i) 2409 { 2410 $ch = my_rand(0, count($set)-1); 2411 $str .= $set[$ch]; 2412 } 2413 2414 return $str; 2415 } 2416 2417 /** 2418 * Formats a username based on their display group 2419 * 2420 * @param string The username 2421 * @param int The usergroup for the user (if not specified, will be fetched) 2422 * @param int The display group for the user (if not specified, will be fetched) 2423 * @return string The formatted username 2424 */ 2425 function format_name($username, $usergroup, $displaygroup="") 2426 { 2427 global $groupscache, $cache; 2428 2429 if(!is_array($groupscache)) 2430 { 2431 $groupscache = $cache->read("usergroups"); 2432 } 2433 2434 if($displaygroup != 0) 2435 { 2436 $usergroup = $displaygroup; 2437 } 2438 2439 $ugroup = $groupscache[$usergroup]; 2440 $format = $ugroup['namestyle']; 2441 $userin = substr_count($format, "{username}"); 2442 2443 if($userin == 0) 2444 { 2445 $format = "{username}"; 2446 } 2447 2448 $format = stripslashes($format); 2449 2450 return str_replace("{username}", $username, $format); 2451 } 2452 2453 /** 2454 * Build the javascript based MyCode inserter 2455 * 2456 * @return string The MyCode inserter 2457 */ 2458 function build_mycode_inserter($bind="message") 2459 { 2460 global $db, $mybb, $theme, $templates, $lang, $plugins; 2461 2462 if($mybb->settings['bbcodeinserter'] != 0) 2463 { 2464 $editor_lang_strings = array( 2465 "editor_title_bold", 2466 "editor_title_italic", 2467 "editor_title_underline", 2468 "editor_title_left", 2469 "editor_title_center", 2470 "editor_title_right", 2471 "editor_title_justify", 2472 "editor_title_numlist", 2473 "editor_title_bulletlist", 2474 "editor_title_image", 2475 "editor_title_hyperlink", 2476 "editor_title_email", 2477 "editor_title_quote", 2478 "editor_title_code", 2479 "editor_title_php", 2480 "editor_title_close_tags", 2481 "editor_enter_list_item", 2482 "editor_enter_url", 2483 "editor_enter_url_title", 2484 "editor_enter_email", 2485 "editor_enter_email_title", 2486 "editor_enter_image", 2487 "editor_enter_video_url", 2488 "editor_video_dailymotion", 2489 "editor_video_metacafe", 2490 "editor_video_myspacetv", 2491 "editor_video_vimeo", 2492 "editor_video_yahoo", 2493 "editor_video_youtube", 2494 "editor_size_xx_small", 2495 "editor_size_x_small", 2496 "editor_size_small", 2497 "editor_size_medium", 2498 "editor_size_large", 2499 "editor_size_x_large", 2500 "editor_size_xx_large", 2501 "editor_font", 2502 "editor_size", 2503 "editor_color" 2504 ); 2505 $editor_language = "var editor_language = {\n"; 2506 2507 $editor_lang_strings = $plugins->run_hooks("mycode_add_codebuttons", $editor_lang_strings); 2508 2509 foreach($editor_lang_strings as $key => $lang_string) 2510 { 2511 // Strip initial editor_ off language string if it exists - ensure case sensitivity does not matter. 2512 $js_lang_string = preg_replace("#^editor_#i", "", $lang_string); 2513 $string = str_replace("\"", "\\\"", $lang->$lang_string); 2514 $editor_language .= "\t{$js_lang_string}: \"{$string}\""; 2515 2516 if(isset($editor_lang_strings[$key+1])) 2517 { 2518 $editor_language .= ","; 2519 } 2520 2521 $editor_language .= "\n"; 2522 } 2523 2524 $editor_language .= "};"; 2525 2526 if(defined("IN_ADMINCP")) 2527 { 2528 global $page; 2529 $codeinsert = $page->build_codebuttons_editor($bind, $editor_language); 2530 } 2531 else 2532 { 2533 eval("\$codeinsert = \"".$templates->get("codebuttons")."\";"); 2534 } 2535 } 2536 2537 return $codeinsert; 2538 } 2539 2540 /** 2541 * Build the javascript clickable smilie inserter 2542 * 2543 * @return string The clickable smilies list 2544 */ 2545 function build_clickable_smilies() 2546 { 2547 global $cache, $smiliecache, $theme, $templates, $lang, $mybb, $smiliecount; 2548 2549 if($mybb->settings['smilieinserter'] != 0 && $mybb->settings['smilieinsertercols'] && $mybb->settings['smilieinsertertot']) 2550 { 2551 if(!$smiliecount) 2552 { 2553 $smilie_cache = $cache->read("smilies"); 2554 $smiliecount = count($smilie_cache); 2555 } 2556 2557 if(!$smiliecache) 2558 { 2559 if(!is_array($smilie_cache)) 2560 { 2561 $smilie_cache = $cache->read("smilies"); 2562 } 2563 foreach($smilie_cache as $smilie) 2564 { 2565 if($smilie['showclickable'] != 0) 2566 { 2567 $smiliecache[$smilie['find']] = $smilie['image']; 2568 } 2569 } 2570 } 2571 2572 unset($smilie); 2573 2574 if(is_array($smiliecache)) 2575 { 2576 reset($smiliecache); 2577 2578 $getmore = ''; 2579 if($mybb->settings['smilieinsertertot'] >= $smiliecount) 2580 { 2581 $mybb->settings['smilieinsertertot'] = $smiliecount; 2582 } 2583 else if($mybb->settings['smilieinsertertot'] < $smiliecount) 2584 { 2585 $smiliecount = $mybb->settings['smilieinsertertot']; 2586 eval("\$getmore = \"".$templates->get("smilieinsert_getmore")."\";"); 2587 } 2588 2589 $smilies = ""; 2590 $counter = 0; 2591 $i = 0; 2592 2593 foreach($smiliecache as $find => $image) 2594 { 2595 if($i < $mybb->settings['smilieinsertertot']) 2596 { 2597 if($counter == 0) 2598 { 2599 $smilies .= "<tr>\n"; 2600 } 2601 2602 $find = htmlspecialchars_uni($find); 2603 $smilies .= "<td style=\"text-align: center\"><img src=\"{$image}\" border=\"0\" class=\"smilie\" alt=\"{$find}\" /></td>\n"; 2604 ++$i; 2605 ++$counter; 2606 2607 if($counter == $mybb->settings['smilieinsertercols']) 2608 { 2609 $counter = 0; 2610 $smilies .= "</tr>\n"; 2611 } 2612 } 2613 } 2614 2615 if($counter != 0) 2616 { 2617 $colspan = $mybb->settings['smilieinsertercols'] - $counter; 2618 $smilies .= "<td colspan=\"{$colspan}\"> </td>\n</tr>\n"; 2619 } 2620 2621 eval("\$clickablesmilies = \"".$templates->get("smilieinsert")."\";"); 2622 } 2623 else 2624 { 2625 $clickablesmilies = ""; 2626 } 2627 } 2628 else 2629 { 2630 $clickablesmilies = ""; 2631 } 2632 2633 return $clickablesmilies; 2634 } 2635 2636 /** 2637 * Builds thread prefixes and returns a selected prefix (or all) 2638 * 2639 * @param int The prefix ID (0 to return all) 2640 * @return array The thread prefix's values (or all thread prefixes) 2641 */ 2642 function build_prefixes($pid=0) 2643 { 2644 global $cache; 2645 static $prefixes_cache; 2646 2647 if(is_array($prefixes_cache)) 2648 { 2649 if($pid > 0 && is_array($prefixes_cache[$pid])) 2650 { 2651 return $prefixes_cache[$pid]; 2652 } 2653 2654 return $prefixes_cache; 2655 } 2656 2657 $prefix_cache = $cache->read("threadprefixes"); 2658 2659 if(!is_array($prefix_cache)) 2660 { 2661 // No cache 2662 $prefix_cache = $cache->read("threadprefixes", true); 2663 2664 if(!is_array($prefix_cache)) 2665 { 2666 return array(); 2667 } 2668 } 2669 2670 $prefixes_cache = array(); 2671 foreach($prefix_cache as $prefix) 2672 { 2673 $prefixes_cache[$prefix['pid']] = $prefix; 2674 } 2675 2676 if($pid != 0 && is_array($prefixes_cache[$pid])) 2677 { 2678 return $prefixes_cache[$pid]; 2679 } 2680 else if(!empty($prefixes_cache)) 2681 { 2682 return $prefixes_cache; 2683 } 2684 2685 return false; 2686 } 2687 2688 /** 2689 * Build the thread prefix selection menu 2690 * 2691 * @param mixed The forum ID (integer ID or string all) 2692 * @param mixed The selected prefix ID (integer ID or string any) 2693 * @return string The thread prefix selection menu 2694 */ 2695 function build_prefix_select($fid, $selected_pid=0, $multiple=0) 2696 { 2697 global $cache, $db, $lang, $mybb; 2698 2699 if($fid != 'all') 2700 { 2701 $fid = intval($fid); 2702 } 2703 2704 $prefix_cache = build_prefixes(0); 2705 if(!$prefix_cache) 2706 { 2707 return false; // We've got no prefixes to show 2708 } 2709 2710 $groups = array($mybb->user['usergroup']); 2711 if($mybb->user['additionalgroups']) 2712 { 2713 $exp = explode(",", $mybb->user['additionalgroups']); 2714 2715 foreach($exp as $group) 2716 { 2717 $groups[] = $group; 2718 } 2719 } 2720 2721 // Go through each of our prefixes and decide which ones we can use 2722 $prefixes = array(); 2723 foreach($prefix_cache as $prefix) 2724 { 2725 if($fid != "all" && $prefix['forums'] != "-1") 2726 { 2727 // Decide whether this prefix can be used in our forum 2728 $forums = explode(",", $prefix['forums']); 2729 2730 if(!in_array($fid, $forums)) 2731 { 2732 // This prefix is not in our forum list 2733 continue; 2734 } 2735 } 2736 2737 if($prefix['groups'] != "-1") 2738 { 2739 $prefix_groups = explode(",", $prefix['groups']); 2740 2741 foreach($groups as $group) 2742 { 2743 if(in_array($group, $prefix_groups) && !isset($prefixes[$prefix['pid']])) 2744 { 2745 // Our group can use this prefix! 2746 $prefixes[$prefix['pid']] = $prefix; 2747 } 2748 } 2749 } 2750 else 2751 { 2752 // This prefix is for anybody to use... 2753 $prefixes[$prefix['pid']] = $prefix; 2754 } 2755 } 2756 2757 if(empty($prefixes)) 2758 { 2759 return false; 2760 } 2761 2762 $prefixselect = ""; 2763 $multipleselect = ""; 2764 if($multiple != 0) 2765 { 2766 $multipleselect = " multiple=\"multiple\" size=\"5\""; 2767 } 2768 2769 $prefixselect = "<select name=\"threadprefix\"{$multipleselect}>\n"; 2770 2771 if($multiple == 1) 2772 { 2773 $any_selected = ""; 2774 if($selected_pid == 'any') 2775 { 2776 $any_selected = " selected=\"selected\""; 2777 } 2778 2779 $prefixselect .= "<option value=\"any\"".$any_selected.">".$lang->any_prefix."</option>\n"; 2780 } 2781 2782 $default_selected = ""; 2783 if((intval($selected_pid) == 0) && $selected_pid != 'any') 2784 { 2785 $default_selected = " selected=\"selected\""; 2786 } 2787 2788 $prefixselect .= "<option value=\"0\"".$default_selected.">".$lang->no_prefix."</option>\n"; 2789 2790 foreach($prefixes as $prefix) 2791 { 2792 $selected = ""; 2793 if($prefix['pid'] == $selected_pid) 2794 { 2795 $selected = " selected=\"selected\""; 2796 } 2797 2798 $prefixselect .= "<option value=\"".$prefix['pid']."\"".$selected.">".htmlspecialchars_uni($prefix['prefix'])."</option>\n"; 2799 } 2800 2801 $prefixselect .= "</select>\n "; 2802 2803 return $prefixselect; 2804 } 2805 2806 /** 2807 * Gzip encodes text to a specified level 2808 * 2809 * @param string The string to encode 2810 * @param int The level (1-9) to encode at 2811 * @return string The encoded string 2812 */ 2813 function gzip_encode($contents, $level=1) 2814 { 2815 if(function_exists("gzcompress") && function_exists("crc32") && !headers_sent() && !(ini_get('output_buffering') && my_strpos(' '.ini_get('output_handler'), 'ob_gzhandler'))) 2816 { 2817 $httpaccept_encoding = ''; 2818 2819 if(isset($_SERVER['HTTP_ACCEPT_ENCODING'])) 2820 { 2821 $httpaccept_encoding = $_SERVER['HTTP_ACCEPT_ENCODING']; 2822 } 2823 2824 if(my_strpos(" ".$httpaccept_encoding, "x-gzip")) 2825 { 2826 $encoding = "x-gzip"; 2827 } 2828 2829 if(my_strpos(" ".$httpaccept_encoding, "gzip")) 2830 { 2831 $encoding = "gzip"; 2832 } 2833 2834 if(isset($encoding)) 2835 { 2836 header("Content-Encoding: $encoding"); 2837 2838 if(function_exists("gzencode")) 2839 { 2840 $contents = gzencode($contents, $level); 2841 } 2842 else 2843 { 2844 $size = strlen($contents); 2845 $crc = crc32($contents); 2846 $gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff"; 2847 $gzdata .= my_substr(gzcompress($contents, $level), 2, -4); 2848 $gzdata .= pack("V", $crc); 2849 $gzdata .= pack("V", $size); 2850 $contents = $gzdata; 2851 } 2852 } 2853 } 2854 2855 return $contents; 2856 } 2857 2858 /** 2859 * Log the actions of a moderator. 2860 * 2861 * @param array The data of the moderator's action. 2862 * @param string The message to enter for the action the moderator performed. 2863 */ 2864 function log_moderator_action($data, $action="") 2865 { 2866 global $mybb, $db, $session; 2867 2868 // If the fid or tid is not set, set it at 0 so MySQL doesn't choke on it. 2869 if($data['fid'] == '') 2870 { 2871 $fid = 0; 2872 } 2873 else 2874 { 2875 $fid = $data['fid']; 2876 unset($data['fid']); 2877 } 2878 2879 if($data['tid'] == '') 2880 { 2881 $tid = 0; 2882 } 2883 else 2884 { 2885 $tid = $data['tid']; 2886 unset($data['tid']); 2887 } 2888 2889 // Any remaining extra data - we serialize and insert in to its own column 2890 if(is_array($data)) 2891 { 2892 $data = serialize($data); 2893 } 2894 2895 $time = TIME_NOW; 2896 2897 $sql_array = array( 2898 "uid" => $mybb->user['uid'], 2899 "dateline" => $time, 2900 "fid" => $fid, 2901 "tid" => $tid, 2902 "action" => $db->escape_string($action), 2903 "data" => $db->escape_string($data), 2904 "ipaddress" => $db->escape_string($session->ipaddress) 2905 ); 2906 $db->insert_query("moderatorlog", $sql_array); 2907 } 2908 2909 /** 2910 * Get the formatted reputation for a user. 2911 * 2912 * @param int The reputation value 2913 * @param int The user ID (if not specified, the generated reputation will not be a link) 2914 * @return string The formatted repuation 2915 */ 2916 function get_reputation($reputation, $uid=0) 2917 { 2918 global $theme; 2919 2920 $display_reputation = ''; 2921 2922 if($uid != 0) 2923 { 2924 $display_reputation = "<a href=\"reputation.php?uid={$uid}\">"; 2925 } 2926 2927 $display_reputation .= "<strong class=\""; 2928 2929 if($reputation < 0) 2930 { 2931 $display_reputation .= "reputation_negative"; 2932 } 2933 elseif($reputation > 0) 2934 { 2935 $display_reputation .= "reputation_positive"; 2936 } 2937 else 2938 { 2939 $display_reputation .= "reputation_neutral"; 2940 } 2941 2942 $display_reputation .= "\">{$reputation}</strong>"; 2943 2944 if($uid != 0) 2945 { 2946 $display_reputation .= "</a>"; 2947 } 2948 2949 return $display_reputation; 2950 } 2951 2952 /** 2953 * Fetch a color coded version of a warning level (based on it's percentage) 2954 * 2955 * @param int The warning level (percentage of 100) 2956 * @return string Formatted warning level 2957 */ 2958 function get_colored_warning_level($level) 2959 { 2960 if($level >= 80) 2961 { 2962 return "<span class=\"high_warning\">{$level}%</span>"; 2963 } 2964 else if($level >= 50) 2965 { 2966 return "<span class=\"moderate_warning\">{$level}%</span>"; 2967 } 2968 else if($level >= 25) 2969 { 2970 return "<span class=\"low_warning\">{$level}%</span>"; 2971 } 2972 else 2973 { 2974 return $level."%"; 2975 } 2976 } 2977 2978 /** 2979 * Fetch the IP address of the current user. 2980 * 2981 * @return string The IP address. 2982 */ 2983 function get_ip() 2984 { 2985 global $mybb, $plugins; 2986 2987 $ip = 0; 2988 2989 if(!preg_match("#^(10|172\.16|192\.168)\.#", $_SERVER['REMOTE_ADDR'])) 2990 { 2991 $ip = $_SERVER['REMOTE_ADDR']; 2992 } 2993 2994 if($mybb->settings['ip_forwarded_check']) 2995 { 2996 if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) 2997 { 2998 preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_FORWARDED_FOR'], $addresses); 2999 } 3000 elseif(isset($_SERVER['HTTP_X_REAL_IP'])) 3001 { 3002 preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_REAL_IP'], $addresses); 3003 } 3004 3005 if(is_array($addresses[0])) 3006 { 3007 foreach($addresses[0] as $key => $val) 3008 { 3009 if(!preg_match("#^(10|172\.16|192\.168)\.#", $val)) 3010 { 3011 $ip = $val; 3012 break; 3013 } 3014 } 3015 } 3016 } 3017 3018 if(!$ip) 3019 { 3020 if(isset($_SERVER['HTTP_CLIENT_IP'])) 3021 { 3022 $ip = $_SERVER['HTTP_CLIENT_IP']; 3023 } 3024 } 3025 3026 if($plugins) 3027 { 3028 $ip_array = array("ip" => &$ip); // Used for backwards compatibility on this hook with the updated run_hooks() function. 3029 $plugins->run_hooks("get_ip", $ip_array); 3030 } 3031 3032 return $ip; 3033 } 3034 3035 /** 3036 * Fetch the friendly size (GB, MB, KB, B) for a specified file size. 3037 * 3038 * @param int The size in bytes 3039 * @return string The friendly file size 3040 */ 3041 function get_friendly_size($size) 3042 { 3043 global $lang; 3044 3045 if(!is_numeric($size)) 3046 { 3047 return $lang->na; 3048 } 3049 3050 // Yottabyte (1024 Zettabytes) 3051 if($size >= 1208925819614629174706176) 3052 { 3053 $size = my_number_format(round(($size / 1208925819614629174706176), 2))." ".$lang->size_yb; 3054 } 3055 // Zetabyte (1024 Exabytes) 3056 elseif($size >= 1180591620717411303424) 3057 { 3058 $size = my_number_format(round(($size / 1180591620717411303424), 2))." ".$lang->size_zb; 3059 } 3060 // Exabyte (1024 Petabytes) 3061 elseif($size >= 1152921504606846976) 3062 { 3063 $size = my_number_format(round(($size / 1152921504606846976), 2))." ".$lang->size_eb; 3064 } 3065 // Petabyte (1024 Terabytes) 3066 elseif($size >= 1125899906842624) 3067 { 3068 $size = my_number_format(round(($size / 1125899906842624), 2))." ".$lang->size_pb; 3069 } 3070 // Terabyte (1024 Gigabytes) 3071 elseif($size >= 1099511627776) 3072 { 3073 $size = my_number_format(round(($size / 1099511627776), 2))." ".$lang->size_tb; 3074 } 3075 // Gigabyte (1024 Megabytes) 3076 elseif($size >= 1073741824) 3077 { 3078 $size = my_number_format(round(($size / 1073741824), 2))." ".$lang->size_gb; 3079 } 3080 // Megabyte (1024 Kilobytes) 3081 elseif($size >= 1048576) 3082 { 3083 $size = my_number_format(round(($size / 1048576), 2))." ".$lang->size_mb; 3084 } 3085 // Kilobyte (1024 bytes) 3086 elseif($size >= 1024) 3087 { 3088 $size = my_number_format(round(($size / 1024), 2))." ".$lang->size_kb; 3089 } 3090 elseif($size == 0) 3091 { 3092 $size = "0 ".$lang->size_bytes; 3093 } 3094 else 3095 { 3096 $size = my_number_format($size)." ".$lang->size_bytes; 3097 } 3098 3099 return $size; 3100 } 3101 3102 /** 3103 * Get the attachment icon for a specific file extension 3104 * 3105 * @param string The file extension 3106 * @return string The attachment icon 3107 */ 3108 function get_attachment_icon($ext) 3109 { 3110 global $cache, $attachtypes, $theme; 3111 3112 if(!$attachtypes) 3113 { 3114 $attachtypes = $cache->read("attachtypes"); 3115 } 3116 3117 $ext = my_strtolower($ext); 3118 3119 if($attachtypes[$ext]['icon']) 3120 { 3121 if(defined("IN_ADMINCP")) 3122 { 3123 $icon = str_replace("{theme}", "", $attachtypes[$ext]['icon']); 3124 if(my_substr($icon, 0, 1) != "/" && my_substr($icon, 0, 7) != "http://") 3125 { 3126 $icon = "../".$icon; 3127 } 3128 } 3129 elseif(defined("IN_PORTAL")) 3130 { 3131 global $change_dir; 3132 $icon = $change_dir."/".str_replace("{theme}", $theme['imgdir'], $attachtypes[$ext]['icon']); 3133 } 3134 else 3135 { 3136 $icon = str_replace("{theme}", $theme['imgdir'], $attachtypes[$ext]['icon']); 3137 } 3138 return "<img src=\"{$icon}\" border=\"0\" alt=\".{$ext}\" />"; 3139 } 3140 else 3141 { 3142 if(defined("IN_ADMINCP")) 3143 { 3144 $theme['imgdir'] = "../images"; 3145 } 3146 else if(defined("IN_PORTAL")) 3147 { 3148 global $change_dir; 3149 $theme['imgdir'] = "{$change_dir}/images"; 3150 } 3151 3152 return "<img src=\"{$theme['imgdir']}/attachtypes/unknown.gif\" border=\"0\" alt=\".{$ext}\" />"; 3153 } 3154 } 3155 3156 /** 3157 * Get a list of the unviewable forums for the current user 3158 * 3159 * @param boolean Set to true to only fetch those forums for which users can actually read a thread in. 3160 * @return string Comma separated values list of the forum IDs which the user cannot view 3161 */ 3162 function get_unviewable_forums($only_readable_threads=false) 3163 { 3164 global $forum_cache, $permissioncache, $mybb, $unviewable, $templates, $forumpass; 3165 3166 if(!is_array($forum_cache)) 3167 { 3168 cache_forums(); 3169 } 3170 3171 if(!is_array($permissioncache)) 3172 { 3173 $permissioncache = forum_permissions(); 3174 } 3175 3176 $password_forums = array(); 3177 foreach($forum_cache as $fid => $forum) 3178 { 3179 if($permissioncache[$forum['fid']]) 3180 { 3181 $perms = $permissioncache[$forum['fid']]; 3182 } 3183 else 3184 { 3185 $perms = $mybb->usergroup; 3186 } 3187 3188 $pwverified = 1; 3189 3190 if($forum['password'] != "") 3191 { 3192 if($mybb->cookies['forumpass'][$forum['fid']] != md5($mybb->user['uid'].$forum['password'])) 3193 { 3194 $pwverified = 0; 3195 } 3196 3197 $password_forums[$forum['fid']] = $forum['password']; 3198 } 3199 else 3200 { 3201 // Check parents for passwords 3202 $parents = explode(",", $forum['parentlist']); 3203 foreach($parents as $parent) 3204 { 3205 if(isset($password_forums[$parent]) && $mybb->cookies['forumpass'][$parent] != md5($mybb->user['uid'].$password_forums[$parent])) 3206 { 3207 $pwverified = 0; 3208 } 3209 } 3210 } 3211 3212 if($perms['canview'] == 0 || $pwverified == 0 || ($only_readable_threads == true && $perms['canviewthreads'] == 0)) 3213 { 3214 if($unviewableforums) 3215 { 3216 $unviewableforums .= ","; 3217 } 3218 3219 $unviewableforums .= "'".$forum['fid']."'"; 3220 } 3221 } 3222 3223 if(isset($unviewableforums)) 3224 { 3225 return $unviewableforums; 3226 } 3227 } 3228 3229 /** 3230 * Fixes mktime for dates earlier than 1970 3231 * 3232 * @param string The date format to use 3233 * @param int The year of the date 3234 * @return string The correct date format 3235 */ 3236 function fix_mktime($format, $year) 3237 { 3238 // Our little work around for the date < 1970 thing. 3239 // -2 idea provided by Matt Light (http://www.mephex.com) 3240 $format = str_replace("Y", $year, $format); 3241 $format = str_replace("y", my_substr($year, -2), $format); 3242 3243 return $format; 3244 } 3245 3246 /** 3247 * Build the breadcrumb navigation trail from the specified items 3248 * 3249 * @return The formatted breadcrumb navigation trail 3250 */ 3251 function build_breadcrumb() 3252 { 3253 global $nav, $navbits, $templates, $theme, $lang, $mybb; 3254 3255 eval("\$navsep = \"".$templates->get("nav_sep")."\";"); 3256 3257 $i = 0; 3258 $activesep = ''; 3259 3260 if(is_array($navbits)) 3261 { 3262 reset($navbits); 3263 foreach($navbits as $key => $navbit) 3264 { 3265 if(isset($navbits[$key+1])) 3266 { 3267 if(isset($navbits[$key+2])) 3268 { 3269 $sep = $navsep; 3270 } 3271 else 3272 { 3273 $sep = ""; 3274 } 3275 3276 $multipage = null; 3277 $multipage_dropdown = null; 3278 if(!empty($navbit['multipage'])) 3279 { 3280 $multipage = multipage($navbit['multipage']['num_threads'], $mybb->settings['threadsperpage'], $navbit['multipage']['current_page'], $navbit['multipage']['url'], true); 3281 if($multipage) 3282 { 3283 ++$i; 3284 $multipage_dropdown = " <img src=\"{$theme['imgdir']}/arrow_down.gif\" alt=\"v\" title=\"\" class=\"pagination_breadcrumb_link\" id=\"breadcrumb_multipage\" />{$multipage}"; 3285 $sep = $multipage_dropdown.$sep; 3286 } 3287 } 3288 3289 // Replace page 1 URLs 3290 $navbit['url'] = str_replace("-page-1.html", ".html", $navbit['url']); 3291 $navbit['url'] = preg_replace("/&page=1$/", "", $navbit['url']); 3292 3293 eval("\$nav .= \"".$templates->get("nav_bit")."\";"); 3294 } 3295 } 3296 } 3297 3298 $navsize = count($navbits); 3299 $navbit = $navbits[$navsize-1]; 3300 3301 if($nav) 3302 { 3303 eval("\$activesep = \"".$templates->get("nav_sep_active")."\";"); 3304 } 3305 3306 eval("\$activebit = \"".$templates->get("nav_bit_active")."\";"); 3307 eval("\$donenav = \"".$templates->get("nav")."\";"); 3308 3309 return $donenav; 3310 } 3311 3312 /** 3313 * Add a breadcrumb menu item to the list. 3314 * 3315 * @param string The name of the item to add 3316 * @param string The URL of the item to add 3317 */ 3318 function add_breadcrumb($name, $url="") 3319 { 3320 global $navbits; 3321 3322 $navsize = count($navbits); 3323 $navbits[$navsize]['name'] = $name; 3324 $navbits[$navsize]['url'] = $url; 3325 } 3326 3327 /** 3328 * Build the forum breadcrumb nagiation (the navigation to a specific forum including all parent forums) 3329 * 3330 * @param int The forum ID to build the navigation for 3331 * @param array The multipage drop down array of information 3332 */ 3333 function build_forum_breadcrumb($fid, $multipage=array()) 3334 { 3335 global $pforumcache, $currentitem, $forum_cache, $navbits, $lang, $base_url, $archiveurl; 3336 3337 if(!$pforumcache) 3338 { 3339 if(!is_array($forum_cache)) 3340 { 3341 cache_forums(); 3342 } 3343 3344 foreach($forum_cache as $key => $val) 3345 { 3346 $pforumcache[$val['fid']][$val['pid']] = $val; 3347 } 3348 } 3349 3350 if(is_array($pforumcache[$fid])) 3351 { 3352 foreach($pforumcache[$fid] as $key => $forumnav) 3353 { 3354 if($fid == $forumnav['fid']) 3355 { 3356 if(!empty($pforumcache[$forumnav['pid']])) 3357 { 3358 build_forum_breadcrumb($forumnav['pid']); 3359 } 3360 3361 $navsize = count($navbits); 3362 // Convert & to & 3363 $navbits[$navsize]['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forumnav['name']); 3364 3365 if(defined("IN_ARCHIVE")) 3366 { 3367 // Set up link to forum in breadcrumb. 3368 if($pforumcache[$fid][$forumnav['pid']]['type'] == 'f' || $pforumcache[$fid][$forumnav['pid']]['type'] == 'c') 3369 { 3370 $navbits[$navsize]['url'] = "{$base_url}forum-".$forumnav['fid'].".html"; 3371 } 3372 else 3373 { 3374 $navbits[$navsize]['url'] = $archiveurl."/index.php"; 3375 } 3376 } 3377 elseif(!empty($multipage)) 3378 { 3379 $navbits[$navsize]['url'] = get_forum_link($forumnav['fid'], $multipage['current_page']); 3380 3381 $navbits[$navsize]['multipage'] = $multipage; 3382 $navbits[$navsize]['multipage']['url'] = str_replace('{fid}', $forumnav['fid'], FORUM_URL_PAGED); 3383 } 3384 else 3385 { 3386 $navbits[$navsize]['url'] = get_forum_link($forumnav['fid']); 3387 } 3388 } 3389 } 3390 } 3391 3392 return 1; 3393 } 3394 3395 /** 3396 * Resets the breadcrumb navigation to the first item, and clears the rest 3397 */ 3398 function reset_breadcrumb() 3399 { 3400 global $navbits; 3401 3402 $newnav[0]['name'] = $navbits[0]['name']; 3403 $newnav[0]['url'] = $navbits[0]['url']; 3404 $newnav[0]['options'] = $navbits[0]['options']; 3405 3406 unset($GLOBALS['navbits']); 3407 $GLOBALS['navbits'] = $newnav; 3408 } 3409 3410 /** 3411 * Builds a URL to an archive mode page 3412 * 3413 * @param string The type of page (thread|announcement|forum) 3414 * @param int The ID of the item 3415 * @return string The URL 3416 */ 3417 function build_archive_link($type, $id="") 3418 { 3419 global $mybb; 3420 3421 // If the server OS is not Windows and not Apache or the PHP is running as a CGI or we have defined ARCHIVE_QUERY_STRINGS, use query strings - DIRECTORY_SEPARATOR checks if running windows 3422 //if((DIRECTORY_SEPARATOR == '\\' && is_numeric(stripos($_SERVER['SERVER_SOFTWARE'], "apache")) == false) || is_numeric(stripos(SAPI_NAME, "cgi")) !== false || defined("ARCHIVE_QUERY_STRINGS")) 3423 if($mybb->settings['seourls_archive'] == 1) 3424 { 3425 $base_url = $mybb->settings['bburl']."/archive/index.php/"; 3426 } 3427 else 3428 { 3429 $base_url = $mybb->settings['bburl']."/archive/index.php?"; 3430 } 3431 3432 switch($type) 3433 { 3434 case "thread": 3435 $url = "{$base_url}thread-{$id}.html"; 3436 break; 3437 case "announcement": 3438 $url = "{$base_url}announcement-{$id}.html"; 3439 break; 3440 case "forum": 3441 $url = "{$base_url}forum-{$id}.html"; 3442 break; 3443 default: 3444 $url = $mybb->settings['bburl']."/archive/index.php"; 3445 } 3446 3447 return $url; 3448 } 3449 3450 /** 3451 * Prints a debug information page 3452 */ 3453 function debug_page() 3454 { 3455 global $db, $debug, $templates, $templatelist, $mybb, $maintimer, $globaltime, $ptimer, $parsetime, $lang; 3456 3457 $totaltime = $maintimer->totaltime; 3458 $phptime = $maintimer->format($maintimer->totaltime - $db->query_time); 3459 $query_time = $maintimer->format($db->query_time); 3460 3461 $percentphp = number_format((($phptime/$maintimer->totaltime)*100), 2); 3462 $percentsql = number_format((($query_time/$maintimer->totaltime)*100), 2); 3463 3464 $phpversion = PHP_VERSION; 3465 3466 $serverload = get_server_load(); 3467 3468 if($mybb->settings['gzipoutput'] != 0) 3469 { 3470 $gzipen = "Enabled"; 3471 } 3472 else 3473 { 3474 $gzipen = "Disabled"; 3475 } 3476 3477 echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 3478 echo "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; 3479 echo "<head>"; 3480 echo "<title>MyBB Debug Information</title>"; 3481 echo "</head>"; 3482 echo "<body>"; 3483 echo "<h1>MyBB Debug Information</h1>\n"; 3484 echo "<h2>Page Generation</h2>\n"; 3485 echo "<table bgcolor=\"#666666\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n"; 3486 echo "<tr>\n"; 3487 echo "<td bgcolor=\"#CCCCCC\" colspan=\"4\"><b><span style=\"size:2;\">Page Generation Statistics</span></b></td>\n"; 3488 echo "</tr>\n"; 3489 echo "<tr>\n"; 3490 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Page Generation Time:</font></b></td>\n"; 3491 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$totaltime seconds</font></td>\n"; 3492 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">No. DB Queries:</font></b></td>\n"; 3493 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$db->query_count</font></td>\n"; 3494 echo "</tr>\n"; 3495 echo "<tr>\n"; 3496 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">PHP Processing Time:</font></b></td>\n"; 3497 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$phptime seconds ($percentphp%)</font></td>\n"; 3498 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">DB Processing Time:</font></b></td>\n"; 3499 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$query_time seconds ($percentsql%)</font></td>\n"; 3500 echo "</tr>\n"; 3501 echo "<tr>\n"; 3502 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Extensions Used:</font></b></td>\n"; 3503 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">{$mybb->config['database']['type']}, xml</font></td>\n"; 3504 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Global.php Processing Time:</font></b></td>\n"; 3505 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$globaltime seconds</font></td>\n"; 3506 echo "</tr>\n"; 3507 echo "<tr>\n"; 3508 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">PHP Version:</font></b></td>\n"; 3509 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$phpversion</font></td>\n"; 3510 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Server Load:</font></b></td>\n"; 3511 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$serverload</font></td>\n"; 3512 echo "</tr>\n"; 3513 echo "<tr>\n"; 3514 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">GZip Encoding Status:</font></b></td>\n"; 3515 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">$gzipen</font></td>\n"; 3516 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">No. Templates Used:</font></b></td>\n"; 3517 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">".count($templates->cache)." (".intval(count(explode(",", $templatelist)))." Cached / ".intval(count($templates->uncached_templates))." Manually Loaded)</font></td>\n"; 3518 echo "</tr>\n"; 3519 3520 $memory_usage = get_memory_usage(); 3521 if(!$memory_usage) 3522 { 3523 $memory_usage = $lang->unknown; 3524 } 3525 else 3526 { 3527 $memory_usage = get_friendly_size($memory_usage)." ({$memory_usage} bytes)"; 3528 } 3529 $memory_limit = @ini_get("memory_limit"); 3530 echo "<tr>\n"; 3531 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Memory Usage:</font></b></td>\n"; 3532 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">{$memory_usage}</font></td>\n"; 3533 echo "<td bgcolor=\"#EFEFEF\" width=\"25%\"><b><font face=\"Tahoma\" size=\"2\">Memory Limit:</font></b></td>\n"; 3534 echo "<td bgcolor=\"#FEFEFE\" width=\"25%\"><font face=\"Tahoma\" size=\"2\">{$memory_limit}</font></td>\n"; 3535 echo "</tr>\n"; 3536 3537 echo "</table>\n"; 3538 3539 echo "<h2>Database Connections (".count($db->connections)." Total) </h2>\n"; 3540 echo "<table style=\"background-color: #666;\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n"; 3541 echo "<tr>\n"; 3542 echo "<td style=\"background: #fff;\">".implode("<br />", $db->connections)."</td>\n"; 3543 echo "</tr>\n"; 3544 echo "</table>\n"; 3545 echo "<br />\n"; 3546 3547 echo "<h2>Database Queries (".$db->query_count." Total) </h2>\n"; 3548 echo $db->explain; 3549 echo "<h2>Template Statistics</h2>\n"; 3550 3551 if(count($templates->cache) > 0) 3552 { 3553 echo "<table style=\"background-color: #666;\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n"; 3554 echo "<tr>\n"; 3555 echo "<td style=\"background-color: #ccc;\"><strong>Templates Used (Loaded for this Page) - ".count($templates->cache)." Total</strong></td>\n"; 3556 echo "</tr>\n"; 3557 echo "<tr>\n"; 3558 echo "<td style=\"background: #fff;\">".implode(", ", array_keys($templates->cache))."</td>\n"; 3559 echo "</tr>\n"; 3560 echo "</table>\n"; 3561 echo "<br />\n"; 3562 } 3563 3564 if(count($templates->uncached_templates) > 0) 3565 { 3566 echo "<table style=\"background-color: #666;\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n"; 3567 echo "<tr>\n"; 3568 echo "<td style=\"background-color: #ccc;\"><strong>Templates Requiring Additional Calls (Not Cached at Startup) - ".count($templates->uncached_templates)." Total</strong></td>\n"; 3569 echo "</tr>\n"; 3570 echo "<tr>\n"; 3571 echo "<td style=\"background: #fff;\">".implode(", ", $templates->uncached_templates)."</td>\n"; 3572 echo "</tr>\n"; 3573 echo "</table>\n"; 3574 echo "<br />\n"; 3575 } 3576 echo "</body>"; 3577 echo "</html>"; 3578 exit; 3579 } 3580 3581 /** 3582 * Outputs the correct page headers. 3583 */ 3584 function send_page_headers() 3585 { 3586 global $mybb; 3587 3588 if($mybb->settings['nocacheheaders'] == 1) 3589 { 3590 header("Expires: Sat, 1 Jan 2000 01:00:00 GMT"); 3591 header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); 3592 header("Cache-Control: no-cache, must-revalidate"); 3593 header("Pragma: no-cache"); 3594 } 3595 } 3596 3597 /** 3598 * Mark specific reported posts of a certain type as dealt with 3599 * 3600 * @param mixed An array or int of the ID numbers you're marking as dealt with 3601 * @param string The type of item the above IDs are for - post, posts, thread, threads, forum, all 3602 */ 3603 function mark_reports($id, $type="post") 3604 { 3605 global $db, $cache, $plugins; 3606 3607 switch($type) 3608 { 3609 case "posts": 3610 if(is_array($id)) 3611 { 3612 $rids = implode($id, "','"); 3613 $rids = "'0','$rids'"; 3614 $db->update_query("reportedposts", array('reportstatus' => 1), "pid IN($rids) AND reportstatus='0'"); 3615 } 3616 break; 3617 case "post": 3618 $db->update_query("reportedposts", array('reportstatus' => 1), "pid='$id' AND reportstatus='0'"); 3619 break; 3620 case "threads": 3621 if(is_array($id)) 3622 { 3623 $rids = implode($id, "','"); 3624 $rids = "'0','$rids'"; 3625 $db->update_query("reportedposts", array('reportstatus' => 1), "tid IN($rids) AND reportstatus='0'"); 3626 } 3627 break; 3628 case "thread": 3629 $db->update_query("reportedposts", array('reportstatus' => 1), "tid='$id' AND reportstatus='0'"); 3630 break; 3631 case "forum": 3632 $db->update_query("reportedposts", array('reportstatus' => 1), "fid='$id' AND reportstatus='0'"); 3633 break; 3634 case "all": 3635 $db->update_query("reportedposts", array('reportstatus' => 1), "reportstatus='0'"); 3636 break; 3637 } 3638 3639 $arguments = array('id' => $id, 'type' => $type); 3640 $plugins->run_hooks("mark_reports", $arguments); 3641 $cache->update_reportedposts(); 3642 } 3643 3644 /** 3645 * Fetch a friendly x days, y months etc date stamp from a timestamp 3646 * 3647 * @param int The timestamp 3648 * @param array Array of options 3649 * @return string The friendly formatted timestamp 3650 */ 3651 function nice_time($stamp, $options=array()) 3652 { 3653 global $lang; 3654 3655 $ysecs = 365*24*60*60; 3656 $mosecs = 31*24*60*60; 3657 $wsecs = 7*24*60*60; 3658 $dsecs = 24*60*60; 3659 $hsecs = 60*60; 3660 $msecs = 60; 3661 3662 if(isset($options['short'])) 3663 { 3664 $lang_year = $lang->year_short; 3665 $lang_years = $lang->years_short; 3666 $lang_month = $lang->month_short; 3667 $lang_months = $lang->months_short; 3668 $lang_week = $lang->week_short; 3669 $lang_weeks = $lang->weeks_short; 3670 $lang_day = $lang->day_short; 3671 $lang_days = $lang->days_short; 3672 $lang_hour = $lang->hour_short; 3673 $lang_hours = $lang->hours_short; 3674 $lang_minute = $lang->minute_short; 3675 $lang_minutes = $lang->minutes_short; 3676 $lang_second = $lang->second_short; 3677 $lang_seconds = $lang->seconds_short; 3678 } 3679 else 3680 { 3681 $lang_year = " ".$lang->year; 3682 $lang_years = " ".$lang->years; 3683 $lang_month = " ".$lang->month; 3684 $lang_months = " ".$lang->months; 3685 $lang_week = " ".$lang->week; 3686 $lang_weeks = " ".$lang->weeks; 3687 $lang_day = " ".$lang->day; 3688 $lang_days = " ".$lang->days; 3689 $lang_hour = " ".$lang->hour; 3690 $lang_hours = " ".$lang->hours; 3691 $lang_minute = " ".$lang->minute; 3692 $lang_minutes = " ".$lang->minutes; 3693 $lang_second = " ".$lang->second; 3694 $lang_seconds = " ".$lang->seconds; 3695 } 3696 3697 $years = floor($stamp/$ysecs); 3698 $stamp %= $ysecs; 3699 $months = floor($stamp/$mosecs); 3700 $stamp %= $mosecs; 3701 $weeks = floor($stamp/$wsecs); 3702 $stamp %= $wsecs; 3703 $days = floor($stamp/$dsecs); 3704 $stamp %= $dsecs; 3705 $hours = floor($stamp/$hsecs); 3706 $stamp %= $hsecs; 3707 $minutes = floor($stamp/$msecs); 3708 $stamp %= $msecs; 3709 $seconds = $stamp; 3710 3711 if($years == 1) 3712 { 3713 $nicetime['years'] = "1".$lang_year; 3714 } 3715 else if($years > 1) 3716 { 3717 $nicetime['years'] = $years.$lang_years; 3718 } 3719 3720 if($months == 1) 3721 { 3722 $nicetime['months'] = "1".$lang_month; 3723 } 3724 else if($months > 1) 3725 { 3726 $nicetime['months'] = $months.$lang_months; 3727 } 3728 3729 if($weeks == 1) 3730 { 3731 $nicetime['weeks'] = "1".$lang_week; 3732 } 3733 else if($weeks > 1) 3734 { 3735 $nicetime['weeks'] = $weeks.$lang_weeks; 3736 } 3737 3738 if($days == 1) 3739 { 3740 $nicetime['days'] = "1".$lang_day; 3741 } 3742 else if($days > 1) 3743 { 3744 $nicetime['days'] = $days.$lang_days; 3745 } 3746 3747 if(!isset($options['hours']) || $options['hours'] !== false) 3748 { 3749 if($hours == 1) 3750 { 3751 $nicetime['hours'] = "1".$lang_hour; 3752 } 3753 else if($hours > 1) 3754 { 3755 $nicetime['hours'] = $hours.$lang_hours; 3756 } 3757 } 3758 3759 if(!isset($options['minutes']) || $options['minutes'] !== false) 3760 { 3761 if($minutes == 1) 3762 { 3763 $nicetime['minutes'] = "1".$lang_minute; 3764 } 3765 else if($minutes > 1) 3766 { 3767 $nicetime['minutes'] = $minutes.$lang_minutes; 3768 } 3769 } 3770 3771 if(!isset($options['seconds']) || $options['seconds'] !== false) 3772 { 3773 if($seconds == 1) 3774 { 3775 $nicetime['seconds'] = "1".$lang_second; 3776 } 3777 else if($seconds > 1) 3778 { 3779 $nicetime['seconds'] = $seconds.$lang_seconds; 3780 } 3781 } 3782 3783 if(is_array($nicetime)) 3784 { 3785 return implode(", ", $nicetime); 3786 } 3787 } 3788 3789 /** 3790 * Select an alternating row colour based on the previous call to this function 3791 * 3792 * @param int 1 to reset the row to trow1. 3793 * @return string trow1 or trow2 depending on the previous call 3794 */ 3795 function alt_trow($reset=0) 3796 { 3797 global $alttrow; 3798 3799 if($alttrow == "trow1" && !$reset) 3800 { 3801 $trow = "trow2"; 3802 } 3803 else 3804 { 3805 $trow = "trow1"; 3806 } 3807 3808 $alttrow = $trow; 3809 3810 return $trow; 3811 } 3812 3813 /** 3814 * Add a user to a specific additional user group. 3815 * 3816 * @param int The user ID 3817 * @param int The user group ID to join 3818 */ 3819 function join_usergroup($uid, $joingroup) 3820 { 3821 global $db, $mybb; 3822 3823 if($uid == $mybb->user['uid']) 3824 { 3825 $user = $mybb->user; 3826 } 3827 else 3828 { 3829 $query = $db->simple_select("users", "additionalgroups, usergroup", "uid='".intval($uid)."'"); 3830 $user = $db->fetch_array($query); 3831 } 3832 3833 // Build the new list of additional groups for this user and make sure they're in the right format 3834 $usergroups = ""; 3835 $usergroups = $user['additionalgroups'].",".$joingroup; 3836 $groupslist = ""; 3837 $groups = explode(",", $usergroups); 3838 3839 if(is_array($groups)) 3840 { 3841 foreach($groups as $gid) 3842 { 3843 if(trim($gid) != "" && $gid != $user['usergroup'] && !$donegroup[$gid]) 3844 { 3845 $groupslist .= $comma.$gid; 3846 $comma = ","; 3847 $donegroup[$gid] = 1; 3848 } 3849 } 3850 } 3851 3852 // What's the point in updating if they're the same? 3853 if($groupslist != $user['additionalgroups']) 3854 { 3855 $db->update_query("users", array('additionalgroups' => $groupslist), "uid='".intval($uid)."'"); 3856 return true; 3857 } 3858 else 3859 { 3860 return false; 3861 } 3862 } 3863 3864 /** 3865 * Remove a user from a specific additional user group 3866 * 3867 * @param int The user ID 3868 * @param int The user group ID 3869 */ 3870 function leave_usergroup($uid, $leavegroup) 3871 { 3872 global $db, $mybb, $cache; 3873 3874 if($uid == $mybb->user['uid']) 3875 { 3876 $user = $mybb->user; 3877 } 3878 else 3879 { 3880 $query = $db->simple_select("users", "*", "uid='".intval($uid)."'"); 3881 $user = $db->fetch_array($query); 3882 } 3883 3884 $groupslist = ""; 3885 $usergroups = ""; 3886 $usergroups = $user['additionalgroups'].","; 3887 3888 $groups = explode(",", $user['additionalgroups']); 3889 3890 if(is_array($groups)) 3891 { 3892 foreach($groups as $gid) 3893 { 3894 if(trim($gid) != "" && $leavegroup != $gid && !$donegroup[$gid]) 3895 { 3896 $groupslist .= $comma.$gid; 3897 $comma = ","; 3898 $donegroup[$gid] = 1; 3899 } 3900 } 3901 } 3902 3903 $dispupdate = ""; 3904 if($leavegroup == $user['displaygroup']) 3905 { 3906 $dispupdate = ", displaygroup=usergroup"; 3907 } 3908 3909 $db->write_query(" 3910 UPDATE ".TABLE_PREFIX."users 3911 SET additionalgroups='$groupslist' $dispupdate 3912 WHERE uid='".intval($uid)."' 3913 "); 3914 3915 $cache->update_moderators(); 3916 } 3917 3918 /** 3919 * Get the current location taking in to account different web serves and systems 3920 * 3921 * @param boolean True to return as "hidden" fields 3922 * @param array Array of fields to ignore if first argument is true 3923 * @return string The current URL being accessed 3924 */ 3925 function get_current_location($fields=false, $ignore=array()) 3926 { 3927 if(defined("MYBB_LOCATION")) 3928 { 3929 return MYBB_LOCATION; 3930 } 3931 3932 if(!empty($_SERVER['PATH_INFO'])) 3933 { 3934 $location = htmlspecialchars_uni($_SERVER['PATH_INFO']); 3935 } 3936 elseif(!empty($_ENV['PATH_INFO'])) 3937 { 3938 $location = htmlspecialchars_uni($_ENV['PATH_INFO']); 3939 } 3940 elseif(!empty($_ENV['PHP_SELF'])) 3941 { 3942 $location = htmlspecialchars_uni($_ENV['PHP_SELF']); 3943 } 3944 else 3945 { 3946 $location = htmlspecialchars_uni($_SERVER['PHP_SELF']); 3947 } 3948 3949 if($fields == true) 3950 { 3951 global $mybb; 3952 3953 if(!is_array($ignore)) 3954 { 3955 $ignore = array($ignore); 3956 } 3957 3958 $form_html = ""; 3959 if(!empty($mybb->input)) 3960 { 3961 foreach($mybb->input as $name => $value) 3962 { 3963 if(in_array($name, $ignore)) 3964 { 3965 continue; 3966 } 3967 3968 $form_html .= "<input type=\"hidden\" name=\"".htmlspecialchars_uni((string)$name)."\" value=\"".htmlspecialchars_uni((string)$value)."\" />\n"; 3969 } 3970 } 3971 3972 return array('location' => $location, 'form_html' => $form_html, 'form_method' => $mybb->request_method); 3973 } 3974 else 3975 { 3976 if(isset($_SERVER['QUERY_STRING'])) 3977 { 3978 $location .= "?".htmlspecialchars_uni($_SERVER['QUERY_STRING']); 3979 } 3980 else if(isset($_ENV['QUERY_STRING'])) 3981 { 3982 $location .= "?".htmlspecialchars_uni($_ENV['QUERY_STRING']); 3983 } 3984 3985 if((isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == "POST") || (isset($_ENV['REQUEST_METHOD']) && $_ENV['REQUEST_METHOD'] == "POST")) 3986 { 3987 $post_array = array('action', 'fid', 'pid', 'tid', 'uid', 'eid'); 3988 3989 foreach($post_array as $var) 3990 { 3991 if(isset($_POST[$var])) 3992 { 3993 $addloc[] = urlencode($var).'='.urlencode($_POST[$var]); 3994 } 3995 } 3996 3997 if(isset($addloc) && is_array($addloc)) 3998 { 3999 if(strpos($location, "?") === false) 4000 { 4001 $location .= "?"; 4002 } 4003 else 4004 { 4005 $location .= "&"; 4006 } 4007 $location .= implode("&", $addloc); 4008 } 4009 } 4010 4011 if(strlen($location) > 150) 4012 { 4013 $location = substr($location, 0, 150); 4014 } 4015 4016 return $location; 4017 } 4018 } 4019 4020 /** 4021 * Build a theme selection menu 4022 * 4023 * @param string The name of the menu 4024 * @param int The ID of the selected theme 4025 * @param int The ID of the parent theme to select from 4026 * @param int The current selection depth 4027 * @param boolean Whether or not to override usergroup permissions (true to override) 4028 * @return string The theme selection list 4029 */ 4030 function build_theme_select($name, $selected="", $tid=0, $depth="", $usergroup_override=false) 4031 { 4032 global $db, $themeselect, $tcache, $lang, $mybb, $limit; 4033 4034 if($tid == 0) 4035 { 4036 $themeselect = "<select name=\"$name\">"; 4037 $themeselect .= "<option value=\"0\">".$lang->use_default."</option>\n"; 4038 $themeselect .= "<option value=\"0\">-----------</option>\n"; 4039 $tid = 1; 4040 } 4041 4042 if(!is_array($tcache)) 4043 { 4044 $query = $db->simple_select("themes", "name, pid, tid, allowedgroups", "pid != '0'", array('order_by' => 'pid, name')); 4045 4046 while($theme = $db->fetch_array($query)) 4047 { 4048 $tcache[$theme['pid']][$theme['tid']] = $theme; 4049 } 4050 } 4051 4052 if(is_array($tcache[$tid])) 4053 { 4054 // Figure out what groups this user is in 4055 if($mybb->user['additionalgroups']) 4056 { 4057 $in_groups = explode(",", $mybb->user['additionalgroups']); 4058 } 4059 $in_groups[] = $mybb->user['usergroup']; 4060 4061 foreach($tcache[$tid] as $theme) 4062 { 4063 $sel = ""; 4064 // Make theme allowed groups into array 4065 $is_allowed = false; 4066 if($theme['allowedgroups'] != "all") 4067 { 4068 $allowed_groups = explode(",", $theme['allowedgroups']); 4069 // See if groups user is in is allowed 4070 foreach($allowed_groups as $agid) 4071 { 4072 if(in_array($agid, $in_groups)) 4073 { 4074 $is_allowed = true; 4075 break; 4076 } 4077 } 4078 } 4079 4080 // Show theme if allowed, or if override is on 4081 if($is_allowed || $theme['allowedgroups'] == "all" || $usergroup_override == true) 4082 { 4083 if($theme['tid'] == $selected) 4084 { 4085 $sel = " selected=\"selected\""; 4086 } 4087 4088 if($theme['pid'] != 0) 4089 { 4090 $themeselect .= "<option value=\"".$theme['tid']."\"$sel>".$depth.htmlspecialchars_uni($theme['name'])."</option>"; 4091 $depthit = $depth."--"; 4092 } 4093 4094 if(array_key_exists($theme['tid'], $tcache)) 4095 { 4096 build_theme_select($name, $selected, $theme['tid'], $depthit, $usergroup_override); 4097 } 4098 } 4099 } 4100 } 4101 4102 if($tid == 1) 4103 { 4104 $themeselect .= "</select>"; 4105 } 4106 4107 return $themeselect; 4108 } 4109 4110 /** 4111 * Custom function for htmlspecialchars which takes in to account unicode 4112 * 4113 * @param string The string to format 4114 * @return string The string with htmlspecialchars applied 4115 */ 4116 function htmlspecialchars_uni($message) 4117 { 4118 $message = preg_replace("#&(?!\#[0-9]+;)#si", "&", $message); // Fix & but allow unicode 4119 $message = str_replace("<", "<", $message); 4120 $message = str_replace(">", ">", $message); 4121 $message = str_replace("\"", """, $message); 4122 return $message; 4123 } 4124 4125 /** 4126 * Custom function for formatting numbers. 4127 * 4128 * @param int The number to format. 4129 * @return int The formatted number. 4130 */ 4131 function my_number_format($number) 4132 { 4133 global $mybb; 4134 4135 if($number == "-") 4136 { 4137 return $number; 4138 } 4139 4140 if(is_int($number)) 4141 { 4142 return number_format($number, 0, $mybb->settings['decpoint'], $mybb->settings['thousandssep']); 4143 } 4144 else 4145 { 4146 $parts = explode('.', $number); 4147 4148 if(isset($parts[1])) 4149 { 4150 $decimals = my_strlen($parts[1]); 4151 } 4152 else 4153 { 4154 $decimals = 0; 4155 } 4156 4157 return number_format((double)$number, $decimals, $mybb->settings['decpoint'], $mybb->settings['thousandssep']); 4158 } 4159 } 4160 4161 function convert_through_utf8($str, $to=true) 4162 { 4163 global $lang; 4164 static $charset; 4165 static $use_mb; 4166 static $use_iconv; 4167 4168 if(!isset($charset)) 4169 { 4170 $charset = my_strtolower($lang->settings['charset']); 4171 } 4172 4173 if($charset == "utf-8") 4174 { 4175 return $str; 4176 } 4177 4178 if(!isset($use_iconv)) 4179 { 4180 $use_iconv = function_exists("iconv"); 4181 } 4182 4183 if(!isset($use_mb)) 4184 { 4185 $use_mb = function_exists("mb_convert_encoding"); 4186 } 4187 4188 if($use_iconv || $use_mb) 4189 { 4190 if($to) 4191 { 4192 $from_charset = $lang->settings['charset']; 4193 $to_charset = "UTF-8"; 4194 } 4195 else 4196 { 4197 $from_charset = "UTF-8"; 4198 $to_charset = $lang->settings['charset']; 4199 } 4200 if($use_iconv) 4201 { 4202 return iconv($from_charset, $to_charset."//IGNORE", $str); 4203 } 4204 else 4205 { 4206 return @mb_convert_encoding($str, $to_charset, $from_charset); 4207 } 4208 } 4209 elseif($charset == "iso-8859-1" && function_exists("utf8_encode")) 4210 { 4211 if($to) 4212 { 4213 return utf8_encode($str); 4214 } 4215 else 4216 { 4217 return utf8_decode($str); 4218 } 4219 } 4220 else 4221 { 4222 return $str; 4223 } 4224 } 4225 4226 /** 4227 * Replacement function for PHP's wordwrap(). This version does not break up HTML tags, URLs or unicode references. 4228 * 4229 * @param string The string to be word wrapped 4230 * @return string The word wraped string 4231 */ 4232 function my_wordwrap($message) 4233 { 4234 global $mybb; 4235 4236 if($mybb->settings['wordwrap'] > 0) 4237 { 4238 $message = convert_through_utf8($message); 4239 4240 if(!($new_message = @preg_replace("#(((?>[^\s&/<>\"\\-\[\]])|(&\#[a-z0-9]{1,10};)){{$mybb->settings['wordwrap']}})#u", "$0​", $message))) 4241 { 4242 $new_message = preg_replace("#(((?>[^\s&/<>\"\\-\[\]])|(&\#[a-z0-9]{1,10};)){{$mybb->settings['wordwrap']}})#", "$0​", $message); 4243 } 4244 4245 $new_message = convert_through_utf8($new_message, false); 4246 4247 return $new_message; 4248 } 4249 4250 return $message; 4251 } 4252 4253 /** 4254 * Workaround for date limitation in PHP to establish the day of a birthday (Provided by meme) 4255 * 4256 * @param int The month of the birthday 4257 * @param int The day of the birthday 4258 * @param int The year of the bithday 4259 * @return int The numeric day of the week for the birthday 4260 */ 4261 function get_weekday($month, $day, $year) 4262 { 4263 $h = 4; 4264 4265 for($i = 1969; $i >= $year; $i--) 4266 { 4267 $j = get_bdays($i); 4268 4269 for($k = 11; $k >= 0; $k--) 4270 { 4271 $l = ($k + 1); 4272 4273 for($m = $j[$k]; $m >= 1; $m--) 4274 { 4275 $h--; 4276 4277 if($i == $year && $l == $month && $m == $day) 4278 { 4279 return $h; 4280 } 4281 4282 if($h == 0) 4283 { 4284 $h = 7; 4285 } 4286 } 4287 } 4288 } 4289 } 4290 4291 /** 4292 * Workaround for date limitation in PHP to establish the day of a birthday (Provided by meme) 4293 * 4294 * @param int The year. 4295 * @return array The number of days in each month of that year 4296 */ 4297 function get_bdays($in) 4298 { 4299 return array( 4300 31, 4301 ($in % 4 == 0 && ($in % 100 > 0 || $in % 400 == 0) ? 29 : 28), 4302 31, 4303 30, 4304 31, 4305 30, 4306 31, 4307 31, 4308 30, 4309 31, 4310 30, 4311 31 4312 ); 4313 } 4314 4315 /** 4316 * Formats a birthday appropriately 4317 * 4318 * @param string The PHP date format string 4319 * @param int The month of the birthday 4320 * @param int The day of the birthday 4321 * @param int The year of the birthday 4322 * @param int The weekday of the birthday 4323 * @return string The formatted birthday 4324 */ 4325 function format_bdays($display, $bm, $bd, $by, $wd) 4326 { 4327 global $lang; 4328 4329 $bdays = array( 4330 $lang->sunday, 4331 $lang->monday, 4332 $lang->tuesday, 4333 $lang->wednesday, 4334 $lang->thursday, 4335 $lang->friday, 4336 $lang->saturday 4337 ); 4338 4339 $bmonth = array( 4340 $lang->month_1, 4341 $lang->month_2, 4342 $lang->month_3, 4343 $lang->month_4, 4344 $lang->month_5, 4345 $lang->month_6, 4346 $lang->month_7, 4347 $lang->month_8, 4348 $lang->month_9, 4349 $lang->month_10, 4350 $lang->month_11, 4351 $lang->month_12 4352 ); 4353 4354 4355 // This needs to be in this specific order 4356 $find = array( 4357 'm', 4358 'd', 4359 'D', 4360 'y', 4361 'Y', 4362 'j', 4363 'S', 4364 'F', 4365 'l', 4366 'M', 4367 ); 4368 4369 $html = array( 4370 'm', 4371 'c', 4372 'D', 4373 'y', 4374 'Y', 4375 'j', 4376 'S', 4377 'F', 4378 'l', 4379 'M', 4380 ); 4381 4382 $bdays = str_replace($find, $html, $bdays); 4383 $bmonth = str_replace($find, $html, $bmonth); 4384 4385 $replace = array( 4386 sprintf('%02s', $bm), 4387 sprintf('%02s', $bd), 4388 ($wd == 2 ? my_substr($bdays[$wd], 0, 4) : ($wd == 4 ? my_substr($bdays[$wd], 0, 5) : my_substr($bdays[$wd], 0, 3))), 4389 my_substr($by, 2), 4390 $by, 4391 ($bd[0] == 0 ? my_substr($bd, 1) : $bd), 4392 ($bd == 1 || $bd == 21 || $bd == 31 ? 'st' : ($bd == 2 || $bd == 22 ? 'nd' : ($bd == 3 || $bd == 23 ? 'rd' : 'th'))), 4393 $bmonth[$bm-1], 4394 $wd, 4395 ($bm == 9 ? my_substr($bmonth[$bm-1], 0, 4) : my_substr($bmonth[$bm-1], 0, 3)), 4396 ); 4397 4398 // Do we have the full month in our output? 4399 // If so there's no need for the short month 4400 if(strpos($display, 'F') !== false) 4401 { 4402 array_pop($find); 4403 array_pop($replace); 4404 } 4405 4406 return str_replace($find, $replace, $display); 4407 } 4408 4409 /** 4410 * Returns the age of a user with specified birthday. 4411 * 4412 * @param string The birthday of a user. 4413 * @return float The age of a user with that birthday. 4414 */ 4415 function get_age($birthday) 4416 { 4417 $bday = explode("-", $birthday); 4418 if(!$bday[2]) 4419 { 4420 return; 4421 } 4422 4423 list($day, $month, $year) = explode("-", my_date("j-n-Y", TIME_NOW, 0, 0)); 4424 4425 $age = $year-$bday[2]; 4426 4427 if(($month == $bday[1] && $day < $bday[0]) || $month < $bday[1]) 4428 { 4429 --$age; 4430 } 4431 return $age; 4432 } 4433 4434 /** 4435 * Updates the first posts in a thread. 4436 * 4437 * @param int The thread id for which to update the first post id. 4438 */ 4439 function update_first_post($tid) 4440 { 4441 global $db; 4442 4443 $query = $db->simple_select("posts", "pid,replyto", "tid='{$tid}'", array('order_by' => 'dateline', 'limit' => 1)); 4444 $post = $db->fetch_array($query); 4445 4446 if($post['replyto'] != 0) 4447 { 4448 $replyto_update = array( 4449 "replyto" => 0 4450 ); 4451 $db->update_query("posts", $replyto_update, "pid='{$post['pid']}'"); 4452 } 4453 4454 $firstpostup = array( 4455 "firstpost" => $post['pid'] 4456 ); 4457 $db->update_query("threads", $firstpostup, "tid='$tid'"); 4458 } 4459 4460 /** 4461 * Checks for the length of a string, mb strings accounted for 4462 * 4463 * @param string The string to check the length of. 4464 * @return int The length of the string. 4465 */ 4466 function my_strlen($string) 4467 { 4468 global $lang; 4469 4470 $string = preg_replace("#&\#([0-9]+);#", "-", $string); 4471 4472 if(strtolower($lang->settings['charset']) == "utf-8") 4473 { 4474 // Get rid of any excess RTL and LTR override for they are the workings of the devil 4475 $string = str_replace(dec_to_utf8(8238), "", $string); 4476 $string = str_replace(dec_to_utf8(8237), "", $string); 4477 4478 // Remove dodgy whitespaces 4479 $string = str_replace(chr(0xCA), "", $string); 4480 } 4481 $string = trim($string); 4482 4483 if(function_exists("mb_strlen")) 4484 { 4485 $string_length = mb_strlen($string); 4486 } 4487 else 4488 { 4489 $string_length = strlen($string); 4490 } 4491 4492 return $string_length; 4493 } 4494 4495 /** 4496 * Cuts a string at a specified point, mb strings accounted for 4497 * 4498 * @param string The string to cut. 4499 * @param int Where to cut 4500 * @param int (optional) How much to cut 4501 * @param bool (optional) Properly handle HTML entities? 4502 * @return int The cut part of the string. 4503 */ 4504 function my_substr($string, $start, $length="", $handle_entities = false) 4505 { 4506 if($handle_entities) 4507 { 4508 $string = unhtmlentities($string); 4509 } 4510 if(function_exists("mb_substr")) 4511 { 4512 if($length != "") 4513 { 4514 $cut_string = mb_substr($string, $start, $length); 4515 } 4516 else 4517 { 4518 $cut_string = mb_substr($string, $start); 4519 } 4520 } 4521 else 4522 { 4523 if($length != "") 4524 { 4525 $cut_string = substr($string, $start, $length); 4526 } 4527 else 4528 { 4529 $cut_string = substr($string, $start); 4530 } 4531 } 4532 4533 if($handle_entities) 4534 { 4535 $cut_string = htmlspecialchars_uni($cut_string); 4536 } 4537 return $cut_string; 4538 } 4539 4540 /** 4541 * lowers the case of a string, mb strings accounted for 4542 * 4543 * @param string The string to lower. 4544 * @return int The lowered string. 4545 */ 4546 function my_strtolower($string) 4547 { 4548 if(function_exists("mb_strtolower")) 4549 { 4550 $string = mb_strtolower($string); 4551 } 4552 else 4553 { 4554 $string = strtolower($string); 4555 } 4556 4557 return $string; 4558 } 4559 4560 /** 4561 * Finds a needle in a haystack and returns it position, mb strings accounted for 4562 * 4563 * @param string String to look in (haystack) 4564 * @param string What to look for (needle) 4565 * @param int (optional) How much to offset 4566 * @return int false on needle not found, integer position if found 4567 */ 4568 function my_strpos($haystack, $needle, $offset=0) 4569 { 4570 if($needle == '') 4571 { 4572 return false; 4573 } 4574 4575 if(function_exists("mb_strpos")) 4576 { 4577 $position = mb_strpos($haystack, $needle, $offset); 4578 } 4579 else 4580 { 4581 $position = strpos($haystack, $needle, $offset); 4582 } 4583 4584 return $position; 4585 } 4586 4587 /** 4588 * ups the case of a string, mb strings accounted for 4589 * 4590 * @param string The string to up. 4591 * @return int The uped string. 4592 */ 4593 function my_strtoupper($string) 4594 { 4595 if(function_exists("mb_strtoupper")) 4596 { 4597 $string = mb_strtoupper($string); 4598 } 4599 else 4600 { 4601 $string = strtoupper($string); 4602 } 4603 4604 return $string; 4605 } 4606 4607 /** 4608 * Returns any html entities to their original character 4609 * 4610 * @param string The string to un-htmlentitize. 4611 * @return int The un-htmlentitied' string. 4612 */ 4613 function unhtmlentities($string) 4614 { 4615 // Replace numeric entities 4616 $string = preg_replace_callback('~&#x([0-9a-f]+);~i', create_function('$matches', 'return unichr(hexdec($matches[1]));'), $string); 4617 $string = preg_replace_callback('~&#([0-9]+);~', create_function('$matches', 'return unichr($matches[1]);'), $string); 4618 4619 // Replace literal entities 4620 $trans_tbl = get_html_translation_table(HTML_ENTITIES); 4621 $trans_tbl = array_flip($trans_tbl); 4622 4623 return strtr($string, $trans_tbl); 4624 } 4625 4626 /** 4627 * Returns any ascii to it's character (utf-8 safe). 4628 * 4629 * @param string The ascii to characterize. 4630 * @return int The characterized ascii. 4631 */ 4632 function unichr($c) 4633 { 4634 if($c <= 0x7F) 4635 { 4636 return chr($c); 4637 } 4638 else if($c <= 0x7FF) 4639 { 4640 return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F); 4641 } 4642 else if($c <= 0xFFFF) 4643 { 4644 return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F) 4645 . chr(0x80 | $c & 0x3F); 4646 } 4647 else if($c <= 0x10FFFF) 4648 { 4649 return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F) 4650 . chr(0x80 | $c >> 6 & 0x3F) 4651 . chr(0x80 | $c & 0x3F); 4652 } 4653 else 4654 { 4655 return false; 4656 } 4657 } 4658 4659 /** 4660 * Get the event poster. 4661 * 4662 * @param array The event data array. 4663 * @return string The link to the event poster. 4664 */ 4665 function get_event_poster($event) 4666 { 4667 $event['username'] = format_name($event['username'], $event['usergroup'], $event['displaygroup']); 4668 $event_poster = build_profile_link($event['username'], $event['author']); 4669 return $event_poster; 4670 } 4671 4672 /** 4673 * Get the event date. 4674 * 4675 * @param array The event data array. 4676 * @return string The event date. 4677 */ 4678 function get_event_date($event) 4679 { 4680 global $mybb; 4681 4682 $event_date = explode("-", $event['date']); 4683 $event_date = mktime(0, 0, 0, $event_date[1], $event_date[0], $event_date[2]); 4684 $event_date = my_date($mybb->settings['dateformat'], $event_date); 4685 4686 return $event_date; 4687 } 4688 4689 /** 4690 * Get the profile link. 4691 * 4692 * @param int The user id of the profile. 4693 * @return string The url to the profile. 4694 */ 4695 function get_profile_link($uid=0) 4696 { 4697 $link = str_replace("{uid}", $uid, PROFILE_URL); 4698 return htmlspecialchars_uni($link); 4699 } 4700 4701 /** 4702 * Get the announcement link. 4703 * 4704 * @param int The announement id of the announcement. 4705 * @return string The url to the announcement. 4706 */ 4707 function get_announcement_link($aid=0) 4708 { 4709 $link = str_replace("{aid}", $aid, ANNOUNCEMENT_URL); 4710 return htmlspecialchars_uni($link); 4711 } 4712 4713 /** 4714 * Build the profile link. 4715 * 4716 * @param string The Username of the profile. 4717 * @param int The user id of the profile. 4718 * @param string The target frame 4719 * @param string Any onclick javascript. 4720 * @return string The complete profile link. 4721 */ 4722 function build_profile_link($username="", $uid=0, $target="", $onclick="") 4723 { 4724 global $mybb, $lang; 4725 4726 if(!$username && $uid == 0) 4727 { 4728 // Return Guest phrase for no UID, no guest nickname 4729 return $lang->guest; 4730 } 4731 elseif($uid == 0) 4732 { 4733 // Return the guest's nickname if user is a guest but has a nickname 4734 return $username; 4735 } 4736 else 4737 { 4738 // Build the profile link for the registered user 4739 if(!empty($target)) 4740 { 4741 $target = " target=\"{$target}\""; 4742 } 4743 4744 if(!empty($onclick)) 4745 { 4746 $onclick = " onclick=\"{$onclick}\""; 4747 } 4748 4749 return "<a href=\"{$mybb->settings['bburl']}/".get_profile_link($uid)."\"{$target}{$onclick}>{$username}</a>"; 4750 } 4751 } 4752 4753 /** 4754 * Build the forum link. 4755 * 4756 * @param int The forum id of the forum. 4757 * @param int (Optional) The page number of the forum. 4758 * @return string The url to the forum. 4759 */ 4760 function get_forum_link($fid, $page=0) 4761 { 4762 if($page > 0) 4763 { 4764 $link = str_replace("{fid}", $fid, FORUM_URL_PAGED); 4765 $link = str_replace("{page}", $page, $link); 4766 return htmlspecialchars_uni($link); 4767 } 4768 else 4769 { 4770 $link = str_replace("{fid}", $fid, FORUM_URL); 4771 return htmlspecialchars_uni($link); 4772 } 4773 } 4774 4775 /** 4776 * Build the thread link. 4777 * 4778 * @param int The thread id of the thread. 4779 * @param int (Optional) The page number of the thread. 4780 * @param string (Optional) The action we're performing (ex, lastpost, newpost, etc) 4781 * @return string The url to the thread. 4782 */ 4783 function get_thread_link($tid, $page=0, $action='') 4784 { 4785 if($page > 1) 4786 { 4787 if($action) 4788 { 4789 $link = THREAD_URL_ACTION; 4790 $link = str_replace("{action}", $action, $link); 4791 } 4792 else 4793 { 4794 $link = THREAD_URL_PAGED; 4795 } 4796 $link = str_replace("{tid}", $tid, $link); 4797 $link = str_replace("{page}", $page, $link); 4798 return htmlspecialchars_uni($link); 4799 } 4800 else 4801 { 4802 if($action) 4803 { 4804 $link = THREAD_URL_ACTION; 4805 $link = str_replace("{action}", $action, $link); 4806 } 4807 else 4808 { 4809 $link = THREAD_URL; 4810 } 4811 $link = str_replace("{tid}", $tid, $link); 4812 return htmlspecialchars_uni($link); 4813 } 4814 } 4815 4816 /** 4817 * Build the post link. 4818 * 4819 * @param int The post ID of the post 4820 * @param int The thread id of the post. 4821 */ 4822 function get_post_link($pid, $tid=0) 4823 { 4824 if($tid > 0) 4825 { 4826 $link = str_replace("{tid}", $tid, THREAD_URL_POST); 4827 $link = str_replace("{pid}", $pid, $link); 4828 return htmlspecialchars_uni($link); 4829 } 4830 else 4831 { 4832 $link = str_replace("{pid}", $pid, POST_URL); 4833 return htmlspecialchars_uni($link); 4834 } 4835 } 4836 4837 /** 4838 * Build the event link. 4839 * 4840 * @param int The event ID of the event 4841 * @return string The URL of the event 4842 */ 4843 function get_event_link($eid) 4844 { 4845 $link = str_replace("{eid}", $eid, EVENT_URL); 4846 return htmlspecialchars_uni($link); 4847 } 4848 4849 /** 4850 * Build the link to a specified date on the calendar 4851 * 4852 * @param int The ID of the calendar 4853 * @param int The year 4854 * @param int The month 4855 * @param int The day (optional) 4856 * @return string The URL of the calendar 4857 */ 4858 function get_calendar_link($calendar, $year=0, $month=0, $day=0) 4859 { 4860 if($day > 0) 4861 { 4862 $link = str_replace("{month}", $month, CALENDAR_URL_DAY); 4863 $link = str_replace("{year}", $year, $link); 4864 $link = str_replace("{day}", $day, $link); 4865 $link = str_replace("{calendar}", $calendar, $link); 4866 return htmlspecialchars_uni($link); 4867 } 4868 else if($month > 0) 4869 { 4870 $link = str_replace("{month}", $month, CALENDAR_URL_MONTH); 4871 $link = str_replace("{year}", $year, $link); 4872 $link = str_replace("{calendar}", $calendar, $link); 4873 return htmlspecialchars_uni($link); 4874 } 4875 else if($year > 0) 4876 { 4877 $link = str_replace("{year}", $year, CALENDAR_URL_YEAR); 4878 $link = str_replace("{calendar}", $calendar, $link); 4879 return htmlspecialchars_uni($link); 4880 } 4881 else 4882 { 4883 $link = str_replace("{calendar}", $calendar, CALENDAR_URL); 4884 return htmlspecialchars_uni($link); 4885 } 4886 } 4887 4888 /** 4889 * Build the link to a specified week on the calendar 4890 * 4891 * @param int The ID of the calendar 4892 * @param int The year 4893 * @param int The week 4894 * @return string The URL of the calendar 4895 */ 4896 function get_calendar_week_link($calendar, $week) 4897 { 4898 if($week < 0) 4899 { 4900 $week = str_replace('-', "n", $week); 4901 } 4902 $link = str_replace("{week}", $week, CALENDAR_URL_WEEK); 4903 $link = str_replace("{calendar}", $calendar, $link); 4904 return htmlspecialchars_uni($link); 4905 } 4906 4907 /** 4908 * Get the user data of a user id. 4909 * 4910 * @param int The user id of the user. 4911 * @return array The users data 4912 */ 4913 function get_user($uid) 4914 { 4915 global $mybb, $db; 4916 static $user_cache; 4917 4918 $uid = intval($uid); 4919 4920 if($uid == $mybb->user['uid']) 4921 { 4922 return $mybb->user; 4923 } 4924 elseif(isset($user_cache[$uid])) 4925 { 4926 return $user_cache[$uid]; 4927 } 4928 elseif(($uid > 0)) 4929 { 4930 $query = $db->simple_select("users", "*", "uid='{$uid}'"); 4931 $user_cache[$uid] = $db->fetch_array($query); 4932 4933 return $user_cache[$uid]; 4934 } 4935 return array(); 4936 } 4937 4938 /** 4939 * Get the forum of a specific forum id. 4940 * 4941 * @param int The forum id of the forum. 4942 * @param int (Optional) If set to 1, will override the active forum status 4943 * @return array The database row of a forum. 4944 */ 4945 function get_forum($fid, $active_override=0) 4946 { 4947 global $cache; 4948 static $forum_cache; 4949 4950 if(!isset($forum_cache) || is_array($forum_cache)) 4951 { 4952 $forum_cache = $cache->read("forums"); 4953 } 4954 4955 if(!$forum_cache[$fid]) 4956 { 4957 return false; 4958 } 4959 4960 if($active_override != 1) 4961 { 4962 $parents = explode(",", $forum_cache[$fid]['parentlist']); 4963 if(is_array($parents)) 4964 { 4965 foreach($parents as $parent) 4966 { 4967 if($forum_cache[$parent]['active'] == 0) 4968 { 4969 return false; 4970 } 4971 } 4972 } 4973 } 4974 4975 return $forum_cache[$fid]; 4976 } 4977 4978 /** 4979 * Get the thread of a thread id. 4980 * 4981 * @param int The thread id of the thread. 4982 * @param boolean Whether or not to recache the thread. 4983 * @return string The database row of the thread. 4984 */ 4985 function get_thread($tid, $recache = false) 4986 { 4987 global $db; 4988 static $thread_cache; 4989 4990 if(isset($thread_cache[$tid]) && !$recache) 4991 { 4992 return $thread_cache[$tid]; 4993 } 4994 else 4995 { 4996 $query = $db->simple_select("threads", "*", "tid='".intval($tid)."'"); 4997 $thread = $db->fetch_array($query); 4998 4999 if($thread) 5000 { 5001 $thread_cache[$tid] = $thread; 5002 return $thread; 5003 } 5004 else 5005 { 5006 $thread_cache[$tid] = false; 5007 return false; 5008 } 5009 } 5010 } 5011 5012 /** 5013 * Get the post of a post id. 5014 * 5015 * @param int The post id of the post. 5016 * @return string The database row of the post. 5017 */ 5018 function get_post($pid) 5019 { 5020 global $db; 5021 static $post_cache; 5022 5023 if(isset($post_cache[$pid])) 5024 { 5025 return $post_cache[$pid]; 5026 } 5027 else 5028 { 5029 $query = $db->simple_select("posts", "*", "pid='".intval($pid)."'"); 5030 $post = $db->fetch_array($query); 5031 5032 if($post) 5033 { 5034 $post_cache[$pid] = $post; 5035 return $post; 5036 } 5037 else 5038 { 5039 $post_cache[$pid] = false; 5040 return false; 5041 } 5042 } 5043 } 5044 5045 /** 5046 * Get inactivate forums. 5047 * 5048 * @return string The comma separated values of the inactivate forum. 5049 */ 5050 function get_inactive_forums() 5051 { 5052 global $forum_cache, $cache, $inactiveforums; 5053 5054 if(!$forum_cache) 5055 { 5056 cache_forums(); 5057 } 5058 5059 $inactive = array(); 5060 5061 foreach($forum_cache as $fid => $forum) 5062 { 5063 if($forum['active'] == 0) 5064 { 5065 $inactive[] = $fid; 5066 foreach($forum_cache as $fid1 => $forum1) 5067 { 5068 if(my_strpos(",".$forum1['parentlist'].",", ",".$fid.",") !== false && !in_array($fid1, $inactive)) 5069 { 5070 $inactive[] = $fid1; 5071 } 5072 } 5073 } 5074 } 5075 $inactiveforums = implode(",", $inactive); 5076 5077 return $inactiveforums; 5078 } 5079 5080 /** 5081 * Checks to make sure a user has not tried to login more times than permitted 5082 * Will stop execution with call to error() unless 5083 * 5084 * @param bool (Optional) The function will stop execution if it finds an error with the login. Default is True 5085 * @return bool Number of logins when success, false if failed. 5086 */ 5087 function login_attempt_check($fatal = true) 5088 { 5089 global $mybb, $lang, $session, $db; 5090 5091 if($mybb->settings['failedlogincount'] == 0) 5092 { 5093 return 1; 5094 } 5095 // Note: Number of logins is defaulted to 1, because using 0 seems to clear cookie data. Not really a problem as long as we account for 1 being default. 5096 5097 // Use cookie if possible, otherwise use session 5098 // Find better solution to prevent clearing cookies 5099 $loginattempts = 0; 5100 $failedlogin = 0; 5101 5102 if(!empty($mybb->cookies['loginattempts'])) 5103 { 5104 $loginattempts = $mybb->cookies['loginattempts']; 5105 } 5106 5107 if(!empty($mybb->cookies['failedlogin'])) 5108 { 5109 $failedlogin = $mybb->cookies['failedlogin']; 5110 } 5111 5112 // Work out if the user has had more than the allowed number of login attempts 5113 if($loginattempts > $mybb->settings['failedlogincount']) 5114 { 5115 // If so, then we need to work out if they can try to login again 5116 // Some maths to work out how long they have left and display it to them 5117 $now = TIME_NOW; 5118 5119 if(empty($mybb->cookies['failedlogin'])) 5120 { 5121 $failedtime = $now; 5122 } 5123 else 5124 { 5125 $failedtime = $mybb->cookies['failedlogin']; 5126 } 5127 5128 $secondsleft = $mybb->settings['failedlogintime'] * 60 + $failedtime - $now; 5129 $hoursleft = floor($secondsleft / 3600); 5130 $minsleft = floor(($secondsleft / 60) % 60); 5131 $secsleft = floor($secondsleft % 60); 5132 5133 // This value will be empty the first time the user doesn't login in, set it 5134 if(empty($failedlogin)) 5135 { 5136 my_setcookie('failedlogin', $now); 5137 if($fatal) 5138 { 5139 error($lang->sprintf($lang->failed_login_wait, $hoursleft, $minsleft, $secsleft)); 5140 } 5141 5142 return false; 5143 } 5144 5145 // Work out if the user has waited long enough before letting them login again 5146 if($mybb->cookies['failedlogin'] < ($now - $mybb->settings['failedlogintime'] * 60)) 5147 { 5148 my_setcookie('loginattempts', 1); 5149 my_unsetcookie('failedlogin'); 5150 if($mybb->user['uid'] != 0) 5151 { 5152 $update_array = array( 5153 'loginattempts' => 1 5154 ); 5155 $db->update_query("users", $update_array, "uid = '{$mybb->user['uid']}'"); 5156 } 5157 return 1; 5158 } 5159 // Not waited long enough 5160 else if($mybb->cookies['failedlogin'] > ($now - $mybb->settings['failedlogintime'] * 60)) 5161 { 5162 if($fatal) 5163 { 5164 error($lang->sprintf($lang->failed_login_wait, $hoursleft, $minsleft, $secsleft)); 5165 } 5166 5167 return false; 5168 } 5169 } 5170 5171 // User can attempt another login 5172 return $loginattempts; 5173 } 5174 5175 /** 5176 * Validates the format of an email address. 5177 * 5178 * @param string The string to check. 5179 * @return boolean True when valid, false when invalid. 5180 */ 5181 function validate_email_format($email) 5182 { 5183 if(strpos($email, ' ') !== false) 5184 { 5185 return false; 5186 } 5187 // Valid local characters for email addresses: http://www.remote.org/jochen/mail/info/chars.html 5188 return preg_match("/^[a-zA-Z0-9&*+\-_.{}~^\?=\/]+@[a-zA-Z0-9-]+\.([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]{2,}$/si", $email); 5189 } 5190 5191 /** 5192 * Checks to see if the email is already in use by another 5193 * 5194 * @param string The email to check. 5195 * @param string User ID of the user (updating only) 5196 * @return boolean True when in use, false when not. 5197 */ 5198 function email_already_in_use($email, $uid="") 5199 { 5200 global $db; 5201 5202 $uid_string = ""; 5203 if($uid) 5204 { 5205 $uid_string = " AND uid != '".intval($uid)."'"; 5206 } 5207 $query = $db->simple_select("users", "COUNT(email) as emails", "email = '".$db->escape_string($email)."'{$uid_string}"); 5208 5209 if($db->fetch_field($query, "emails") > 0) 5210 { 5211 return true; 5212 } 5213 5214 return false; 5215 } 5216 5217 /* 5218 * DEPRECATED! ONLY INCLUDED FOR COMPATIBILITY PURPOSES. 5219 */ 5220 function rebuildsettings() 5221 { 5222 rebuild_settings(); 5223 } 5224 5225 /** 5226 * Rebuilds settings.php 5227 * 5228 */ 5229 function rebuild_settings() 5230 { 5231 global $db, $mybb; 5232 5233 if(!file_exists(MYBB_ROOT."inc/settings.php")) 5234 { 5235 $mode = "x"; 5236 } 5237 else 5238 { 5239 $mode = "w"; 5240 } 5241 5242 $options = array( 5243 "order_by" => "title", 5244 "order_dir" => "ASC" 5245 ); 5246 $query = $db->simple_select("settings", "value, name", "", $options); 5247 5248 while($setting = $db->fetch_array($query)) 5249 { 5250 $mybb->settings[$setting['name']] = $setting['value']; 5251 $setting['value'] = addcslashes($setting['value'], '\\"$'); 5252 $settings .= "\$settings['{$setting['name']}'] = \"{$setting['value']}\";\n"; 5253 } 5254 5255 $settings = "<"."?php\n/*********************************\ \n DO NOT EDIT THIS FILE, PLEASE USE\n THE SETTINGS EDITOR\n\*********************************/\n\n$settings\n?".">"; 5256 $file = @fopen(MYBB_ROOT."inc/settings.php", $mode); 5257 @fwrite($file, $settings); 5258 @fclose($file); 5259 5260 $GLOBALS['settings'] = &$mybb->settings; 5261 } 5262 5263 /** 5264 * Build a PREG compatible array of search highlight terms to replace in posts. 5265 * 5266 * @param string Incoming terms to highlight 5267 * @return array PREG compatible array of terms 5268 */ 5269 function build_highlight_array($terms) 5270 { 5271 global $mybb; 5272 5273 if($mybb->settings['minsearchword'] < 1) 5274 { 5275 $mybb->settings['minsearchword'] = 3; 5276 } 5277 5278 if(is_array($terms)) 5279 { 5280 $terms = implode(' ', $terms); 5281 } 5282 5283 // Strip out any characters that shouldn't be included 5284 $bad_characters = array( 5285 "(", 5286 ")", 5287 "+", 5288 "-", 5289 "~" 5290 ); 5291 $terms = str_replace($bad_characters, '', $terms); 5292 5293 // Check if this is a "series of words" - should be treated as an EXACT match 5294 if(my_strpos($terms, "\"") !== false) 5295 { 5296 $inquote = false; 5297 $terms = explode("\"", $terms); 5298 foreach($terms as $phrase) 5299 { 5300 $phrase = htmlspecialchars_uni($phrase); 5301 if($phrase != "") 5302 { 5303 if($inquote) 5304 { 5305 $words[] = trim($phrase); 5306 } 5307 else 5308 { 5309 $split_words = preg_split("#\s{1,}#", $phrase, -1); 5310 if(!is_array($split_words)) 5311 { 5312 continue; 5313 } 5314 foreach($split_words as $word) 5315 { 5316 if(!$word || strlen($word) < $mybb->settings['minsearchword']) 5317 { 5318 continue; 5319 } 5320 $words[] = trim($word); 5321 } 5322 } 5323 } 5324 $inquote = !$inquote; 5325 } 5326 } 5327 // Otherwise just a simple search query with no phrases 5328 else 5329 { 5330 $terms = htmlspecialchars_uni($terms); 5331 $split_words = preg_split("#\s{1,}#", $terms, -1); 5332 if(is_array($split_words)) 5333 { 5334 foreach($split_words as $word) 5335 { 5336 if(!$word || strlen($word) < $mybb->settings['minsearchword']) 5337 { 5338 continue; 5339 } 5340 $words[] = trim($word); 5341 } 5342 } 5343 } 5344 5345 if(!is_array($words)) 5346 { 5347 return false; 5348 } 5349 5350 // Sort the word array by length. Largest terms go first and work their way down to the smallest term. 5351 // This resolves problems like "test tes" where "tes" will be highlighted first, then "test" can't be highlighted because of the changed html 5352 usort($words, create_function('$a,$b', 'return strlen($b) - strlen($a);')); 5353 5354 // Loop through our words to build the PREG compatible strings 5355 foreach($words as $word) 5356 { 5357 $word = trim($word); 5358 5359 $word = my_strtolower($word); 5360 5361 // Special boolean operators should be stripped 5362 if($word == "" || $word == "or" || $word == "not" || $word == "and") 5363 { 5364 continue; 5365 } 5366 5367 // Now make PREG compatible 5368 $find = "#(?!<.*?)(".preg_quote($word, "#").")(?![^<>]*?>)#ui"; 5369 $replacement = "<span class=\"highlight\" style=\"padding-left: 0px; padding-right: 0px;\">$1</span>"; 5370 $highlight_cache[$find] = $replacement; 5371 } 5372 5373 return $highlight_cache; 5374 } 5375 5376 /** 5377 * Converts a decimal reference of a character to its UTF-8 equivalent 5378 * (Code by Anne van Kesteren, http://annevankesteren.nl/2005/05/character-references) 5379 * 5380 * @param string Decimal value of a character reference 5381 */ 5382 function dec_to_utf8($src) 5383 { 5384 $dest = ''; 5385 5386 if($src < 0) 5387 { 5388 return false; 5389 } 5390 elseif($src <= 0x007f) 5391 { 5392 $dest .= chr($src); 5393 } 5394 elseif($src <= 0x07ff) 5395 { 5396 $dest .= chr(0xc0 | ($src >> 6)); 5397 $dest .= chr(0x80 | ($src & 0x003f)); 5398 } 5399 elseif($src <= 0xffff) 5400 { 5401 $dest .= chr(0xe0 | ($src >> 12)); 5402 $dest .= chr(0x80 | (($src >> 6) & 0x003f)); 5403 $dest .= chr(0x80 | ($src & 0x003f)); 5404 } 5405 elseif($src <= 0x10ffff) 5406 { 5407 $dest .= chr(0xf0 | ($src >> 18)); 5408 $dest .= chr(0x80 | (($src >> 12) & 0x3f)); 5409 $dest .= chr(0x80 | (($src >> 6) & 0x3f)); 5410 $dest .= chr(0x80 | ($src & 0x3f)); 5411 } 5412 else 5413 { 5414 // Out of range 5415 return false; 5416 } 5417 5418 return $dest; 5419 } 5420 5421 /** 5422 * Checks if a username has been disallowed for registration/use. 5423 * 5424 * @param string The username 5425 * @param boolean True if the 'last used' dateline should be updated if a match is found. 5426 * @return boolean True if banned, false if not banned 5427 */ 5428 function is_banned_username($username, $update_lastuse=false) 5429 { 5430 global $db; 5431 $query = $db->simple_select('banfilters', 'filter, fid', "type='2'"); 5432 while($banned_username = $db->fetch_array($query)) 5433 { 5434 // Make regular expression * match 5435 $banned_username['filter'] = str_replace('\*', '(.*)', preg_quote($banned_username['filter'], '#')); 5436 if(preg_match("#(^|\b){$banned_username['filter']}($|\b)#i", $username)) 5437 { 5438 // Updating last use 5439 if($update_lastuse == true) 5440 { 5441 $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_username['fid']}'"); 5442 } 5443 return true; 5444 } 5445 } 5446 // Still here - good username 5447 return false; 5448 } 5449 5450 /** 5451 * Check if a specific email address has been banned. 5452 * 5453 * @param string The email address. 5454 * @param boolean True if the 'last used' dateline should be updated if a match is found. 5455 * @return boolean True if banned, false if not banned 5456 */ 5457 function is_banned_email($email, $update_lastuse=false) 5458 { 5459 global $cache, $db; 5460 5461 $banned_cache = $cache->read("bannedemails"); 5462 5463 if($banned_cache === false) 5464 { 5465 // Failed to read cache, see if we can rebuild it 5466 $cache->update_bannedemails(); 5467 $banned_cache = $cache->read("bannedemails"); 5468 } 5469 5470 if(is_array($banned_cache) && !empty($banned_cache)) 5471 { 5472 foreach($banned_cache as $banned_email) 5473 { 5474 // Make regular expression * match 5475 $banned_email['filter'] = str_replace('\*', '(.*)', preg_quote($banned_email['filter'], '#')); 5476 5477 if(preg_match("#{$banned_email['filter']}#i", $email)) 5478 { 5479 // Updating last use 5480 if($update_lastuse == true) 5481 { 5482 $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_email['fid']}'"); 5483 } 5484 return true; 5485 } 5486 } 5487 } 5488 5489 // Still here - good email 5490 return false; 5491 } 5492 5493 /** 5494 * Checks if a specific IP address has been banned. 5495 * 5496 * @param string The IP address. 5497 * @param boolean True if the 'last used' dateline should be updated if a match is found. 5498 * @return boolean True if banned, false if not banned. 5499 */ 5500 function is_banned_ip($ip_address, $update_lastuse=false) 5501 { 5502 global $db, $cache; 5503 5504 $banned_ips = $cache->read("bannedips"); 5505 if(!is_array($banned_ips)) 5506 { 5507 return false; 5508 } 5509 5510 foreach($banned_ips as $banned_ip) 5511 { 5512 if(!$banned_ip['filter']) 5513 { 5514 continue; 5515 } 5516 5517 // Make regular expression * match 5518 $banned_ip['filter'] = str_replace('\*', '(.*)', preg_quote($banned_ip['filter'], '#')); 5519 if(preg_match("#^{$banned_ip['filter']}$#i", $ip_address)) 5520 { 5521 // Updating last use 5522 if($update_lastuse == true) 5523 { 5524 $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_ip['fid']}'"); 5525 } 5526 return true; 5527 } 5528 } 5529 5530 // Still here - good ip 5531 return false; 5532 } 5533 5534 /** 5535 * Build a time zone selection list. 5536 * 5537 * @param string The name of the select 5538 * @param int The selected time zone (defaults to GMT) 5539 * @param boolean True to generate a "short" list with just timezone and current time 5540 */ 5541 function build_timezone_select($name, $selected=0, $short=false) 5542 { 5543 global $mybb, $lang; 5544 5545 $timezones = array( 5546 "-12" => $lang->timezone_gmt_minus_1200, 5547 "-11" => $lang->timezone_gmt_minus_1100, 5548 "-10" => $lang->timezone_gmt_minus_1000, 5549 "-9" => $lang->timezone_gmt_minus_900, 5550 "-8" => $lang->timezone_gmt_minus_800, 5551 "-7" => $lang->timezone_gmt_minus_700, 5552 "-6" => $lang->timezone_gmt_minus_600, 5553 "-5" => $lang->timezone_gmt_minus_500, 5554 "-4.5" => $lang->timezone_gmt_minus_450, 5555 "-4" => $lang->timezone_gmt_minus_400, 5556 "-3.5" => $lang->timezone_gmt_minus_350, 5557 "-3" => $lang->timezone_gmt_minus_300, 5558 "-2" => $lang->timezone_gmt_minus_200, 5559 "-1" => $lang->timezone_gmt_minus_100, 5560 "0" => $lang->timezone_gmt, 5561 "1" => $lang->timezone_gmt_100, 5562 "2" => $lang->timezone_gmt_200, 5563 "3" => $lang->timezone_gmt_300, 5564 "3.5" => $lang->timezone_gmt_350, 5565 "4" => $lang->timezone_gmt_400, 5566 "4.5" => $lang->timezone_gmt_450, 5567 "5" => $lang->timezone_gmt_500, 5568 "5.5" => $lang->timezone_gmt_550, 5569 "6" => $lang->timezone_gmt_600, 5570 "7" => $lang->timezone_gmt_700, 5571 "8" => $lang->timezone_gmt_800, 5572 "9" => $lang->timezone_gmt_900, 5573 "9.5" => $lang->timezone_gmt_950, 5574 "10" => $lang->timezone_gmt_1000, 5575 "11" => $lang->timezone_gmt_1100, 5576 "12" => $lang->timezone_gmt_1200 5577 ); 5578 5579 $selected = str_replace("+", "", $selected); 5580 $select = "<select name=\"{$name}\" id=\"{$name}\">\n"; 5581 foreach($timezones as $timezone => $label) 5582 { 5583 $selected_add = ""; 5584 if($selected == $timezone) 5585 { 5586 $selected_add = " selected=\"selected\""; 5587 } 5588 if($short == true) 5589 { 5590 $label = ''; 5591 if($timezone != 0) 5592 { 5593 $label = $timezone; 5594 if($timezone > 0) 5595 { 5596 $label = "+{$label}"; 5597 } 5598 if(strpos($timezone, ".") !== false) 5599 { 5600 $label = str_replace(".", ":", $label); 5601 $label = str_replace(":5", ":30", $label); 5602 } 5603 else 5604 { 5605 $label .= ":00"; 5606 } 5607 } 5608 $time_in_zone = my_date($mybb->settings['timeformat'], TIME_NOW, $timezone); 5609 $label = $lang->sprintf($lang->timezone_gmt_short, $label." ", $time_in_zone); 5610 } 5611 $select .= "<option value=\"{$timezone}\"{$selected_add}>{$label}</option>\n"; 5612 } 5613 $select .= "</select>"; 5614 return $select; 5615 } 5616 5617 /** 5618 * Fetch the contents of a remote fle. 5619 * 5620 * @param string The URL of the remote file 5621 * @return string The remote file contents. 5622 */ 5623 function fetch_remote_file($url, $post_data=array()) 5624 { 5625 $post_body = ''; 5626 if(!empty($post_data)) 5627 { 5628 foreach($post_data as $key => $val) 5629 { 5630 $post_body .= '&'.urlencode($key).'='.urlencode($val); 5631 } 5632 $post_body = ltrim($post_body, '&'); 5633 } 5634 5635 if(function_exists("curl_init")) 5636 { 5637 $ch = curl_init(); 5638 curl_setopt($ch, CURLOPT_URL, $url); 5639 curl_setopt($ch, CURLOPT_HEADER, 0); 5640 curl_setopt($ch, CURLOPT_TIMEOUT, 10); 5641 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 5642 if(!empty($post_body)) 5643 { 5644 curl_setopt($ch, CURLOPT_POST, 1); 5645 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body); 5646 } 5647 $data = curl_exec($ch); 5648 curl_close($ch); 5649 return $data; 5650 } 5651 else if(function_exists("fsockopen")) 5652 { 5653 $url = @parse_url($url); 5654 if(!$url['host']) 5655 { 5656 return false; 5657 } 5658 if(!$url['port']) 5659 { 5660 $url['port'] = 80; 5661 } 5662 if(!$url['path']) 5663 { 5664 $url['path'] = "/"; 5665 } 5666 if($url['query']) 5667 { 5668 $url['path'] .= "?{$url['query']}"; 5669 } 5670 $fp = @fsockopen($url['host'], $url['port'], $error_no, $error, 10); 5671 @stream_set_timeout($fp, 10); 5672 if(!$fp) 5673 { 5674 return false; 5675 } 5676 $headers = array(); 5677 if(!empty($post_body)) 5678 { 5679 $headers[] = "POST {$url['path']} HTTP/1.0"; 5680 $headers[] = "Content-Length: ".strlen($post_body); 5681 $headers[] = "Content-Type: application/x-www-form-urlencoded"; 5682 } 5683 else 5684 { 5685 $headers[] = "GET {$url['path']} HTTP/1.0"; 5686 } 5687 5688 $headers[] = "Host: {$url['host']}"; 5689 $headers[] = "Connection: Close"; 5690 $headers[] = ''; 5691 5692 if(!empty($post_body)) 5693 { 5694 $headers[] = $post_body; 5695 } 5696 else 5697 { 5698 // If we have no post body, we need to add an empty element to make sure we've got \r\n\r\n before the (non-existent) body starts 5699 $headers[] = ''; 5700 } 5701 5702 $headers = implode("\r\n", $headers); 5703 if(!@fwrite($fp, $headers)) 5704 { 5705 return false; 5706 } 5707 while(!feof($fp)) 5708 { 5709 $data .= fgets($fp, 12800); 5710 } 5711 fclose($fp); 5712 $data = explode("\r\n\r\n", $data, 2); 5713 return $data[1]; 5714 } 5715 else if(empty($post_data)) 5716 { 5717 return @implode("", @file($url)); 5718 } 5719 else 5720 { 5721 return false; 5722 } 5723 } 5724 5725 /** 5726 * Checks if a particular user is a super administrator. 5727 * 5728 * @param int The user ID to check against the list of super admins 5729 * @return boolean True if a super admin, false if not 5730 */ 5731 function is_super_admin($uid) 5732 { 5733 global $mybb; 5734 5735 $mybb->config['super_admins'] = str_replace(" ", "", $mybb->config['super_admins']); 5736 if(my_strpos(",{$mybb->config['super_admins']},", ",{$uid},") === false) 5737 { 5738 return false; 5739 } 5740 else 5741 { 5742 return true; 5743 } 5744 } 5745 5746 /** 5747 * Split a string based on the specified delimeter, ignoring said delimeter in escaped strings. 5748 * Ex: the "quick brown fox" jumped, could return 1 => the, 2 => quick brown fox, 3 => jumped 5749 * 5750 * @param string The delimeter to split by 5751 * @param string The string to split 5752 * @param string The escape character or string if we have one. 5753 * @return array Array of split string 5754 */ 5755 function escaped_explode($delimeter, $string, $escape="") 5756 { 5757 $strings = array(); 5758 $original = $string; 5759 $in_escape = false; 5760 if($escape) 5761 { 5762 if(is_array($escape)) 5763 { 5764 function escaped_explode_escape($string) 5765 { 5766 return preg_quote($string, "#"); 5767 } 5768 $escape_preg = "(".implode("|", array_map("escaped_explode_escape", $escape)).")"; 5769 } 5770 else 5771 { 5772 $escape_preg = preg_quote($escape, "#"); 5773 } 5774 $quoted_strings = preg_split("#(?<!\\\){$escape_preg}#", $string); 5775 } 5776 else 5777 { 5778 $quoted_strings = array($string); 5779 } 5780 foreach($quoted_strings as $string) 5781 { 5782 if($string != "") 5783 { 5784 if($in_escape) 5785 { 5786 $strings[] = trim($string); 5787 } 5788 else 5789 { 5790 $split_strings = explode($delimeter, $string); 5791 foreach($split_strings as $string) 5792 { 5793 if($string == "") continue; 5794 $strings[] = trim($string); 5795 } 5796 } 5797 } 5798 $in_escape = !$in_escape; 5799 } 5800 if(!count($strings)) 5801 { 5802 return $original; 5803 } 5804 return $strings; 5805 } 5806 5807 /** 5808 * Fetch an IPv4 long formatted range for searching IPv4 IP addresses. 5809 * 5810 * @param string The IP address to convert to a range based LONG 5811 * @rturn mixed If a full IP address is provided, the ip2long equivalent, otherwise an array of the upper & lower extremities of the IP 5812 */ 5813 function fetch_longipv4_range($ip) 5814 { 5815 $ip_bits = explode(".", $ip); 5816 $ip_string1 = $ip_string2 = ""; 5817 5818 if($ip == "*") 5819 { 5820 return array(my_ip2long('128.0.0.0'), my_ip2long('127.255.255.255')); 5821 } 5822 5823 if(strpos($ip, ".*") === false) 5824 { 5825 $ip = str_replace("*", "", $ip); 5826 if(count($ip_bits) == 4) 5827 { 5828 return my_ip2long($ip); 5829 } 5830 else 5831 { 5832 return array(my_ip2long($ip.".0"), my_ip2long($ip.".255")); 5833 } 5834 } 5835 // Wildcard based IP provided 5836 else 5837 { 5838 $sep = ""; 5839 foreach($ip_bits as $piece) 5840 { 5841 if($piece == "*") 5842 { 5843 $ip_string1 .= $sep."0"; 5844 $ip_string2 .= $sep."255"; 5845 } 5846 else 5847 { 5848 $ip_string1 .= $sep.$piece; 5849 $ip_string2 .= $sep.$piece; 5850 } 5851 $sep = "."; 5852 } 5853 return array(my_ip2long($ip_string1), my_ip2long($ip_string2)); 5854 } 5855 } 5856 5857 /** 5858 * Fetch a list of ban times for a user account. 5859 * 5860 * @return array Array of ban times 5861 */ 5862 function fetch_ban_times() 5863 { 5864 global $plugins, $lang; 5865 5866 // Days-Months-Years 5867 $ban_times = array( 5868 "1-0-0" => "1 {$lang->day}", 5869 "2-0-0" => "2 {$lang->days}", 5870 "3-0-0" => "3 {$lang->days}", 5871 "4-0-0" => "4 {$lang->days}", 5872 "5-0-0" => "5 {$lang->days}", 5873 "6-0-0" => "6 {$lang->days}", 5874 "7-0-0" => "1 {$lang->week}", 5875 "14-0-0" => "2 {$lang->weeks}", 5876 "21-0-0" => "3 {$lang->weeks}", 5877 "0-1-0" => "1 {$lang->month}", 5878 "0-2-0" => "2 {$lang->months}", 5879 "0-3-0" => "3 {$lang->months}", 5880 "0-4-0" => "4 {$lang->months}", 5881 "0-5-0" => "5 {$lang->months}", 5882 "0-6-0" => "6 {$lang->months}", 5883 "0-0-1" => "1 {$lang->year}", 5884 "0-0-2" => "2 {$lang->years}" 5885 ); 5886 5887 $ban_times = $plugins->run_hooks("functions_fetch_ban_times", $ban_times); 5888 5889 $ban_times['---'] = $lang->permanent; 5890 return $ban_times; 5891 } 5892 5893 /** 5894 * Format a ban length in to a UNIX timestamp. 5895 * 5896 * @param string The ban length string 5897 * @param int The optional UNIX timestamp, if 0, current time is used. 5898 * @return int The UNIX timestamp when the ban will be lifted 5899 */ 5900 function ban_date2timestamp($date, $stamp=0) 5901 { 5902 if($stamp == 0) 5903 { 5904 $stamp = TIME_NOW; 5905 } 5906 $d = explode('-', $date); 5907 $nowdate = date("H-j-n-Y", $stamp); 5908 $n = explode('-', $nowdate); 5909 $n[1] += $d[0]; 5910 $n[2] += $d[1]; 5911 $n[3] += $d[2]; 5912 return mktime(date("G"), date("i"), 0, $n[2], $n[1], $n[3]); 5913 } 5914 5915 /** 5916 * Expire old warnings in the database. 5917 * 5918 */ 5919 function expire_warnings() 5920 { 5921 global $db; 5922 5923 $users = array(); 5924 5925 $query = $db->query(" 5926 SELECT w.wid, w.uid, w.points, u.warningpoints 5927 FROM ".TABLE_PREFIX."warnings w 5928 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=w.uid) 5929 WHERE expires<".TIME_NOW." AND expires!=0 AND expired!=1 5930 "); 5931 while($warning = $db->fetch_array($query)) 5932 { 5933 $updated_warning = array( 5934 "expired" => 1 5935 ); 5936 $db->update_query("warnings", $updated_warning, "wid='{$warning['wid']}'"); 5937 5938 if(array_key_exists($warning['uid'], $users)) 5939 { 5940 $users[$warning['uid']] -= $warning['points']; 5941 } 5942 else 5943 { 5944 $users[$warning['uid']] = $warning['warningpoints']-$warning['points']; 5945 } 5946 } 5947 5948 foreach($users as $uid => $warningpoints) 5949 { 5950 if($warningpoints < 0) 5951 { 5952 $warningpoints = 0; 5953 } 5954 5955 $updated_user = array( 5956 "warningpoints" => intval($warningpoints) 5957 ); 5958 $db->update_query("users", $updated_user, "uid='".intval($uid)."'"); 5959 } 5960 } 5961 5962 /** 5963 * Custom chmod function to fix problems with hosts who's server configurations screw up umasks 5964 * 5965 * @param string The file to chmod 5966 * @param string The mode to chmod(i.e. 0666) 5967 */ 5968 function my_chmod($file, $mode) 5969 { 5970 // Passing $mode as an octal number causes strlen and substr to return incorrect values. Instead pass as a string 5971 if(substr($mode, 0, 1) != '0' || strlen($mode) !== 4) 5972 { 5973 return false; 5974 } 5975 $old_umask = umask(0); 5976 5977 // We convert the octal string to a decimal number because passing a octal string doesn't work with chmod 5978 // and type casting subsequently removes the prepended 0 which is needed for octal numbers 5979 $result = chmod($file, octdec($mode)); 5980 umask($old_umask); 5981 return $result; 5982 } 5983 5984 /** 5985 * Custom rmdir function to loop through an entire directory and delete all files/folders within 5986 * 5987 * @param string The path to the directory 5988 * @param array Any files you wish to ignore (optional) 5989 */ 5990 function my_rmdir_recursive($path, $ignore=array()) 5991 { 5992 global $orig_dir; 5993 5994 if(!isset($orig_dir)) 5995 { 5996 $orig_dir = $path; 5997 } 5998 5999 if(@is_dir($path) && !@is_link($path)) 6000 { 6001 if($dh = @opendir($path)) 6002 { 6003 while(($file = @readdir($dh)) !== false) 6004 { 6005 if($file == '.' || $file == '..' || $file == '.svn' || in_array($path.'/'.$file, $ignore) || !my_rmdir_recursive($path.'/'.$file)) 6006 { 6007 continue; 6008 } 6009 } 6010 @closedir($dh); 6011 } 6012 6013 // Are we done? Don't delete the main folder too and return true 6014 if($path == $orig_dir) 6015 { 6016 return true; 6017 } 6018 6019 return @rmdir($path); 6020 } 6021 6022 return @unlink($path); 6023 } 6024 6025 /** 6026 * Counts the number of subforums in a array([pid][disporder][fid]) starting from the pid 6027 * 6028 * @param array The array of forums 6029 * @return integer The number of sub forums 6030 */ 6031 function subforums_count($array) 6032 { 6033 $count = 0; 6034 foreach($array as $array2) 6035 { 6036 $count += count($array2); 6037 } 6038 6039 return $count; 6040 } 6041 6042 /** 6043 * Fix for PHP's ip2long to guarantee a 32-bit signed integer value is produced (this is aimed 6044 * at 64-bit versions of PHP) 6045 * 6046 * @param string The IP to convert 6047 * @return integer IP in 32-bit signed format 6048 */ 6049 function my_ip2long($ip) 6050 { 6051 $ip_long = ip2long($ip); 6052 6053 if(!$ip_long) 6054 { 6055 $ip_long = sprintf("%u", ip2long($ip)); 6056 6057 if(!$ip_long) 6058 { 6059 return 0; 6060 } 6061 } 6062 6063 if($ip_long >= 2147483648) // Won't occur on 32-bit PHP 6064 { 6065 $ip_long -= 4294967296; 6066 } 6067 6068 return $ip_long; 6069 } 6070 6071 /** 6072 * As above, fix for PHP's long2ip on 64-bit versions 6073 * 6074 * @param integer The IP to convert (will accept 64-bit IPs as well) 6075 * @return string IP in IPv4 format 6076 */ 6077 function my_long2ip($long) 6078 { 6079 // On 64-bit machines is_int will return true. On 32-bit it will return false 6080 if($long < 0 && is_int(2147483648)) 6081 { 6082 // We have a 64-bit system 6083 $long += 4294967296; 6084 } 6085 return long2ip($long); 6086 } 6087 6088 6089 /** 6090 * Processes a checksum list on MyBB files and returns a result set 6091 * 6092 * @param array The array of checksums and their corresponding files 6093 * @return array The bad files 6094 */ 6095 function verify_files($path=MYBB_ROOT, $count=0) 6096 { 6097 global $mybb, $checksums, $bad_verify_files; 6098 6099 // We don't need to check these types of files 6100 $ignore = array(".", "..", ".svn", "config.php", "settings.php", "Thumb.db", "config.default.php", "lock", "htaccess.txt", "logo.gif"); 6101 $ignore_ext = array("attach"); 6102 6103 if(substr($path, -1, 1) == "/") 6104 { 6105 $path = substr($path, 0, -1); 6106 } 6107 6108 if(!is_array($bad_verify_files)) 6109 { 6110 $bad_verify_files = array(); 6111 } 6112 6113 // Make sure that we're in a directory and it's not a symbolic link 6114 if(@is_dir($path) && !@is_link($path)) 6115 { 6116 if($dh = @opendir($path)) 6117 { 6118 // Loop through all the files/directories in this directory 6119 while(($file = @readdir($dh)) !== false) 6120 { 6121 if(in_array($file, $ignore) || in_array(get_extension($file), $ignore_ext)) 6122 { 6123 continue; 6124 } 6125 6126 // Recurse through the directory tree 6127 if(is_dir($path."/".$file)) 6128 { 6129 verify_files($path."/".$file, ($count+1)); 6130 continue; 6131 } 6132 6133 // We only need the last part of the path (from the MyBB directory to the file. i.e. inc/functions.php) 6134 $file_path = ".".str_replace(substr(MYBB_ROOT, 0, -1), "", $path)."/".$file; 6135 6136 // Does this file even exist in our official list? Perhaps it's a plugin 6137 if(array_key_exists($file_path, $checksums)) 6138 { 6139 $filename = $path."/".$file; 6140 $handle = fopen($filename, "rb"); 6141 $contents = ''; 6142 while(!feof($handle)) 6143 { 6144 $contents .= fread($handle, 8192); 6145 } 6146 fclose($handle); 6147 6148 $md5 = md5($contents); 6149 6150 // Does it match any of our hashes (unix/windows new lines taken into consideration with the hashes) 6151 if(!in_array($md5, $checksums[$file_path])) 6152 { 6153 $bad_verify_files[] = array("status" => "changed", "path" => $file_path); 6154 } 6155 } 6156 unset($checksums[$file_path]); 6157 } 6158 @closedir($dh); 6159 } 6160 } 6161 6162 if($count == 0) 6163 { 6164 if(!empty($checksums)) 6165 { 6166 foreach($checksums as $file_path => $hashes) 6167 { 6168 if(in_array(basename($file_path), $ignore)) 6169 { 6170 continue; 6171 } 6172 $bad_verify_files[] = array("status" => "missing", "path" => $file_path); 6173 } 6174 } 6175 } 6176 6177 // uh oh 6178 if($count == 0) 6179 { 6180 return $bad_verify_files; 6181 } 6182 } 6183 6184 /** 6185 * Returns a signed value equal to an integer 6186 * 6187 * @param int The integer 6188 * @return string The signed equivalent 6189 */ 6190 function signed($int) 6191 { 6192 if($int < 0) 6193 { 6194 return "$int"; 6195 } 6196 else 6197 { 6198 return "+$int"; 6199 } 6200 } 6201 6202 /** 6203 * Returns a securely generated seed for PHP's RNG (Random Number Generator) 6204 * 6205 * @param int Length of the seed bytes (8 is default. Provides good cryptographic variance) 6206 * @return int An integer equivalent of a secure hexadecimal seed 6207 */ 6208 function secure_seed_rng($count=8) 6209 { 6210 $output = ''; 6211 6212 // Try the unix/linux method 6213 if(@is_readable('/dev/urandom') && ($handle = @fopen('/dev/urandom', 'rb'))) 6214 { 6215 $output = @fread($handle, $count); 6216 @fclose($handle); 6217 } 6218 6219 // Didn't work? Do we still not have enough bytes? Use our own (less secure) rng generator 6220 if(strlen($output) < $count) 6221 { 6222 $output = ''; 6223 6224 // Close to what PHP basically uses internally to seed, but not quite. 6225 $unique_state = microtime().@getmypid(); 6226 6227 for($i = 0; $i < $count; $i += 16) 6228 { 6229 $unique_state = md5(microtime().$unique_state); 6230 $output .= pack('H*', md5($unique_state)); 6231 } 6232 } 6233 6234 // /dev/urandom and openssl will always be twice as long as $count. base64_encode will roughly take up 33% more space but crc32 will put it to 32 characters 6235 $output = hexdec(substr(dechex(crc32(base64_encode($output))), 0, $count)); 6236 6237 return $output; 6238 } 6239 6240 /** 6241 * Wrapper function for mt_rand. Automatically seeds using a secure seed once. 6242 * 6243 * @param int Optional lowest value to be returned (default: 0) 6244 * @param int Optional highest value to be returned (default: mt_getrandmax()) 6245 * @param boolean True forces it to reseed the RNG first 6246 * @return int An integer equivalent of a secure hexadecimal seed 6247 */ 6248 function my_rand($min=null, $max=null, $force_seed=false) 6249 { 6250 static $seeded = false; 6251 static $obfuscator = 0; 6252 6253 if($seeded == false || $force_seed == true) 6254 { 6255 mt_srand(secure_seed_rng()); 6256 $seeded = true; 6257 6258 $obfuscator = abs((int) secure_seed_rng()); 6259 6260 // Ensure that $obfuscator is <= mt_getrandmax() for 64 bit systems. 6261 if($obfuscator > mt_getrandmax()) 6262 { 6263 $obfuscator -= mt_getrandmax(); 6264 } 6265 } 6266 6267 if($min !== null && $max !== null) 6268 { 6269 $distance = $max - $min; 6270 if ($distance > 0) 6271 { 6272 return $min + (int)((float)($distance + 1) * (float)(mt_rand() ^ $obfuscator) / (mt_getrandmax() + 1)); 6273 } 6274 else 6275 { 6276 return mt_rand($min, $max); 6277 } 6278 } 6279 else 6280 { 6281 $val = mt_rand() ^ $obfuscator; 6282 return $val; 6283 } 6284 } 6285 6286 /** 6287 * More robust version of PHP's trim() function. It includes a list of UTF-16 blank characters 6288 * from http://kb.mozillazine.org/Network.IDN.blacklist_chars 6289 * 6290 * @param string The string to trim from 6291 * @param string Optional. The stripped characters can also be specified using the charlist parameter 6292 * @return string The trimmed string 6293 */ 6294 function trim_blank_chrs($string, $charlist=false) 6295 { 6296 $hex_chrs = array( 6297 0x20 => 1, 6298 0x09 => 1, 6299 0x0A => 1, 6300 0x0D => 1, 6301 0x0B => 1, 6302 0xAD => 1, 6303 0xA0 => 1, 6304 0xAD => 1, 6305 0xBF => 1, 6306 0x81 => 1, 6307 0x8D => 1, 6308 0x90 => 1, 6309 0x9D => 1, 6310 0xCC => array(0xB7 => 1, 0xB8 => 1), // \x{0337} or \x{0338} 6311 0xE1 => array(0x85 => array(0x9F => 1, 0xA0 => 1)), // \x{115F} or \x{1160} 6312 0xE2 => array(0x80 => array(0x80 => 1, 0x81 => 1, 0x82 => 1, 0x83 => 1, 0x84 => 1, 0x85 => 1, 0x86 => 1, 0x87 => 1, 0x88 => 1, 0x89 => 1, 0x8A => 1, 0x8B => 1, // \x{2000} to \x{200B} 6313 0xA8 => 1, 0xA9 => 1, 0xAA => 1, 0xAB => 1, 0xAC => 1, 0xAD => 1, 0xAE => 1, 0xAF => 1), // \x{2028} to \x{202F} 6314 0x81 => array(0x9F => 1)), // \x{205F} 6315 0xE3 => array(0x80 => array(0x80 => 1), // \x{3000} 6316 0x85 => array(0xA4 => 1)), // \x{3164} 6317 0xEF => array(0xBB => array(0xBF => 1), // \x{FEFF} 6318 0xBE => array(0xA0 => 1), // \x{FFA0} 6319 0xBF => array(0xB9 => 1, 0xBA => 1, 0xBB => 1)), // \x{FFF9} to \x{FFFB} 6320 ); 6321 6322 $hex_chrs_rev = array( 6323 0x20 => 1, 6324 0x09 => 1, 6325 0x0A => 1, 6326 0x0D => 1, 6327 0x0B => 1, 6328 0xA0 => array(0xC2 => 1), 6329 0xAD => array(0xC2 => 1), 6330 0xBF => array(0xC2 => 1), 6331 0x81 => array(0xC2 => 1), 6332 0x8D => array(0xC2 => 1), 6333 0x90 => array(0xC2 => 1), 6334 0x9D => array(0xC2 => 1), 6335 0xB8 => array(0xCC => 1), // \x{0338} 6336 0xB7 => array(0xCC => 1), // \x{0337} 6337 0xA0 => array(0x85 => array(0xE1 => 1)), // \x{1160} 6338 0x9F => array(0x85 => array(0xE1 => 1), // \x{115F} 6339 0x81 => array(0xE2 => 1)), // \x{205F} 6340 0x80 => array(0x80 => array(0xE3 => 1, 0xE2 => 1)), // \x{3000}, \x{2000} 6341 0x81 => array(0x80 => array(0xE2 => 1)), // \x{2001} 6342 0x82 => array(0x80 => array(0xE2 => 1)), // \x{2002} 6343 0x83 => array(0x80 => array(0xE2 => 1)), // \x{2003} 6344 0x84 => array(0x80 => array(0xE2 => 1)), // \x{2004} 6345 0x85 => array(0x80 => array(0xE2 => 1)), // \x{2005} 6346 0x86 => array(0x80 => array(0xE2 => 1)), // \x{2006} 6347 0x87 => array(0x80 => array(0xE2 => 1)), // \x{2007} 6348 0x88 => array(0x80 => array(0xE2 => 1)), // \x{2008} 6349 0x89 => array(0x80 => array(0xE2 => 1)), // \x{2009} 6350 0x8A => array(0x80 => array(0xE2 => 1)), // \x{200A} 6351 0x8B => array(0x80 => array(0xE2 => 1)), // \x{200B} 6352 0xA8 => array(0x80 => array(0xE2 => 1)), // \x{2028} 6353 0xA9 => array(0x80 => array(0xE2 => 1)), // \x{2029} 6354 0xAA => array(0x80 => array(0xE2 => 1)), // \x{202A} 6355 0xAB => array(0x80 => array(0xE2 => 1)), // \x{202B} 6356 0xAC => array(0x80 => array(0xE2 => 1)), // \x{202C} 6357 0xAD => array(0x80 => array(0xE2 => 1)), // \x{202D} 6358 0xAE => array(0x80 => array(0xE2 => 1)), // \x{202E} 6359 0xAF => array(0x80 => array(0xE2 => 1)), // \x{202F} 6360 0xA4 => array(0x85 => array(0xE3 => 1)), // \x{3164} 6361 0xBF => array(0xBB => array(0xEF => 1)), // \x{FEFF} 6362 0xA0 => array(0xBE => array(0xEF => 1)), // \x{FFA0} 6363 0xB9 => array(0xBF => array(0xEF => 1)), // \x{FFF9} 6364 0xBA => array(0xBF => array(0xEF => 1)), // \x{FFFA} 6365 0xBB => array(0xBF => array(0xEF => 1)), // \x{FFFB} 6366 ); 6367 6368 // Start from the beginning and work our way in 6369 do 6370 { 6371 // Check to see if we have matched a first character in our utf-16 array 6372 $offset = match_sequence($string, $hex_chrs); 6373 if(!$offset) 6374 { 6375 // If not, then we must have a "good" character and we don't need to do anymore processing 6376 break; 6377 } 6378 $string = substr($string, $offset); 6379 } 6380 while(++$i); 6381 6382 // Start from the end and work our way in 6383 $string = strrev($string); 6384 do 6385 { 6386 // Check to see if we have matched a first character in our utf-16 array 6387 $offset = match_sequence($string, $hex_chrs_rev); 6388 if(!$offset) 6389 { 6390 // If not, then we must have a "good" character and we don't need to do anymore processing 6391 break; 6392 } 6393 $string = substr($string, $offset); 6394 } 6395 while(++$i); 6396 $string = strrev($string); 6397 6398 if($charlist !== false) 6399 { 6400 $string = trim($string, $charlist); 6401 } 6402 else 6403 { 6404 $string = trim($string); 6405 } 6406 6407 return $string; 6408 } 6409 6410 function match_sequence($string, $array, $i=0, $n=0) 6411 { 6412 if($string === "") 6413 { 6414 return 0; 6415 } 6416 6417 $ord = ord($string[$i]); 6418 if(array_key_exists($ord, $array)) 6419 { 6420 $level = $array[$ord]; 6421 ++$n; 6422 if(is_array($level)) 6423 { 6424 ++$i; 6425 return match_sequence($string, $level, $i, $n); 6426 } 6427 return $n; 6428 } 6429 6430 return 0; 6431 } 6432 6433 /** 6434 * Obtain the version of GD installed. 6435 * 6436 * @return float Version of GD 6437 */ 6438 function gd_version() 6439 { 6440 static $gd_version; 6441 6442 if($gd_version) 6443 { 6444 return $gd_version; 6445 } 6446 if(!extension_loaded('gd')) 6447 { 6448 return; 6449 } 6450 6451 if(function_exists("gd_info")) 6452 { 6453 $gd_info = gd_info(); 6454 preg_match('/\d/', $gd_info['GD Version'], $gd); 6455 $gd_version = $gd[0]; 6456 } 6457 else 6458 { 6459 ob_start(); 6460 phpinfo(8); 6461 $info = ob_get_contents(); 6462 ob_end_clean(); 6463 $info = stristr($info, 'gd version'); 6464 preg_match('/\d/', $info, $gd); 6465 $gd_version = $gd[0]; 6466 } 6467 6468 return $gd_version; 6469 } 6470 6471 /** 6472 * Handles 4 byte UTF-8 characters. 6473 * 6474 * This can be used to either reject strings which contain 4 byte UTF-8 6475 * characters, or replace them with question marks. This is limited to UTF-8 6476 * collated databases using MySQL. 6477 * 6478 * Original: http://www.avidheap.org/2013/a-quick-way-to-normalize-a-utf8-string-when-your-mysql-database-is-not-utf8mb4 6479 * 6480 * @param string The string to be checked. 6481 * @param bool If false don't return the string, only the boolean result. 6482 * @return mixed Return a string if the second parameter is true, boolean otherwise. 6483 */ 6484 function utf8_handle_4byte_string($input, $return=true) 6485 { 6486 global $config; 6487 6488 if($config['database']['type'] != 'mysql' && $config['database']['type'] != 'mysqli') 6489 { 6490 if($return == true) 6491 { 6492 return $input; 6493 } 6494 return true; 6495 } 6496 6497 $contains_4bytes = false; 6498 if(!empty($input)) 6499 { 6500 $utf8_2byte = 0xC0 /*1100 0000*/; 6501 $utf8_2byte_bmask = 0xE0 /*1110 0000*/; 6502 6503 $utf8_3byte = 0xE0 /*1110 0000*/; 6504 $utf8_3byte_bmask = 0XF0 /*1111 0000*/; 6505 6506 $utf8_4byte = 0xF0 /*1111 0000*/; 6507 $utf8_4byte_bmask = 0xF8 /*1111 1000*/; 6508 6509 $sanitized = ""; 6510 $len = strlen($input); 6511 for($i = 0; $i < $len; ++$i) 6512 { 6513 $mb_char = $input[$i]; // Potentially a multibyte sequence 6514 $byte = ord($mb_char); 6515 if(($byte & $utf8_2byte_bmask) == $utf8_2byte) 6516 { 6517 $mb_char .= $input[++$i]; 6518 } 6519 elseif(($byte & $utf8_3byte_bmask) == $utf8_3byte) 6520 { 6521 $mb_char .= $input[++$i]; 6522 $mb_char .= $input[++$i]; 6523 } 6524 elseif(($byte & $utf8_4byte_bmask) == $utf8_4byte) 6525 { 6526 $contains_4bytes = true; 6527 // Replace with ? to avoid MySQL exception 6528 $mb_char = '?'; 6529 $i += 3; 6530 } 6531 6532 $sanitized .= $mb_char; 6533 6534 if($contains_4bytes == true && $return == false) 6535 { 6536 return false; 6537 } 6538 } 6539 6540 $input = $sanitized; 6541 } 6542 6543 if($contains_4bytes == false && $return == false) 6544 { 6545 return true; 6546 } 6547 return $input; 6548 } 6549 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Oct 8 19:19:50 2013 | Cross-referenced by PHPXref 0.7.1 |