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