PageRenderTime 110ms CodeModel.GetById 4ms app.highlight 77ms RepoModel.GetById 1ms app.codeStats 2ms

/sources/functions.php

http://github.com/usebb/UseBB
PHP | 3682 lines | 1841 code | 884 blank | 957 comment | 475 complexity | b4d531bf6e256716d2bacdf4ff36d2ac MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/*
   4	Copyright (C) 2003-2012 UseBB Team
   5	http://www.usebb.net
   6	
   7	$Id$
   8	
   9	This file is part of UseBB.
  10	
  11	UseBB is free software; you can redistribute it and/or modify
  12	it under the terms of the GNU General Public License as published by
  13	the Free Software Foundation; either version 2 of the License, or
  14	(at your option) any later version.
  15	
  16	UseBB is distributed in the hope that it will be useful,
  17	but WITHOUT ANY WARRANTY; without even the implied warranty of
  18	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19	GNU General Public License for more details.
  20	
  21	You should have received a copy of the GNU General Public License
  22	along with UseBB; if not, write to the Free Software
  23	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  24*/
  25
  26/**
  27 * Functions
  28 *
  29 * Contains all kinds of procedural functions and the functions class.
  30 *
  31 * @author	UseBB Team
  32 * @link	http://www.usebb.net
  33 * @license	GPL-2
  34 * @version	$Revision$
  35 * @copyright	Copyright (C) 2003-2012 UseBB Team
  36 * @package	UseBB
  37 * @subpackage Core
  38 */
  39
  40//
  41// Die when called directly in browser
  42//
  43if ( !defined('INCLUDED') )
  44	exit();
  45
  46/**
  47 * Debug output function
  48 *
  49 * Takes variable number of arguments that get printed out to template.
  50 */
  51function usebb_debug_output() {
  52	
  53	global $template;
  54
  55	$numargs = func_num_args();
  56
  57	if ( $template == null || USEBB_IS_PROD_ENV || $numargs == 0 )
  58		return;
  59	
  60	$values = array_map('unhtml', array_map('print_r', func_get_args(), array_fill(0, $numargs, true)));
  61	$template->add_raw_content('<pre>'.implode('<br />', $values).'</pre>');
  62
  63}
  64
  65/**
  66 * Callback for array_walk
  67 *
  68 * Will add slashes to and trim the value.
  69 * Third parameter disables addslashes (magic_quotes_gpc on)
  70 */
  71function usebb_clean_input_value(&$value, $key, $mq=false) {
  72	
  73	if ( is_array($value) ) {
  74		
  75		array_walk($value, 'usebb_clean_input_value', $mq);
  76		
  77	} else {
  78		
  79		if ( !$mq )
  80			$value = addslashes($value);
  81		
  82		$value = trim($value);
  83		
  84	}
  85
  86}
  87
  88/**
  89 * Callback for array_walk
  90 *
  91 * Will add slashes to the value.
  92 */
  93function usebb_clean_db_value(&$value, $key) {
  94	
  95	if ( is_array($value) )
  96		array_walk($value, 'usebb_clean_db_value');
  97	else
  98		$value = addslashes($value);
  99	
 100}
 101
 102/**
 103 * Check whether the string contains HTML entities.
 104 *
 105 * @param string $string String to check
 106 * @param bool $num_only Look for &#...; only
 107 * @returns bool Contains entities
 108 */
 109function contains_entities($string, $num_only=false) {
 110	
 111	return preg_match(( $num_only ? '#&\#[^;]+;#' : '#&\#?[^;]+;#' ), $string);
 112	
 113}
 114
 115/**
 116 * Resets the named entities to the code ones.
 117 *
 118 * Code from the Drupal Atom module, patch by stefanor (at Drupal.org).
 119 * @link http://drupal.org/node/579286
 120 *
 121 * @param string $string String
 122 * @returns string String
 123 */
 124function named_entities_to_numeric($string) {
 125	
 126  $table = array(
 127    "&nbsp;"     => "&#160;",
 128    "&iexcl;"    => "&#161;",
 129    "&cent;"     => "&#162;",
 130    "&pound;"    => "&#163;",
 131    "&curren;"   => "&#164;",
 132    "&yen;"      => "&#165;",
 133    "&brvbar;"   => "&#166;",
 134    "&sect;"     => "&#167;",
 135    "&uml;"      => "&#168;",
 136    "&copy;"     => "&#169;",
 137    "&ordf;"     => "&#170;",
 138    "&laquo;"    => "&#171;",
 139    "&not;"      => "&#172;",
 140    "&shy;"      => "&#173;",
 141    "&reg;"      => "&#174;",
 142    "&macr;"     => "&#175;",
 143    "&deg;"      => "&#176;",
 144    "&plusmn;"   => "&#177;",
 145    "&sup2;"     => "&#178;",
 146    "&sup3;"     => "&#179;",
 147    "&acute;"    => "&#180;",
 148    "&micro;"    => "&#181;",
 149    "&para;"     => "&#182;",
 150    "&middot;"   => "&#183;",
 151    "&cedil;"    => "&#184;",
 152    "&sup1;"     => "&#185;",
 153    "&ordm;"     => "&#186;",
 154    "&raquo;"    => "&#187;",
 155    "&frac14;"   => "&#188;",
 156    "&frac12;"   => "&#189;",
 157    "&frac34;"   => "&#190;",
 158    "&iquest;"   => "&#191;",
 159    "&Agrave;"   => "&#192;",
 160    "&Aacute;"   => "&#193;",
 161    "&Acirc;"    => "&#194;",
 162    "&Atilde;"   => "&#195;",
 163    "&Auml;"     => "&#196;",
 164    "&Aring;"    => "&#197;",
 165    "&AElig;"    => "&#198;",
 166    "&Ccedil;"   => "&#199;",
 167    "&Egrave;"   => "&#200;",
 168    "&Eacute;"   => "&#201;",
 169    "&Ecirc;"    => "&#202;",
 170    "&Euml;"     => "&#203;",
 171    "&Igrave;"   => "&#204;",
 172    "&Iacute;"   => "&#205;",
 173    "&Icirc;"    => "&#206;",
 174    "&Iuml;"     => "&#207;",
 175    "&ETH;"      => "&#208;",
 176    "&Ntilde;"   => "&#209;",
 177    "&Ograve;"   => "&#210;",
 178    "&Oacute;"   => "&#211;",
 179    "&Ocirc;"    => "&#212;",
 180    "&Otilde;"   => "&#213;",
 181    "&Ouml;"     => "&#214;",
 182    "&times;"    => "&#215;",
 183    "&Oslash;"   => "&#216;",
 184    "&Ugrave;"   => "&#217;",
 185    "&Uacute;"   => "&#218;",
 186    "&Ucirc;"    => "&#219;",
 187    "&Uuml;"     => "&#220;",
 188    "&Yacute;"   => "&#221;",
 189    "&THORN;"    => "&#222;",
 190    "&szlig;"    => "&#223;",
 191    "&agrave;"   => "&#224;",
 192    "&aacute;"   => "&#225;",
 193    "&acirc;"    => "&#226;",
 194    "&atilde;"   => "&#227;",
 195    "&auml;"     => "&#228;",
 196    "&aring;"    => "&#229;",
 197    "&aelig;"    => "&#230;",
 198    "&ccedil;"   => "&#231;",
 199    "&egrave;"   => "&#232;",
 200    "&eacute;"   => "&#233;",
 201    "&ecirc;"    => "&#234;",
 202    "&euml;"     => "&#235;",
 203    "&igrave;"   => "&#236;",
 204    "&iacute;"   => "&#237;",
 205    "&icirc;"    => "&#238;",
 206    "&iuml;"     => "&#239;",
 207    "&eth;"      => "&#240;",
 208    "&ntilde;"   => "&#241;",
 209    "&ograve;"   => "&#242;",
 210    "&oacute;"   => "&#243;",
 211    "&ocirc;"    => "&#244;",
 212    "&otilde;"   => "&#245;",
 213    "&ouml;"     => "&#246;",
 214    "&divide;"   => "&#247;",
 215    "&oslash;"   => "&#248;",
 216    "&ugrave;"   => "&#249;",
 217    "&uacute;"   => "&#250;",
 218    "&ucirc;"    => "&#251;",
 219    "&uuml;"     => "&#252;",
 220    "&yacute;"   => "&#253;",
 221    "&thorn;"    => "&#254;",
 222    "&yuml;"     => "&#255;",
 223    "&fnof;"     => "&#402;",
 224    "&Alpha;"    => "&#913;",
 225    "&Beta;"     => "&#914;",
 226    "&Gamma;"    => "&#915;",
 227    "&Delta;"    => "&#916;",
 228    "&Epsilon;"  => "&#917;",
 229    "&Zeta;"     => "&#918;",
 230    "&Eta;"      => "&#919;",
 231    "&Theta;"    => "&#920;",
 232    "&Iota;"     => "&#921;",
 233    "&Kappa;"    => "&#922;",
 234    "&Lambda;"   => "&#923;",
 235    "&Mu;"       => "&#924;",
 236    "&Nu;"       => "&#925;",
 237    "&Xi;"       => "&#926;",
 238    "&Omicron;"  => "&#927;",
 239    "&Pi;"       => "&#928;",
 240    "&Rho;"      => "&#929;",
 241    "&Sigma;"    => "&#931;",
 242    "&Tau;"      => "&#932;",
 243    "&Upsilon;"  => "&#933;",
 244    "&Phi;"      => "&#934;",
 245    "&Chi;"      => "&#935;",
 246    "&Psi;"      => "&#936;",
 247    "&Omega;"    => "&#937;",
 248    "&alpha;"    => "&#945;",
 249    "&beta;"     => "&#946;",
 250    "&gamma;"    => "&#947;",
 251    "&delta;"    => "&#948;",
 252    "&epsilon;"  => "&#949;",
 253    "&zeta;"     => "&#950;",
 254    "&eta;"      => "&#951;",
 255    "&theta;"    => "&#952;",
 256    "&iota;"     => "&#953;",
 257    "&kappa;"    => "&#954;",
 258    "&lambda;"   => "&#955;",
 259    "&mu;"       => "&#956;",
 260    "&nu;"       => "&#957;",
 261    "&xi;"       => "&#958;",
 262    "&omicron;"  => "&#959;",
 263    "&pi;"       => "&#960;",
 264    "&rho;"      => "&#961;",
 265    "&sigmaf;"   => "&#962;",
 266    "&sigma;"    => "&#963;",
 267    "&tau;"      => "&#964;",
 268    "&upsilon;"  => "&#965;",
 269    "&phi;"      => "&#966;",
 270    "&chi;"      => "&#967;",
 271    "&psi;"      => "&#968;",
 272    "&omega;"    => "&#969;",
 273    "&thetasym;" => "&#977;",
 274    "&upsih;"    => "&#978;",
 275    "&piv;"      => "&#982;",
 276    "&bull;"     => "&#8226;",
 277    "&hellip;"   => "&#8230;",
 278    "&prime;"    => "&#8242;",
 279    "&Prime;"    => "&#8243;",
 280    "&oline;"    => "&#8254;",
 281    "&frasl;"    => "&#8260;",
 282    "&weierp;"   => "&#8472;",
 283    "&image;"    => "&#8465;",
 284    "&real;"     => "&#8476;",
 285    "&trade;"    => "&#8482;",
 286    "&alefsym;"  => "&#8501;",
 287    "&larr;"     => "&#8592;",
 288    "&uarr;"     => "&#8593;",
 289    "&rarr;"     => "&#8594;",
 290    "&darr;"     => "&#8595;",
 291    "&harr;"     => "&#8596;",
 292    "&crarr;"    => "&#8629;",
 293    "&lArr;"     => "&#8656;",
 294    "&uArr;"     => "&#8657;",
 295    "&rArr;"     => "&#8658;",
 296    "&dArr;"     => "&#8659;",
 297    "&hArr;"     => "&#8660;",
 298    "&forall;"   => "&#8704;",
 299    "&part;"     => "&#8706;",
 300    "&exist;"    => "&#8707;",
 301    "&empty;"    => "&#8709;",
 302    "&nabla;"    => "&#8711;",
 303    "&isin;"     => "&#8712;",
 304    "&notin;"    => "&#8713;",
 305    "&ni;"       => "&#8715;",
 306    "&prod;"     => "&#8719;",
 307    "&sum;"      => "&#8721;",
 308    "&minus;"    => "&#8722;",
 309    "&lowast;"   => "&#8727;",
 310    "&radic;"    => "&#8730;",
 311    "&prop;"     => "&#8733;",
 312    "&infin;"    => "&#8734;",
 313    "&ang;"      => "&#8736;",
 314    "&and;"      => "&#8743;",
 315    "&or;"       => "&#8744;",
 316    "&cap;"      => "&#8745;",
 317    "&cup;"      => "&#8746;",
 318    "&int;"      => "&#8747;",
 319    "&there4;"   => "&#8756;",
 320    "&sim;"      => "&#8764;",
 321    "&cong;"     => "&#8773;",
 322    "&asymp;"    => "&#8776;",
 323    "&ne;"       => "&#8800;",
 324    "&equiv;"    => "&#8801;",
 325    "&le;"       => "&#8804;",
 326    "&ge;"       => "&#8805;",
 327    "&sub;"      => "&#8834;",
 328    "&sup;"      => "&#8835;",
 329    "&nsub;"     => "&#8836;",
 330    "&sube;"     => "&#8838;",
 331    "&supe;"     => "&#8839;",
 332    "&oplus;"    => "&#8853;",
 333    "&otimes;"   => "&#8855;",
 334    "&perp;"     => "&#8869;",
 335    "&sdot;"     => "&#8901;",
 336    "&lceil;"    => "&#8968;",
 337    "&rceil;"    => "&#8969;",
 338    "&lfloor;"   => "&#8970;",
 339    "&rfloor;"   => "&#8971;",
 340    "&lang;"     => "&#9001;",
 341    "&rang;"     => "&#9002;",
 342    "&loz;"      => "&#9674;",
 343    "&spades;"   => "&#9824;",
 344    "&clubs;"    => "&#9827;",
 345    "&hearts;"   => "&#9829;",
 346    "&diams;"    => "&#9830;",
 347    "&OElig;"    => "&#338;",
 348    "&oelig;"    => "&#339;",
 349    "&Scaron;"   => "&#352;",
 350    "&scaron;"   => "&#353;",
 351    "&Yuml;"     => "&#376;",
 352    "&circ;"     => "&#710;",
 353    "&tilde;"    => "&#732;",
 354    "&ensp;"     => "&#8194;",
 355    "&emsp;"     => "&#8195;",
 356    "&thinsp;"   => "&#8201;",
 357    "&zwnj;"     => "&#8204;",
 358    "&zwj;"      => "&#8205;",
 359    "&lrm;"      => "&#8206;",
 360    "&rlm;"      => "&#8207;",
 361    "&ndash;"    => "&#8211;",
 362    "&mdash;"    => "&#8212;",
 363    "&lsquo;"    => "&#8216;",
 364    "&rsquo;"    => "&#8217;",
 365    "&sbquo;"    => "&#8218;",
 366    "&ldquo;"    => "&#8220;",
 367    "&rdquo;"    => "&#8221;",
 368    "&bdquo;"    => "&#8222;",
 369    "&dagger;"   => "&#8224;",
 370    "&Dagger;"   => "&#8225;",
 371    "&permil;"   => "&#8240;",
 372    "&lsaquo;"   => "&#8249;",
 373    "&rsaquo;"   => "&#8250;",
 374    "&euro;"     => "&#8364;",
 375  );
 376
 377  return strtr($string, $table);
 378
 379}
 380
 381/**
 382 * Disable HTML in a string without disabling entities
 383 *
 384 * @param string $string String to un-HTML
 385 * @param bool $rss_mode Do hexadecimal escaping of &, < and > ONLY
 386 * @returns string Parsed $string
 387 */
 388function unhtml($string, $rss_mode=false) {
 389	
 390	$string = htmlspecialchars($string);
 391	
 392	//
 393	// Code which is necessary to not break numeric entities (quirky support for strange encodings on a page).
 394	// Broken entities (without trailing ;) at string end are stripped since they break XML well-formedness.
 395	//
 396	if ( strpos($string, '&') !== false )
 397		$string = preg_replace(array('#&amp;\#([0-9]+)#', '#&\#?[a-z0-9]+$#'), array('&#\\1', ''), $string);
 398	
 399	//
 400	// RSS mode
 401	//
 402	if ( $rss_mode )
 403		$string = named_entities_to_numeric($string);
 404	
 405	return $string;
 406	
 407}
 408
 409/**
 410 * Gives the length of a string and counts a HTML entitiy as one character.
 411 *
 412 * @param string $string String to find length of
 413 * @returns int Length of $string
 414 */
 415function entities_strlen($string) {
 416	
 417	if ( strpos($string, '&') !== false )
 418		$string = preg_replace('#&\#?[^;]+;#', '.', $string);
 419	
 420	return strlen($string);
 421	
 422}
 423
 424/**
 425 * Right trim a string to $length characters, keeping entities as one character.
 426 *
 427 * @param string $string String to trim
 428 * @param int $length Length of new string
 429 * @returns string Trimmed string
 430 */
 431function entities_rtrim($string, $length) {
 432	
 433	if ( function_exists('mb_language') && mb_language() != 'neutral') {
 434		
 435		$strlen = 'mb_strlen';
 436		$substr = 'mb_substr';
 437		
 438	} else {
 439		
 440		$strlen = 'strlen';
 441		$substr = 'substr';
 442		
 443	}
 444	
 445	if ( strpos($string, '&') === false )
 446		return $substr($string, 0, $length);
 447	
 448	$new_string = '';
 449	$new_length = $pos = 0;
 450	$entity_open = false;
 451	
 452	while ( $pos < $strlen($string) && ( $new_length < $length || $entity_open ) ) {
 453		
 454		$char = $substr($string, $pos, 1);
 455		
 456		if ( $char == '&' ) {
 457			
 458			$entity_open = true;
 459			
 460		} elseif ( $char == ';' && $entity_open ) {
 461			
 462			$entity_open = false;
 463			$new_length++;
 464			
 465		} elseif ( !$entity_open ) {
 466			
 467			$new_length++;
 468			
 469		}
 470		
 471		$new_string .= $char;
 472		$pos++;
 473		
 474	}
 475	
 476	return $new_string;
 477	
 478}
 479
 480/**
 481 * Check if a variable contains a valid integer.
 482 * If so, correct it (intval).
 483 *
 484 * @param string $string String to check
 485 * @returns bool Contains valid integer
 486 */
 487function valid_int(&$string) {
 488	
 489	if ( $string == strval(intval($string)) ) {
 490		
 491		$string = (int) $string;
 492		
 493		return true;
 494		
 495	} else {
 496		
 497		return false;
 498		
 499	}
 500	
 501}
 502
 503/**
 504 * checkdnsrr replacement for Windows
 505 *
 506 * @author Zend.com
 507 * @link http://www.zend.com/codex.php?id=370&single=1
 508 * @param string $host host
 509 * @param string $type type
 510 * @returns bool Contains valid integer
 511 */
 512function checkdnsrr_win($host, $type='') {
 513	
 514	$types = array(
 515		'A',
 516		'MX',
 517		'NS',
 518		'SOA',
 519		'PTR',
 520		'CNAME',
 521		'AAAA',
 522		'A6',
 523		'SRV',
 524		'NAPTR',
 525		'ANY'
 526	);
 527	$type = ( !empty($type) && in_array($type, $types) ) ? $type : 'MX';
 528	
 529	$output = array();
 530	exec('nslookup -type='.$type.' '.$host, $output);
 531	
 532	$host_len = strlen($host);
 533	foreach ( $output as $line ) {
 534		
 535		if ( !strncasecmp($line, $host, $host_len) )
 536			return true;
 537		
 538	}
 539	
 540	return false;
 541	
 542}
 543
 544/**
 545 * Functions
 546 *
 547 * All kinds of functions used everywhere.
 548 *
 549 * @author	UseBB Team
 550 * @link	http://www.usebb.net
 551 * @license	GPL-2
 552 * @version	$Revision$
 553 * @copyright	Copyright (C) 2003-2012 UseBB Team
 554 * @package	UseBB
 555 * @subpackage Core
 556 */
 557class functions {
 558	
 559	/**#@+
 560	 * @access private
 561	 */
 562	var $board_config = array();
 563	var $board_config_original = array();
 564	var $board_config_defined = array();
 565	var $statistics = array();
 566	var $languages = array();
 567	var $language_sections = array();
 568	var $mod_auth;
 569	var $badwords;
 570	var $updated_forums;
 571	var $available = array('templates' => array(), 'languages' => array());
 572	var $db_tables = array();
 573	var $server_load;
 574	var $is_mbstring;
 575	var $date_format_from_db = FALSE;
 576	/**#@-*/
 577	
 578	/**
 579	 * @access private
 580	 */
 581	function usebb_die($errno, $error, $file, $line) {
 582		
 583		global $db, $dbs, $template, $session;
 584		
 585		//
 586		// Ignore the ones we don't want
 587		//
 588		if ( ($errno & error_reporting()) == 0 )
 589			return;
 590		
 591		//
 592		// Ignore certain messages
 593		//
 594		foreach ( array(
 595			// Might be disabled
 596			'ini_set', 'ini_get', 'exec()',
 597			// Available since PHP 5.0.0. Removed in PHP 5.3.0
 598			'ze1_compatibility_mode',
 599			// Not able to access
 600			'/proc/loadavg',
 601			// Unknown languages and such
 602			'mb_language',
 603			// Garbage data
 604			'unserialize'
 605		) as $ignore_warning ) {
 606			
 607			if ( strpos($error, $ignore_warning) !== FALSE )
 608				return;
 609			
 610		}
 611		
 612		//
 613		// Error processing...
 614		//
 615		
 616		$errtypes = array(
 617			1     => 'E_ERROR',
 618			2     => 'E_WARNING',
 619			4     => 'E_PARSE',
 620			8     => 'E_NOTICE',
 621			16    => 'E_CORE_ERROR',
 622			32    => 'E_CORE_WARNING',
 623			64    => 'E_COMPILE_ERROR',
 624			128   => 'E_COMPILE_WARNING',
 625			256   => 'E_USER_ERROR',
 626			512   => 'E_USER_WARNING',
 627			1024  => 'E_USER_NOTICE',
 628			2048  => 'E_STRICT',
 629			4096  => 'E_RECOVERABLE_ERROR',
 630			8192  => 'E_DEPRECATED',
 631			16384 => 'E_USER_DEPRECATED',
 632		);
 633		
 634		if ( !strncmp($error, 'SQL:', 4) ) {
 635			
 636			$errtype = 'SQL_ERROR';
 637			$error = substr($error, 5);
 638			
 639		} else {
 640			
 641			$errtype = $errtypes[$errno];
 642			
 643		}
 644		
 645		//
 646		// Log using PHP's mechanism
 647		//
 648		if ( $this->get_config('enable_error_log') ) {
 649			
 650			$ip_addr = ( is_object($session) && !empty($session->sess_info['ip_addr']) ) ? $session->sess_info['ip_addr'] : '?';
 651			error_log('[UseBB Error] '
 652				.'['.date('Y-m-d H:i:s').'] '
 653				.'['.$ip_addr.'] '
 654				.'['.$errtype.' - '.preg_replace('#(?:\s+|\s)#', ' ', $error).'] '
 655				.'['.$file.':'.$line.']');
 656
 657		}
 658		
 659		//
 660		// Ignore hidden errors on production env (after being logged).
 661		//
 662		if ( USEBB_IS_PROD_ENV && ( ($errno & (USEBB_DEV_ERROR_LEVEL ^ USEBB_PROD_ERROR_LEVEL)) > 0 ) )
 663			return;
 664		
 665		//
 666		// Filter some sensitive data
 667		//
 668		
 669		//
 670		// Full script path
 671		//
 672		$full_path = substr(dirname(__FILE__), 0, -7);
 673		$file = str_replace($full_path, '', $file);
 674		$error = str_replace($full_path, '', $error);
 675		
 676		//
 677		// MySQL username and host for debug levels < extended
 678		//
 679		if ( ( !strncmp($error, 'mysql', 5) || $errtype == 'SQL_ERROR' ) && $this->get_config('debug') < DEBUG_EXTENDED )
 680			$error = preg_replace("#'[^ ]+'?@'?[^ ]+'#", '<em>-filtered-</em>', $error);
 681		
 682		$html_msg  = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 683<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 684	<head>
 685		<title>UseBB General Error</title>
 686		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 687		<style type="text/css">
 688			body {
 689				font-family: sans-serif;
 690				font-size: 10pt;
 691			}
 692			h1 {
 693				color: #369;
 694			}
 695			blockquote {
 696				width: 55%;
 697				border-top: 2px solid silver;
 698				border-bottom: 2px solid silver;
 699				font-family: monospace;
 700				font-size: 8pt;
 701			}
 702			#error {
 703				color: #7f0000;
 704			}
 705			textarea {
 706				width: 98%;
 707				border: 1px solid silver;
 708				padding: 3px;
 709			}
 710		</style>
 711	</head>
 712	<body>
 713		<h1>UseBB General Error</h1>
 714		<p>An error was encountered. We apologize for any inconvenience.</p>
 715		<blockquote>
 716			<p>In file <strong>'.$file.'</strong> on line <strong>'.$line.'</strong>:</p>
 717			<p id="error"><em>'.$errtype.'</em> - '.nl2br($error).'</p>';
 718				
 719		//
 720		// Show query with extended debug
 721		//
 722		if ( $errtype == 'SQL_ERROR' && $this->get_config('debug') == DEBUG_EXTENDED ) {
 723			
 724			$used_queries = $db->get_used_queries();
 725			
 726			if ( count($used_queries) ) {
 727				
 728				$html_msg .= '
 729			<p>SQL query causing the error:</p><p><textarea rows="10" cols="60" readonly="readonly">'.unhtml(end($used_queries)).'</textarea></p>';
 730				
 731			}
 732			
 733		}
 734		
 735		$html_msg .= '
 736		</blockquote>';
 737		
 738		//
 739		// Installation note if
 740		// - config.php does not exist
 741		// - error "'install' must be removed"
 742		// - mysql*() error "Access denied for user"
 743		// - sql error "Table 'x' doesn't exist" or "Access denied for user"
 744		//
 745		if ( strpos($error, 'config.php does not exist') !== false 
 746			|| strpos($error, '\'install\' must be removed') !== false
 747			|| ( !strncmp($error, 'mysql', 5) && strpos($error, 'Access denied for user') !== false )
 748			|| ( $errtype == 'SQL_ERROR' && preg_match("#(?:Table '.+' doesn't exist|Access denied for user)#i", $error) ) ) {
 749			
 750			$html_msg .= '
 751		<p><strong>UseBB may not have been installed yet.</strong></p>
 752		<p>If this is the case and you are the owner of this board, please <a href="docs/index.html">see docs/index.html for <strong>installation instructions</strong></a>.</p>
 753		<p>Otherwise, please report this error to the owner.</p>';
 754			
 755		} else {
 756			
 757			$html_msg .= '
 758		<p>This error should probably not have occured, so please report it to the owner. Thank you for your help.</p>
 759		<p>If you are the owner of this board and you believe this is a bug, please send a bug report.</p>';
 760			
 761		}
 762		
 763	$html_msg .= '
 764	</body>
 765</html>';
 766		
 767		if ( isset($template) )
 768			ob_end_clean();
 769		die($html_msg);
 770		
 771	}
 772	
 773	/**
 774	 * Get configuration variables
 775	 *
 776	 * Rewritten to speed things up and use a cache array at July 8th, 2007.
 777	 *
 778	 * @param string $setting Setting to retrieve
 779	 * @param bool $original Use original config.php configuration
 780	 * @returns mixed Value of setting
 781	 */
 782	function get_config($setting, $original=false) {
 783		
 784		global $session;
 785
 786		//
 787		// Really early stage where config file is not loaded yet.
 788		//
 789		if ( !defined('USEBB_VERSION') )
 790			return FALSE;
 791		
 792		//
 793		// Load settings into array.
 794		//
 795		if ( !count($this->board_config_original) ) {
 796			
 797			$this->board_config_original = array_merge($GLOBALS['dbs'], $GLOBALS['conf']);
 798			$this->board_config_defined = array_keys($this->board_config_original);
 799			
 800		}
 801		
 802		//
 803		// users_must_activate was renamed to activation_mode.
 804		//
 805		if ( $setting == 'activation_mode' && !isset($this->board_config_original[$setting]) )
 806			$setting = 'users_must_activate';
 807		
 808		//
 809		// Some missing (newer) settings have default values and are added to original config.
 810		//
 811		if ( !isset($this->board_config_original[$setting]) ) {
 812			
 813			switch ( $setting ) {
 814				
 815				case 'search_limit_results':
 816				case 'sig_max_length':
 817					$set_to = 1000;
 818					break;
 819				case 'search_nonindex_words_min_length':
 820				case 'username_min_length':
 821					$set_to = 3;
 822					break;
 823				case 'enable_ip_bans':
 824				case 'enable_badwords_filter':
 825				case 'guests_can_see_contact_info':
 826				case 'show_raw_entities_in_code':
 827				case 'show_never_activated_members':
 828				case 'disable_xhtml_header':
 829				case 'cookie_httponly':
 830				case 'enable_error_log':
 831				case 'error_log_log_hidden':
 832				case 'dnsbl_powered_banning_globally':
 833					$set_to = true;
 834					break;
 835				case 'view_search_min_level':
 836				case 'view_active_topics_min_level':
 837					$set_to = LEVEL_GUEST;
 838					break;
 839				case 'dnsbl_powered_banning_whitelist':
 840				case 'dnsbl_powered_banning_servers':
 841					$set_to = array();
 842					break;
 843				case 'username_max_length':
 844					$set_to = 30;
 845					break;
 846				case 'edit_post_timeout':
 847					$set_to = 900;
 848					break;
 849				case 'mass_email_msg_recipients':
 850					$set_to = 50;
 851					break;
 852				case 'acp_auto_logout':
 853					$set_to = 10;
 854					break;
 855				default:
 856					$set_to = null;
 857				
 858			}
 859			
 860			if ( isset($set_to) )
 861				$this->board_config_original[$setting] = $set_to;
 862			
 863		}
 864
 865		//
 866		// Get original settings when requested.
 867		// Treat a missing one as "false".
 868		//
 869		if ( defined('IS_INSTALLER') || $original )
 870			return ( isset($this->board_config_original[$setting]) ) ? $this->board_config_original[$setting] : false;
 871		
 872		//
 873		// As of here, settings are altered and no longer "original",
 874		// e.g. can contain inherited settings from user accounts or be computed.
 875		//
 876		// ====================
 877		//
 878
 879		//
 880		// Settings cache for this request.
 881		//
 882		if ( isset($this->board_config[$setting]) )
 883			return $this->board_config[$setting];
 884		
 885		//
 886		// User-based settings.
 887		//
 888		if ( is_object($session) && !empty($session->sess_info['user_id']) && isset($session->sess_info['user_info'][$setting]) ) {
 889			
 890			switch ( $setting ) {
 891				
 892				case 'language':
 893					$keep_default = ( !in_array($session->sess_info['user_info'][$setting], $this->get_language_packs()) );
 894					break;
 895				case 'template':
 896					$keep_default = ( !in_array($session->sess_info['user_info'][$setting], $this->get_template_sets()) );
 897					break;
 898				default:
 899					$keep_default = false;
 900				
 901			}
 902			
 903			$this->board_config[$setting] = ( $keep_default ) ? $this->board_config_original[$setting] : $session->sess_info['user_info'][$setting];
 904			
 905			if ( !$keep_default && $setting == 'date_format' )
 906				$this->date_format_from_db = TRUE;
 907			
 908			return $this->board_config[$setting];
 909			
 910		}
 911		
 912		//
 913		// Auto-detected settings when empty.
 914		//
 915		if ( in_array($setting, array('board_url', 'cookie_domain', 'cookie_path')) && empty($this->board_config_original[$setting]) ) {
 916			
 917			switch ( $setting ) {
 918				
 919				case 'board_url':
 920					$path_parts = pathinfo($_SERVER['SCRIPT_NAME']);
 921					if ( ON_WINDOWS )
 922						$path_parts['dirname'] = str_replace('\\', '/', $path_parts['dirname']);
 923					if ( substr($path_parts['dirname'], -1) != '/' )
 924						$path_parts['dirname'] .= '/';
 925					$protocol = ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ) ? 'https' : 'http';
 926					$set_to = $protocol.'://'.$_SERVER['HTTP_HOST'].$path_parts['dirname'];
 927					break;
 928				case 'cookie_domain':
 929					$set_to = ( !empty($_SERVER['SERVER_NAME']) && preg_match('#^(?:[a-z0-9\-]+\.){1,}[a-z]{2,}$#i', $_SERVER['SERVER_NAME']) ) ? preg_replace('#^www\.#', '.', $_SERVER['SERVER_NAME']) : '';
 930					break;
 931				case 'cookie_path':
 932					$set_to = '/';
 933				
 934			}
 935			
 936			$this->board_config[$setting] = $set_to;
 937			return $this->board_config[$setting];
 938			
 939		}
 940		
 941		//
 942		// Settings that need validity checking.
 943		//
 944		if ( in_array($setting, array('board_url', 'session_name', 'debug')) ) {
 945			
 946			$set_to = $this->board_config_original[$setting];
 947			
 948			if ( $setting == 'board_url' && substr($set_to, -1) != '/' )
 949				$set_to .= '/';
 950			if ( $setting == 'session_name' && ( !preg_match('#^[A-Za-z0-9]+$#', $set_to) || preg_match('#^[0-9]+$#', $set_to) ) )
 951				$set_to = 'usebb';
 952			// Only allow extended debug when not in production environment.
 953			if ( $setting == 'debug' && $set_to == DEBUG_EXTENDED && USEBB_IS_PROD_ENV )
 954				$set_to = DEBUG_SIMPLE;
 955			
 956			$this->board_config[$setting] = $set_to;
 957			return $this->board_config[$setting];
 958			
 959		}
 960		
 961		//
 962		// All other settings taken from the original array.
 963		// Use false when setting does not exist.
 964		//
 965		$this->board_config[$setting] = isset($this->board_config_original[$setting]) ? $this->board_config_original[$setting] : false;
 966
 967		return $this->board_config[$setting];
 968		
 969	}
 970	
 971	/**
 972	 * Get board statistics
 973	 *
 974	 * @param string $stat Statistical value to retrieve
 975	 * @returns mixed Statistical value
 976	 */
 977	function get_stats($stat) {
 978		
 979		global $db;
 980		
 981		//
 982		// Already requested, return
 983		//
 984		if ( isset($this->statistics[$stat]) )
 985			return $this->statistics[$stat];
 986		
 987		//
 988		// Get requested value
 989		//
 990		switch ( $stat ) {
 991			
 992			case 'categories':
 993				$result = $db->query("SELECT COUNT(id) AS count FROM ".TABLE_PREFIX."cats");
 994				$out = $db->fetch_result($result);
 995				$this->statistics[$stat] = $out['count'];
 996				break;
 997			
 998			case 'forums':
 999				$result = $db->query("SELECT COUNT(id) AS count FROM ".TABLE_PREFIX."forums");
1000				$out = $db->fetch_result($result);
1001				$this->statistics[$stat] = $out['count'];
1002				break;
1003
1004			case 'viewable_forums':
1005				$result = $db->query("SELECT id, auth FROM ".TABLE_PREFIX."forums");
1006				$this->statistics[$stat] = 0;
1007				
1008				while ( $forumdata = $db->fetch_result($result) ) {
1009					
1010					if ( $this->auth($forumdata['auth'], 'view', $forumdata['id']) )
1011						$this->statistics[$stat]++;
1012					
1013				}
1014				break;
1015			
1016			case 'latest_member':
1017				$never_activated_sql = ( $this->get_config('show_never_activated_members') ) ? "" : " WHERE ( active <> 0 OR last_login <> 0 )";
1018				$result = $db->query("SELECT id, displayed_name, regdate FROM ".TABLE_PREFIX."members".$never_activated_sql." ORDER BY id DESC LIMIT 1");
1019				$this->statistics[$stat] = $db->fetch_result($result);
1020				break;
1021			
1022			default:
1023				$result = $db->query("SELECT name, content FROM ".TABLE_PREFIX."stats");
1024				while ( $out = $db->fetch_result($result) )
1025					$this->statistics[$out['name']] = $out['content'];
1026			
1027		}
1028		
1029		if ( isset($this->statistics[$stat]) )
1030			return $this->statistics[$stat];
1031		else
1032			trigger_error('The statistic variable "'.$stat.'" does not exist!', E_USER_ERROR);
1033		
1034	}
1035	
1036	/**
1037	 * Set board statistics
1038	 *
1039	 * @param string $stat Statistical value to set
1040	 * @param mixed $value New value
1041	 * @param bool $add Add to current value or not
1042	 */
1043	function set_stats($stat, $value, $add=false) {
1044		
1045		global $db;
1046		
1047		if ( $add )
1048			$value = $this->get_stats($stat) + $value;
1049
1050		$db->query("UPDATE ".TABLE_PREFIX."stats SET content = '".$value."' WHERE name = '".$stat."'");
1051		$this->statistics[$stat] = $value;
1052
1053	}
1054
1055	/**
1056	 * Friendly URL builder
1057	 *
1058	 * @param string $filename base filename to link to
1059	 * @param array $vars GET variabeles
1060	 * @returns string URL
1061	 */
1062	function _make_friendly_url($filename, $vars) {
1063		
1064		if ( $filename == 'index' && count($vars) == 0 )
1065			return './';
1066
1067		$url = $filename;
1068		$keyed = array('forum', 'topic', 'post', 'quotepost', 'al');
1069
1070		foreach ( $vars as $key => $val )
1071			$url .= '-' . urlencode(( in_array($key, $keyed) ) ? $key . $val : $val);
1072
1073		$url .= ( $filename == 'rss' ) ? '.xml' : '.html';
1074
1075		return $url;
1076
1077	}
1078
1079	/**
1080	 * Interactive URL builder
1081	 *
1082	 * @param string $filename .php filename to link to
1083	 * @param array $vars GET variabeles
1084	 * @param bool $html Return HTML URL
1085	 * @param bool $enable_sid Enable session ID's
1086	 * @param bool $force_php Force linking to .php files
1087	 * @param bool $enable_token Enable token (forces .php link)
1088	 * @returns string URL
1089	 */
1090	function make_url($filename, $vars=array(), $html=true, $enable_sid=true, $force_php=false, $enable_token=false) {
1091		
1092		global $session;
1093		
1094		//
1095		// Base name
1096		//
1097		$filename = basename($filename, '.php');
1098
1099		//
1100		// Don't keep session key variable
1101		//
1102		if ( is_array($vars) )
1103			unset($vars[$this->get_config('session_name').'_sid']);
1104		else
1105			$vars = array();
1106
1107		//
1108		// No session IDs for search engines
1109		//
1110		$enable_sid = ( $enable_sid && !$session->is_search_engine() );
1111
1112		//
1113		// No friendly URLs for tokenized URLs, admin, installer and activation links
1114		//
1115		$force_php = ( $force_php || $enable_token || $filename == 'admin' || defined('IS_INSTALLER') || ( $filename == 'panel' && isset($vars['act']) && $vars['act'] == 'activate' ) );
1116
1117		//
1118		// Friendly URLs
1119		//
1120		if ( !$force_php && $this->get_config('friendly_urls') )
1121			return $this->_make_friendly_url($filename, $vars);
1122
1123		//
1124		// Build URL
1125		//
1126
1127		$url = $filename . '.php';
1128
1129		//
1130		// Add session variable when needed
1131		//
1132		$SID = SID;
1133		if ( !empty($SID) && $enable_sid && ( !$html || !ini_get('session.use_trans_sid') ) ) {
1134			
1135			$SID_parts = explode('=', $SID, 2);
1136			$vars[$SID_parts[0]] = $SID_parts[1];
1137
1138		}
1139
1140		//
1141		// Add token
1142		//
1143		if ( $enable_token )
1144			$vars['_url_token_'] = $this->generate_token();
1145
1146		if ( count($vars) == 0 )
1147			return $url;
1148
1149		$url .= '?';
1150		$delim = ( $html ) ? '&amp;' : '&';
1151
1152		foreach ( $vars as $key => $val )
1153			$url .= urlencode($key) . '=' . urlencode($val) . $delim;
1154
1155		return substr($url, 0, - strlen($delim));
1156		
1157	}
1158	
1159	/**
1160	 * Attaches a SID to URLs which should contain one (e.g. referer URLs)
1161	 *
1162	 * @param string $url URL
1163	 * @returns string URL
1164	 */
1165	function attach_sid($url) {
1166		
1167		$SID = SID;
1168		
1169		if ( empty($SID) || $this->get_config('friendly_urls') || preg_match('/'.preg_quote($SID, '/').'$/', $url) )
1170			return $url;
1171		
1172		if ( strpos($url, '?') !== false )
1173			return $url . '&' . $SID;
1174		
1175		return $url . '?' . $SID;
1176
1177	}
1178	
1179	/**
1180	 * Fetch a language file
1181	 *
1182	 * @param string $language Language name (default language is used when missing)
1183	 * @param string $section Section name (main section is used when missing)
1184	 * @returns array Language variables
1185	 */
1186	function fetch_language($language='', $section='') {
1187		
1188		$language = ( !empty($language) && in_array($language, $this->get_language_packs()) ) ? $language : $this->get_config('language');
1189		$section = ( !empty($section) ) ? $section : 'lang';
1190		
1191		if ( !isset($this->language_sections[$language]) || !in_array($section, $this->language_sections[$language]) ) {
1192			
1193			//
1194			// Not loaded yet
1195			//
1196
1197			if ( $section != 'lang' ) {
1198				
1199				//
1200				// Add to current $lang
1201				//
1202				$lang = $GLOBALS['lang'];
1203
1204				if ( !file_exists(ROOT_PATH.'languages/'.$section.'_'.$language.'.php') ) {
1205					
1206					//
1207					// Fallback to English
1208					//
1209					if ( $language != 'English' && in_array('English', $this->get_language_packs()) )
1210						require(ROOT_PATH.'languages/'.$section.'_English.php');
1211					else
1212						trigger_error('Section "'.$section.'" for language pack "'.$language.'" could not be found. No English fallback was available. Please use an updated language pack or also upload the English one.', E_USER_ERROR);
1213					
1214				} else {
1215					
1216					require(ROOT_PATH.'languages/'.$section.'_'.$language.'.php');
1217					
1218					//
1219					// Merge with English for missing strings
1220					//
1221					if ( $language != 'English' && in_array('English', $this->get_language_packs()) )
1222						$lang = array_merge($this->fetch_language('English', $section), $lang);
1223					
1224				}
1225				
1226			} else {
1227				
1228				require(ROOT_PATH.'languages/'.$section.'_'.$language.'.php');
1229				
1230				//
1231				// Merge with English for missing strings
1232				//
1233				if ( $language != 'English' && in_array('English', $this->get_language_packs()) )
1234					$lang = array_merge($this->fetch_language('English', $section), $lang);
1235				
1236				if ( empty($lang['character_encoding']) )
1237					$lang['character_encoding'] = 'iso-8859-1';
1238				
1239				//
1240				// UTF-8 patching
1241				//
1242				if ( function_exists('mb_internal_encoding') ) {
1243					
1244					// Setting mbstring
1245					$mb_internal_encoding = ( $lang['character_encoding'] == 'iso-8859-8-i' ) ? 'iso-8859-8' : $lang['character_encoding'];
1246
1247					$is_mb_language = mb_language($language);
1248					$is_mb_internal_encoding = mb_internal_encoding($mb_internal_encoding);
1249					
1250					if ( $is_mb_language !== FALSE || $is_mb_internal_encoding !== FALSE ) {
1251						
1252						$this->is_mbstring = TRUE;
1253						
1254					} else {
1255						 
1256						// mbstring can not be used, reset
1257						mb_language('neutral');
1258						mb_internal_encoding('ISO-8859-1');
1259						
1260					}
1261
1262					// Reset other parameters
1263					ini_set('mbstring.http_input', 'pass');
1264					ini_set('mbstring.http_output', 'pass');
1265					ini_set('mbstring.func_overload', 0);
1266					ini_set('mbstring.substitute_character', 'none');
1267				}
1268				
1269			}
1270			
1271			$this->languages[$language] = $lang;
1272		}
1273		
1274		if ( !isset($this->language_sections[$language]) )
1275			$this->language_sections[$language] = array();
1276		$this->language_sections[$language][] = $section;
1277		
1278		$returned = &$this->languages[$language];
1279		return $returned;
1280		
1281	}
1282	
1283	/**
1284	 * Kick a user to the login form
1285	 */
1286	function redir_to_login() {
1287		
1288		global $session, $template, $lang;
1289		
1290		if ( !$session->sess_info['user_id'] ) {
1291			
1292			$_SESSION['referer'] = $_SERVER['REQUEST_URI'];
1293			$this->redirect('panel.php', array('act' => 'login'));
1294			
1295		} else {
1296			
1297			header(HEADER_403);
1298			$template->clear_breadcrumbs();
1299			$template->add_breadcrumb($lang['Note']);
1300			$template->parse('msgbox', 'global', array(
1301				'box_title' => $lang['Note'],
1302				'content' => $lang['NotPermitted']
1303			));
1304			
1305		}
1306		
1307	}
1308	
1309	/**
1310	 * Generate a date given a timestamp
1311	 *
1312	 * @param int $stamp Unix timestamp
1313	 * @param string $format Date format syntax (identical to PHP's date() - default is used when missing)
1314	 * @param bool $keep_gmt Use GMT and no time zones
1315	 * @param bool $translate Localize dates
1316	 * @returns string Date
1317	 */
1318	function make_date($stamp, $format='', $keep_gmt=false, $translate=true) {
1319		
1320		global $lang;
1321		
1322		$format = ( !empty($format) ) ? $format : strip_tags($this->get_config('date_format'));
1323		
1324		if ( $this->date_format_from_db )
1325			$format = stripslashes($format);
1326		
1327		if ( $keep_gmt )
1328			$date = gmdate($format, $stamp);
1329		else
1330			$date = gmdate($format, $stamp + (3600 * $this->get_config('timezone')) + (3600 * $this->get_config('dst')));
1331		
1332		if ( $translate && isset($lang['date_translations']) && is_array($lang['date_translations']) )
1333			$date = ucfirst(strtr($date, $lang['date_translations']));
1334		
1335		return $date;
1336		
1337	}
1338	
1339	/**
1340	 * Generate a time past string
1341	 *
1342	 * @param int $timestamp Unix timestamp
1343	 * @param int $until Calculate time past until this Unix timestamp (current is used when missing)
1344	 * @returns string Time past
1345	 */
1346	function time_past($timestamp, $until=null) {
1347	
1348		global $lang;
1349	
1350		$seconds = ( ( is_int($until) ) ? $until : time() ) - $timestamp;
1351	
1352		$times = array();
1353		$sections = array(
1354			'weeks' => 604800,
1355			'days' => 86400,
1356			'hours' => 3600,
1357			'minutes' => 60,
1358			'seconds' => 1
1359		);
1360	
1361		foreach( $sections as $what => $length ) {
1362			
1363			if ( $seconds >= $length ) {
1364				
1365				$times[$what] = ( $length >0 ) ? floor($seconds / $length) : $length;
1366				$seconds %= $length;
1367				
1368			}
1369			
1370		}
1371	
1372		$sections = array();
1373		foreach ( $times as $key => $val )
1374			$sections[] = $val.' '.$lang[ucfirst($key)];
1375	
1376		return array($times, join(', ', $sections));
1377	
1378	}
1379	
1380	/**
1381	 * Generate an e-mail link/text
1382	 *
1383	 * @param array $user User information containing id, email and email_show
1384	 * @returns string HTML
1385	 */
1386	function show_email($user) {
1387		
1388		global $session, $lang;
1389		
1390		//
1391		// Possible email_view_level values:
1392		// - 0: Hide all
1393		// - 1: Use mail form
1394		// - 2: Show spam proof
1395		// - 3: Show raw
1396		//
1397		
1398		$email_view_level = $this->get_config('email_view_level');
1399		
1400		if ( $this->get_user_level() >= $this->get_config('view_hidden_email_addresses_min_level') ) {
1401			
1402			//
1403			// This user may view hidden e-mail addresses
1404			//
1405			$return = '<a href="mailto:'.$user['email'].'">'.$user['email'].'</a>';
1406			if ( $email_view_level == 1 )
1407				$return = '<a href="'.$this->make_url('mail.php', array('id' => $user['id'])).'">'.$lang['SendMessage'].'</a> ('.$return.')';
1408			
1409		} else {
1410			
1411			if ( $email_view_level == 0 || ( !$user['email_show'] && $user['id'] != $session->sess_info['user_id'] ) ) {
1412				
1413				//
1414				// E-mail addresses are hidden or the user has chosen to keep it hidden
1415				//
1416				$return = $lang['Hidden'];
1417				
1418			} else {
1419				
1420				switch ( $email_view_level ) {
1421					
1422					case 1:
1423						$return = '<a href="'.$this->make_url('mail.php', array('id' => $user['id'])).'">'.$lang['SendMessage'].'</a>';
1424						break;
1425					case 2:
1426						$user['email'] = $this->string_to_entities($user['email']);
1427						// No break here, since we just want to convert $user['email']
1428					default:
1429						$return = '<a href="mailto:'.$user['email'].'">'.$user['email'].'</a>';
1430					
1431				}
1432				
1433			}
1434			
1435		}
1436		
1437		return $return;
1438		
1439	}
1440	
1441	/**
1442	 * Translate an ASCII string to HTML entities
1443	 *
1444	 * This function only works for ASCII characters, nothing else.
1445	 *
1446	 * @param string $string String to convert
1447	 * @returns string Converted string
1448	 */
1449	function string_to_entities($string) {
1450		
1451		$length = strlen($string);
1452		$new_string = '';
1453		for ( $i = 0; $i < $length; $i++ )
1454			$new_string .= '&#'.ord(substr($string, $i, $i+1)).';';
1455		
1456		return $new_string;
1457		
1458	}
1459
1460	/**
1461	 * Generate a random key
1462	 *
1463	 * @param bool $is_password Is the random key used as a password?
1464	 * @returns string Random key
1465	 */
1466	function random_key($is_password=false) {
1467		
1468		if ( !$is_password )
1469			return md5(mt_rand());
1470		
1471		$chars = range(33, 126); // ! until ~
1472		$max = count($chars) - 1;
1473
1474		$passwd_min_length = (int) $this->get_config('passwd_min_length');
1475		$length = ( $passwd_min_length > 10 ) ? $passwd_min_length : 10;
1476		
1477		do {
1478		
1479			$key = '';
1480			for ( $i = 0; $i < $length; $i++ )
1481				$key .= chr($chars[mt_rand(0, $max)]);
1482
1483			$valid = $this->validate_password($key, true);
1484
1485		} while ( !$valid );
1486		
1487		return $key;
1488		
1489	}
1490	
1491	/**
1492	 * Send an email
1493	 *
1494	 * Why don't they just send me an e-mail? -- Belgian ad for coffee
1495	 *
1496	 * @param string $subject Subject of e-mail
1497	 * @param string $rawbody Body of e-mail
1498	 * @param array $bodyvars Variables for e-mail body
1499	 * @param string $from_name Name of sender
1500	 * @param string $from_email E-mail of sender
1501	 * @param string $to E-mail of recipient
1502	 * @param string $bcc_email E-mail of BCC recipient (no BCC when missing)
1503	 * @param string $language Language name the e-mail is in (default language when missing)
1504	 * @param string $charset Character set the e-mail is in (default charset when missing)
1505	 */
1506	function usebb_mail($subject, $rawbody, $bodyvars=array(), $from_name, $from_email, $to, $bcc_email='', $language='', $charset='') {
1507		
1508		global $lang;
1509		
1510		$bodyvars = ( is_array($bodyvars) ) ? $bodyvars : array();
1511		
1512		$is_enable_mbstring = ( function_exists('mb_language') && mb_language() != 'neutral' );
1513
1514		//
1515		// Eventually use the right language and character encoding which may be passed
1516		// in the parameters when another language is used (e.g. subscription notices)
1517		//
1518		$language = ( !empty($language) ) ? $language : $this->get_config('language');
1519		$charset = ( !empty($charset) ) ? $charset : $lang['character_encoding'];
1520		
1521		//
1522		// Set the correct mb_language when neccessary (when mbstring enabled)
1523		//
1524		$is_mbstring = FALSE;
1525		if ( $this->is_mbstring ) {
1526			
1527			$backup_mb_language = mb_language();
1528			$backup_mb_internal_encoding = mb_internal_encoding();
1529			
1530			if ( @mb_language($language) !== FALSE && @mb_internal_encoding($charset) !== FALSE )
1531				$is_mbstring = TRUE;
1532			
1533		}
1534		
1535		$body = str_replace(array("\r\n", "\r"), "\n", $rawbody);
1536		
1537		//
1538		// Windows: \r\n; other: \n
1539		//
1540		$cr = ( ON_WINDOWS ) ? "\r\n" : "\n";
1541		$body = str_replace("\n", $cr, $rawbody);
1542		
1543		$bodyvars['board_name'] = $this->get_config('board_name');
1544		$bodyvars['board_link'] = $this->get_config('board_url');
1545		$bodyvars['admin_email'] = $this->get_config('admin_email');
1546		
1547		foreach ( $bodyvars as $key => $val )
1548			$body = str_replace('['.$key.']', $val, $body);
1549		
1550		$headers = array();
1551		
1552		if ( $is_mbstring && function_exists('mb_encode_mimeheader') ) {
1553			
1554			$from_name = mb_encode_mimeheader($from_name);
1555			
1556		} else {
1557			
1558			if ( strtolower($charset) == 'utf-8' ) {
1559
1560				$subject = '=?'.$charset.'?B?'.base64_encode($subject).'?=';
1561				$from_name = '=?'.$charset.'?B?'.base64_encode($from_name).'?=';
1562
1563			}
1564			
1565		}
1566		
1567		if ( !empty($bcc_email) )
1568			$headers[] = 'Bcc: '.$bcc_email;
1569		$headers[] = 'Date: '.date('r');
1570		$headers[] = 'Message-Id: '.sprintf("<%s.%s>", substr(md5(time()), 4, 10), $from_email);
1571		$headers[] = 'X-Mailer: UseBB';
1572		
1573		//
1574		// Fix for hosts that require From to be a domain name hosted on the same host
1575		// So, instead we can use a Reply-To header to contain the sender email
1576		//
1577		if ( $from_email != $this->get_config('admin_email') && $this->get_config('email_reply-to_header') ) {
1578			
1579			$headers[] = 'From: "'.$from_name.'" <'.$this->get_config('admin_email').'>';
1580			$headers[] = 'Reply-To: '.$from_email;
1581			
1582		} else {
1583			
1584			$headers[] = 'From: "'.$from_name.'" <'.$from_email.'>';
1585			
1586		}
1587		
1588		// TODO safe mode to be removed in PHP 5.4
1589		$is_safe_mode = in_array(strtolower(ini_get('safe_mode')), array('1', 'on'));
1590
1591		if ( $is_mbstring && function_exists('mb_send_mail') ) {
1592
1593			$mail_func = 'mb_send_mail';
1594
1595		} else {
1596			
1597			$mail_func = 'mail';
1598			$headers[] = 'MIME-Version: 1.0';
1599			$headers[] = 'Content-Type: text/plain; charset='.$charset;
1600			if ( preg_match('/^(iso-8859-|iso-2022-)/i', $charset))
1601				$headers[] = 'Content-Transfer-Encoding: 7bit';
1602			else
1603				$headers[] = 'Content-Transfer-Encoding: 8bit';
1604			
1605		}
1606
1607		if ( $is_safe_mode || !$this->get_config('sendmail_sender_parameter') )
1608			$mail_result = $mail_func($to, $subject, $body, join($cr, $headers));
1609		else
1610			$mail_result = $mail_func($to, $subject, $body, join($cr, $headers), '-f'.$from_email);
1611
1612		if ( !$mail_result )
1613			trigger_error('Unable to send e-mail!', E_USER_ERROR);
1614		
1615		//
1616		// Restored language and character encoding.
1617		//
1618		if ( $this->is_mbstring ) {
1619			
1620			mb_language($backup_mb_language);
1621			mb_internal_encoding($backup_mb_internal_encoding);
1622			
1623		}
1624		
1625	}
1626	
1627	/**
1628	 * Set the remember cookie
1629	 *
1630	 * @param int $user_id User ID
1631	 * @param string $passwd_hash Password hash
1632	 */
1633	function set_al($user_id, $passwd_hash) {
1634		
1635		$content = array(
1636			intval($user_id),
1637			$passwd_hash
1638		);
1639		$this->setcookie($this->get_config('session_name').'_al', serialize($content), time()+31536000);
1640		
1641	}
1642	
1643	/**
1644	 * Unset the remember cookie
1645	 */
1646	function unset_al() {
1647		
1648		$this->setcookie($this->get_config('session_name').'_al', '');
1649		
1650	}
1651	
1652	/**
1653	 * Is the remember cookie set?
1654	 *
1655	 * @returns bool Remember cookie set
1656	 */
1657	function isset_al() {
1658		
1659		$cookie_name = $this->get_config('session_name').'_al';
1660
1661		if ( empty($_COOKIE[$cookie_name]) )
1662			return FALSE;
1663
1664		$value = stripslashes($_COOKIE[$cookie_name]);
1665
1666		return ( preg_match('/^a:2:\{i:0;i:[0-9]+;i:1;s:32:"[a-z0-9]{32}";\}$/', $value) === 1 );
1667		
1668	}
1669	
1670	/**
1671	 * Get the remember cookie's value
1672	 *
1673	 * @returns mixed Array with user ID and password hash -or- false when not set
1674	 */
1675	function get_al() {
1676		
1677		if ( !$this->isset_al() )
1678			return FALSE;
1679			
1680		return unserialize(stripslashes($_COOKIE[$this->get_config('session_name').'_al']));
1681		
1682	}
1683	
1684	/**
1685	 * Get the user's level
1686	 *
1687	 * @returns int User level
1688	 */
1689	function get_user_level() {
1690		
1691		global $session;
1692		
1693		if ( !isset($session->sess_info['user_id']) )
1694			trigger_error('You first need to call $session->update() before you can get any session info.', E_USER_ERROR);
1695		
1696		if ( $session->sess_info['user_id'] )
1697			return $session->sess_info['user_info']['level'];
1698		else
1699			return LEVEL_GUEST;
1700		
1701	}
1702	
1703	/**
1704	 * Authorization function
1705	 *
1706	 * Defines whether a user has permission to take a certain action.
1707	 *
1708	 * @param string $auth_int Authorization "integer" (string because of leading zeroes)
1709	 * @param string $action Action to establish
1710	 * @param int $forum_id ID of forum
1711	 * @param bool $self For own account
1712	 * @param array $alternative_user_info When not for own account, array with user information
1713	 * @returns bool Allowed
1714	 */
1715	function auth($auth_int, $action, $forum_id, $self=true, $alternative_user_info=null) {
1716		
1717		global $session, $db;
1718		
1719		if ( $self )
1720			$user_info = ( $session->sess_info['user_id'] ) ? $session->sess_info['user_info'] : array('id' => LEVEL_GUEST, 'level' => LEVEL_GUEST);
1721		else
1722			$user_info = $alternative_user_info;
1723		
1724		if ( ( $self && $session->sess_info['ip_banned'] ) || ( $this->get_config('board_closed') && $user_info['level'] < LEVEL_ADMIN ) )
1725			return false;
1726		
1727		//
1728		// Define the user level
1729		//
1730		if ( $user_info['id'] ) {
1731			
1732			//
1733			// Logged in user
1734			//
1735			if ( $user_info['level'] == LEVEL_MOD ) {
1736				
1737				if ( !is_array($this->mod_auth) ) {
1738					
1739					$result = $db->query("SELECT forum_id FROM ".TABLE_PREFIX."moderators WHERE user_id = ".$user_info['id']);
1740					$this->mod_auth = array();
1741					while ( $out = $db->fetch_result($result) )
1742						$this->mod_auth[] = intval($out['forum_id']);
1743					
1744				}
1745				
1746				$userlevel = ( in_array($forum_id, $this->mod_auth) ) ? LEVEL_MOD : LEVEL_MEMBER;
1747				
1748			} else {
1749				
1750				$userlevel = $user_info['level'];
1751				
1752			}
1753			
1754		} else {
1755			
1756			//
1757			// Guest
1758			//
1759			if ( !$this->get_config('guests_can_access_board') )
1760				return false;
1761			else
1762				$userlevel = LEVEL_GUEST;
1763			
1764		}
1765		
1766		//
1767		// Get the part of the auth integer that
1768		// corresponds with the action given
1769		//
1770		$actions = array(
1771			'view' => 0,
1772			'read' => 1,
1773			'post' => 2,
1774			'reply' => 3,
1775			'edit' => 4,
1776			'move' => 5,
1777			'delete' => 6,
1778			'lock' => 7,
1779			'sticky' => 8,
1780			'html' => 9
1781		);
1782		$min_level = intval($auth_int[$actions[$action]]);
1783		
1784		//
1785		// If the user level is equal or greater than the
1786		// auth integer, return a true, otherwise return a false.
1787		//
1788		if ( $userlevel >= $min_level )
1789			return true;
1790		else
1791			return false;
1792		
1793	}
1794	
1795	/**
1796	 * Return a list of moderators, clickable and separated with commas
1797	 *
1798	 * @param int $forum Forum ID
1799	 * @param array $listarray Array with all moderators (automatically requested when missing)
1800	 * @returns string Moderator list
1801	 */
1802	function get_mods_list($forum, $listarray=false) {
1803		
1804		global $db, $lang;
1805		
1806		$forum_moderators = array();
1807		
1808		if ( is_array($listarray) && count($listarray) ) {
1809			
1810			foreach ( $listarray as $modsdata ) {
1811				
1812				if ( $modsdata['forum_id'] == $forum )
1813					$forum_moderators[] = $this->make_profile_link($modsdata['id'], $modsdata['displayed_name'], $modsdata['level']);
1814				
1815			}
1816			
1817			if ( !count($forum_moderators) ) {
1818				
1819				return $lang['Nobody'];
1820				
1821			}
1822			
1823		} else {
1824			
1825			$result = $db->query("SELECT u.id, u.displayed_name, u.level FROM ".TABLE_PREFIX."members u, ".TABLE_PREFIX."moderators m WHERE m.forum_id = ".$forum." AND m.user_id = u.id ORDER BY u.displayed_name");
1826			while ( $modsdata = $db->fetch_result($result) )
1827				$forum_moderators[] = $this->make_profile_link($modsdata['id'], $modsdata['displayed_name'], $modsdata['level']);
1828				
1829			if ( !count($forum_moderators) ) {
1830				
1831				return $lang['Nobody'];
1832				
1833			}
1834			
1835		}
1836		
1837		//
1838		// Join all values in the array
1839		//
1840		return join(', ', $forum_moderators);
1841		
1842	}
1843	
1844	/**
1845	 * Return a clickable list of pages
1846	 *
1847	 * @param int $pages_number Total number of pages
1848	 * @param int $current_page Current page
1849	 * @param int $items_number Number of items
1850	 * @param int $items_per_page Items per page
1851	 * @param string $page_name .php page name
1852	 * @param int $page_id_val URL id GET value
1853	 * @param bool $back_forward_links Enable back and forward links
1854	 * @param array $url_vars Other URL vars
1855	 * @param bool $force_php Force linking to .php files
1856	 * @returns string HTML
1857	 */
1858	function make_page_links($pages_number, $current_page, $items_number, $items_per_page, $page_name, $page_id_val=NULL, $back_forward_links=true, $url_vars=array(), $force_php=false) {
1859		
1860		global $lang;
1861		
1862		if ( intval($items_number) > intval($items_per_page) ) {
1863			
1864			$page_links = array();
1865			$page_links_groups_length = 4;
1866			
1867			if ( !$current_page ) {
1868				
1869				$current_page = $pages_number+1;
1870				$page_links_groups_length++;
1871				
1872			}
1873			
1874			for ( $i = 1; $i <= $pages_number; $i++ ) {
1875				
1876				if ( $current_page != $i ) {
1877					
1878					if ( $i+$page_links_groups_length >= $current_page && $i-$page_links_groups_length <= $current_page ) {
1879						
1880						if ( valid_int($page_id_val) )
1881							$url_vars['id'] = $page_id_val;
1882						$url_vars['page'] = $i;
1883						$page_links[] = '<a href="'.$this->make_url($page_name, $url_vars, true, true, $force_php).'">'.$i.'</a>';
1884						
1885					} else {
1886						
1887						if ( end($page_links) != '...' )
1888							$page_links[] = '...';
1889						
1890					}
1891					
1892				} else {
1893					
1894					$page_links[] = '<strong>'.$i.'</strong>';
1895					
1896				}
1897				
1898			}
1899			
1900			$page_links = join(' ', $page_links);
1901			
1902			if ( $back_forward_links ) {
1903				
1904				if ( valid_int($page_id_val) )
1905					$url_vars['id'] = $page_id_val;
1906				
1907				if ( $current_page > 1 ) {
1908					
1909					$url_vars['page'] = $current_page-1;
1910					$page_links = '<a href="'.$this->make_url($page_name, $url_vars, true, true, $force_php).'">&lt;</a> '.$page_links;
1911					
1912				}
1913				if ( $current_page < $pages_number ) {
1914					
1915					$url_vars['page'] = $current_page+1;
1916					$page_links .= ' <a href="'.$this->make_url($page_name, $url_vars, tru…

Large files files are truncated, but you can click here to view the full file