\\1
', '\\1', '\\2', '\'\\2
', '\\2', '\\2', '\\2', $this->lang->spoiler . ':\s(.+)\s<\/span>\s<\/code>$/', '$1', $input);
} else {
$input = htmlspecialchars(str_replace(array('\'', '\"'), array(''', '"'), $input));
$title = $this->lang->main_code;
}
if (isset($tagged)) {
$input = str_replace(array('<?php', '?>'), '', $input);
}
if ($title == 'PHP') {
$lines = explode('
', $input);
} else {
$lines = explode("\n", $input);
}
$count = count($lines);
$col1 = '';
$col2 = '';
for ($i = 0; $i < $count; $i++)
{
$col1 .= $start . "\n";
$col2 .= $lines[$i];
$start++;
}
$height = ($count * 14) + 14;
$return = '';
if ($php) {
$return = '';
} else {
$return = '';
}
$return .= '' . $title . ':';
/* $return .= '$col1'; */
$return .= '' . $col2 . '
';
return $return;
}
/**
* Finds all subforums of $parent in $array
*
* @param array $array Array of forums from forum_grab()
* @param int $parent forum_id of a parent forum
* @author Mark Elliot
* @since Beta 4.0
* @return array Array of subforums
**/
function forum_array($array, $parent)
{
$arr = array();
for ($i = 0; $i < count($array); $i++)
{
if ($array[$i]['forum_parent'] == $parent) {
$arr[] = $array[$i];
}
}
return $arr;
}
/**
* Gets all forums and puts them in an array
*
* @param string $sort Field to sort by
* @author Mark Elliot
* @since Beta 4.0
* @return array Array of all existing forums to be passed to select_forums()
**/
function forum_grab($sort = 'forum_position')
{
$forums = array();
$q = $this->db->query('SELECT forum_id, forum_parent, forum_tree, forum_name, forum_position FROM ' . $this->pre . 'forums ORDER BY ' . $sort);
while ($f = $this->db->nqfetch($q))
{
$forums[] = $f;
}
return $forums;
}
/**
* Generates a random pronounceable password
*
* @param int $length Length of password
* @author http://www.zend.com/codex.php?id=215&single=1
* @since 1.1.0
*/
function generate_pass($length)
{
$vowels = array('a', 'e', 'i', 'o', 'u');
$cons = array('b', 'c', 'd', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'u', 'v', 'w', 'tr',
'cr', 'br', 'fr', 'th', 'dr', 'ch', 'ph', 'wr', 'st', 'sp', 'sw', 'pr', 'sl', 'cl');
$num_vowels = count($vowels);
$num_cons = count($cons);
$password = '';
for ($i = 0; $i < $length; $i++)
{
$password .= $cons[rand(0, $num_cons - 1)] . $vowels[rand(0, $num_vowels - 1)];
}
return substr($password, 0, $length);
}
/**
* Checks if an email address looks valid
*
* @param string $email Address to check
* @return true if the email checks out
* @author http://iamcal.com/publish/articles/php/parsing_email
* @since 1.1.5
*/
function is_valid_email_address($email)
{
$qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
$dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
$atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'.
'\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
$quoted_pair = '\\x5c\\x00-\\x7f';
$domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
$quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
$domain_ref = $atom;
$sub_domain = "($domain_ref|$domain_literal)";
$word = "($atom|$quoted_string)";
$domain = "$sub_domain(\\x2e$sub_domain)*";
$local_part = "$word(\\x2e$word)*";
$addr_spec = "$local_part\\x40$domain";
return preg_match("!^$addr_spec$!", $email) ? 1 : 0;
}
/**
* Retrieves message icons and puts them into a table as radio buttons
*
* @param string $select Icon to select
* @author Jason Warner
* @since Beta 2.0
* @return string HTML-formatted message icons
**/
function get_icons($select = -1)
{
$i = 0;
$icons = array();
$dir = opendir("./skins/$this->skin/mbicons");
while (($file = readdir($dir)) !== false)
{
$ext = substr($file, -4);
if ((($ext == '.gif') || ($ext == '.jpg') || ($ext == '.png')) && !is_dir("./skins/$this->skin/mbicons/$file")) {
$icons[$i] = $file;
$i++;
}
}
closedir($dir);
natsort($icons);
$msgicons = null;
$i = 0;
foreach ($icons as $icon)
{
if (($i % 8 == 0) && ($i != 0)) {
$msgicons .= "\n\n\n";
}
$msgicons .= "\n ";
$i++;
}
return $msgicons;
}
/**
* Loads a user_language. Bet you couldn't figure that out...
*
* @param string $lang Language to load
* @param string $a Word set to load
* @param string $path Path to the user_languages directory
* @param bool $main Load main universal strings
* @author Jason Warner
* @since Beta 3.0
* @return object Language
**/
function get_lang($lang, $a = null, $path = './', $main = true)
{
if (isset($this->get['lang'])) {
$lang = $this->get['lang'];
}
if (strstr($lang, '/') || !file_exists($path . 'languages/' . $lang . '.php')) {
$lang = 'en';
}
include $path . 'languages/' . $lang . '.php';
$obj = new $lang();
// Check if language function is available before running it
if ($a && is_callable(array($obj,$a))) {
$obj->$a();
}
if ($main) {
$obj->main();
}
$obj->universal();
return $obj;
}
function get_lang_name($code)
{
$code = strtolower($code);
switch($code)
{
case 'bg': return 'Bulgarian'; break;
case 'zh': return 'Chinese'; break;
case 'cs': return 'Czech'; break;
case 'nl': return 'Dutch'; break;
case 'en': return 'English'; break;
case 'fi': return 'Finnish'; break;
case 'fr': return 'French'; break;
case 'de': return 'German'; break;
case 'he': return 'Hebrew'; break;
case 'hu': return 'Hungarian'; break;
case 'id': return 'Indonesian'; break;
case 'it': return 'Italian'; break;
case 'no': return 'Norwegian'; break;
case 'pt': return 'Portuguese'; break;
case 'ru': return 'Russian'; break;
case 'sk': return 'Slovak'; break;
case 'es': return 'Spanish'; break;
case 'sv': return 'Swedish'; break;
default: return $code; break;
}
}
/**
* Gets information about a member's level and title
*
* @param int $posts Member's post count
* @author Jason Warner
* @since Beta 2.1
* @return array Array of information about the member:
string user_title - default member title for that post count
int user_level - default member level for that post count
**/
function get_level($posts)
{
$memtitle = array(
'user_title' => '',
'user_level' => '0'
);
$titles = $this->db->query("SELECT * FROM {$this->pre}membertitles WHERE membertitle_posts <= $posts ORDER BY membertitle_posts");
while ($title = $this->db->nqfetch($titles))
{
if ($posts >= $title['membertitle_posts']) {
$memtitle['user_title'] = $title['membertitle_title'];
$memtitle['user_level'] = $title['membertitle_id'];
} else {
break;
}
}
return $memtitle;
}
/**
* Retrieves the current server load
*
* @author Jason Warner
* @since Beta 2.0
* @return int Server load
**/
function get_load()
{
if (get_cfg_var('safe_mode') || stristr(PHP_OS, 'WIN')) {
return 0;
}
if (@file_exists('/proc/loadavg')) {
$file = @fopen('/proc/loadavg', 'r');
if (!$file) {
return 0;
}
$load = explode(' ', fread($file, 6));
fclose($file);
} else {
$load = @exec('uptime');
if (!$load) {
return 0;
}
$load = split('load averages?: ', $load);
$load = explode(',', $load[1]);
}
return trim($load[0]);
}
/**
* Retrieves the number of personal messages the user has received
*
* @param bool $seen True to retreive all messages, false to retrieve only unread messages
* @param int $folder The folder to check user_pms for
* @author Jason Warner
* @since Beta 2.0
* @return int Count of personal messages
**/
function get_messages($seen = false, $folder = 0)
{
$count = $this->db->fetch("SELECT COUNT(pm_id) AS messages FROM {$this->pre}pmsystem WHERE pm_to={$this->user['user_id']} AND pm_folder=$folder" . (!$seen ? " AND pm_read=0" : null));
return $count['messages'];
}
/**
* Creates HTML-formatted page numbers
*
* @param mixed $rows Can be either a resource, query, or number; number of total entries for pagination
* @param string $link Query string to attach to link
* @param int $min First entry to display
* @param int $num Number of entries per page
* @author Mark Elliot
* @since Beta 1.0
* @return string HTML-formatted page numbers
**/
function get_pages($rows, $link, $min = 0, $num = 10)
{
if (!$num) {
$num = 10;
}
// preliminary row handling
if (!is_resource($rows)) {
if (!is_numeric($rows)) {
$rows = $this->db->num_rows($this->db->query($rows));
}
} else {
$rows = $this->db->num_rows($records);
}
// some base variables
$current = ceil($min / $num);
$string = null;
$pages = ceil($rows / $num);
$end = ($pages - 1) * $num;
// check if there's previous articles
if ($min == 0) {
$startlink = '<<';
$previouslink = $this->lang->main_prev;
} else {
$startlink = "self}?$link&min=0&num=$num\" class=\"pagelinks\"><<";
$prev = $min - $num;
$previouslink = "self}?$link&min=$prev&num=$num\" class=\"pagelinks\">{$this->lang->main_prev} ";
}
// check for next/end
if (($min + $num) < $rows) {
$next = $min + $num;
$nextlink = "self}?$link&min=$next&num=$num\" class=\"pagelinks\">{$this->lang->main_next}";
$endlink = "self}?$link&min=$end&num=$num\" class=\"pagelinks\">>>";
} else {
$nextlink = $this->lang->main_next;
$endlink = '>>';
}
// setup references
$b = $current - 2;
$e = $current + 2;
// set end and beginning of loop
if ($b < 0) {
$e = $e - $b;
$b = 0;
}
// check that end coheres to the issues
if ($e > $pages - 1) {
$b = $b - ($e - $pages + 1);
$e = ($pages - 1 < $current) ? $pages : $pages - 1;
// b may need adjusting again
if ($b < 0) {
$b = 0;
}
}
// ellipses
if ($b != 0) {
$badd = '...';
} else {
$badd = '';
}
if (($e != $pages - 1) && $rows) {
$eadd = '...';
} else {
$eadd = '';
}
// run loop for numbers to the page
for ($i = $b; $i < $current; $i++)
{
$where = $num * $i;
$string .= ", self}?$link&min=$where&num=$num\" class=\"bodylinktype\">" . ($i + 1) . '';
}
// add in page
$string .= ', ' . ($current + 1) . '';
// run to the end
for ($i = $current + 1; $i <= $e; $i++)
{
$where = $num * $i;
$string .= ", self}?$link&min=$where&num=$num\" class=\"bodylinktype\">" . ($i + 1) . '';
}
// get rid of preliminary comma. (optimized by jason: mark uses preg_replace() like candy)
if (substr($string, 0, 1) == ',') {
$string = substr($string, 1);
}
return "$startlink $previouslink $badd $string $eadd $nextlink $endlink";
}
/**
* Creates HTML-formatted page numbers for topics - see get_pages()
*
* @param int $records Number of replies in the topic
* @param int $link Query string to attach to link
* @param string $sep Separator for pages
* @param int $min First entry to display
* @param int $n Number of entries to display
* @author Mark Elliot
* @since Beta 2.0
* @return
**/
function get_pages_topic($records, $link, $sep, $min = 0, $n = 10)
{
$records++;
$pages = ceil($records / $n);
$max_page = ($pages - 1) * $n;
if ($pages == 1) {
return null;
}
$pagelinks = null;
if ($pages > 3) {
$countfor = 3;
} else {
$countfor = $pages;
}
for ($i = 0; $i < $countfor; $i++)
{
$minpag = $i * $n;
$page = $i + 1;
$pagelinks .= "self}?$link&min=$minpag&num=$n\" class=\"pages\">$page{$sep}";
}
if (substr($pagelinks, -(strlen($sep))) == $sep) {
$pagelinks = substr($pagelinks, 0, -(strlen($sep)));
}
if ($pages > 3) {
$ellipsis = ($pages == 4) ? '' : '..';
$pagelinks .= "$sepself}?$link&min=$max_page&num=$n\" class=\"pages\">{$ellipsis}{$pages}";
}
$pagelinks = "( $pagelinks )";
return $pagelinks;
}
/**
* Loads emoticon and censor information from the replacements table
*
* @author Jason Warner
* @since Beta 2.1
* @return void
**/
function get_replaces()
{
$this->replaces_loaded = true;
$replace = $this->db->query("SELECT * FROM {$this->pre}replacements ORDER BY LENGTH(replacement_search) DESC");
while ($r = $this->db->nqfetch($replace))
{
if ($r['replacement_type'] == 'emoticon') {
$this->emotes['replacement'][$r['replacement_search']] = "
";
if ($r['replacement_clickable']) {
$this->emotes['replacement_clickable'][$r['replacement_search']] = "
";
}
} elseif ($r['replacement_type'] == 'censor') {
$this->censor[] = '/' . $r['replacement_search'] . '/i';
}
}
}
/**
* Loads settings
*
* @author Jason Warner
* @since 1.1.0
* @return array Settings
**/
function get_settings($sets)
{
$settings = $this->db->fetch("SELECT settings_data FROM {$this->pre}settings LIMIT 1");
return array_merge($sets, unserialize($settings['settings_data']));
}
/**
* Loads templates into an array, replacing {{var}} with $var
*
* @param string $a Template group
* @param bool $getMain Load the standard set of templates
* @author Jason Warner
* @since Beta 2.0
* @return mixed Array of templates on success, error message on failure
**/
function get_templates($a, $getMain = true, $getAdmin = false)
{
if ($getMain) {
$temp_query = $this->db->query("SELECT template_name, template_html FROM {$this->pre}templates WHERE template_skin='$this->skin' AND (template_set='Main' OR template_set='$a')");
} elseif ($getAdmin) {
$temp_query = $this->db->query("SELECT template_name, template_html FROM {$this->pre}templates WHERE template_skin='$this->skin' AND (template_set='Admin' OR template_set='$a')");
} else {
$temp_query = $this->db->query("SELECT template_name, template_html FROM {$this->pre}templates WHERE template_skin='$this->skin' AND template_set='$a'");
}
while ($template = $this->db->nqfetch($temp_query))
{
// Check for IF statements
$template['template_html'] = preg_replace('~(.*?)((.*?))? ~se', '$this->get_templates_callback(\'\\1\', \'\\2\', $template[\'template_name\'], \'\\3\')', $template['template_html']);
// Check for MODLET with optional parameter
$template['template_html'] = preg_replace('//se', '$this->run_modlet(\'\\1\', \'\\2\', $template[\'template_name\'], $getAdmin)', $template['template_html']);
$templates[$template['template_name']] = $template['template_html'];
}
if ($getAdmin)
$dir = file_exists('../skins/' . $this->skin) && is_dir('../skins/' . $this->skin);
else
$dir = file_exists('./skins/' . $this->skin) && is_dir('./skins/' . $this->skin);
if (isset($templates) && $dir) {
$templates = str_replace(array('\\', '"', '\\$'), array('\\\\', '\\"', '\\\\$'), $templates);
return $templates;
} else {
if ($dir) {
error(QUICKSILVER_ERROR, "Template set not found in database: $a", __FILE__, __LINE__);
} else {
error(QUICKSILVER_ERROR, "Template set not found in database: $a
Skin not found in the skins directory: $this->skin", __FILE__, __LINE__);
}
}
}
/**
* Stores if statements into an array (performance speed-up)
*
* @param string if statements
* @param string string to use if condition is true
* @param string template
* @param string string to use if contition is false (optional)
* @author Inverno
* @return string replace if statements with a var
**/
function get_templates_callback($condition, $code, $piece, $falseCode = '')
{
$macro_id = isset($this->macro[$piece]) ? count($this->macro[$piece]) : 0;
if ($falseCode) {
// Strip off the
$falseCode = substr($falseCode, 6);
}
$this->macro[$piece][$macro_id] = '$macro_replace[' . $macro_id . '] = ((' . $condition . ') ? "' . $code . '" : "' . $falseCode . '"); ';
return '{' . chr(36) . 'macro_replace[' . $macro_id . ']}';
}
/**
* Creates the modlet and stores modlet run statements into an array
*
* @param string modlet to run
* @param string template
* @param bool $getMain Are we loading admincp templates
* @author Geoffrey Dunn
* @return string replace modlet statements with a var
**/
function run_modlet($modlet, $parameter, $piece, $getAdmin)
{
$macro_id = isset($this->macro[$piece]) ? count($this->macro[$piece]) : 0;
// Check the modlet uses valid characters
if (preg_match('/[^a-zA-Z0-9_\-]/', $modlet)) {
return '';
}
if (!isset($this->modlets[$modlet])) {
if ($getAdmin) {
if (!is_readable('../modlets/' . $modlet . '.php')) {
return '';
} else {
require_once('../modlets/' . $modlet . '.php');
}
} else {
if (!is_readable('./modlets/' . $modlet . '.php')) {
return '';
} else {
require_once('./modlets/' . $modlet . '.php');
}
}
$this->modlets[$modlet] =& new $modlet($this);
if ($this->validate($modlet, TYPE_OBJECT, 'modlet')) {
return '';
}
}
$this->macro[$piece][$macro_id] = '$macro_replace[' . $macro_id . '] = (isset($this)) ? $this->modlets["'. $modlet . '"]->run("' . $parameter . '") : $qsf->modlets["'. $modlet . '"]->run("' . $parameter . '"); ';
return '{' . chr(36) . 'macro_replace[' . $macro_id . ']}';
}
/**
* Determines if a user has been banned
*
* @return bool True if the user is banned, false if the user is not
**/
function is_banned()
{
//Ban by user group
if (!$this->perms->auth('do_anything')) {
return true;
}
//Ban by IP
if ($this->sets['banned_ips']) {
foreach ($this->sets['banned_ips'] as $ip)
{
if (preg_match("/$ip/", $this->ip)) {
return true;
}
}
}
return false;
}
/**
* Generates clickable emoticon HTML
*
* @param int $per_row Smilies to show per row
* @author Jason Warner
* @since Beta 3.0
* @return string HTML
**/
function make_clickable($per_row)
{
$return = null;
$x = 0;
if (!$this->replaces_loaded) {
$this->get_replaces();
}
foreach ($this->emotes['replacement_clickable'] as $search => $replace)
{
if (!$x) {
$return .= "\n";
}
$return .= "\n{$replace} ";
if ($x == $per_row - 1) {
$return .= "\n ";
$x = 0;
} else {
$x++;
}
}
if ($x && ($x < $per_row)) {
while ($x < $per_row)
{
$return .= "\n ";
$x++;
}
$return .= "\n ";
}
return $return;
}
/**
* Used as a replacement for date() which deals with time zones
*
* @param mixed $format Date format using date() keywords. Either a date constant or a string.
* @param int $time Timestamp. If left out, uses current time
* @param bool $useToday true if dates should substitute date with 'today' or 'yesterday'
* @author Jason Warner
* @since Beta 2.1
* @return string Human-readable, formatted Unix timestamp
**/
function mbdate($format, $time = 0, $useToday = true)
{
if (!$time) {
$time = $this->time;
}
$time += $this->tz_adjust;
if (is_int($format)) {
switch($format)
{
case DATE_LONG:
$date_format = 'M j, Y';
$time_format = ', g:i a';
break;
case DATE_SHORT:
$date_format = 'n/j/y';
$time_format = ', g:i a';
break;
case DATE_ONLY_LONG:
$date_format = 'M j, Y';
$time_format = '';
break;
case DATE_TIME:
$date_format = '';
$time_format = 'g:i a';
break;
case DATE_ISO822:
$date_format = 'D, j M Y';
$time_format = ' H:i:s T';
break;
default: // DATE_ONLY_SHORT
$date_format = 'n/j/y';
$time_format = '';
break;
}
if (!$useToday) {
$date = gmdate($date_format, $time);
} else if ($date_format) {
$date = gmdate($date_format, $time);
$today = gmdate($date_format, $this->time + $this->tz_adjust);
$yesterday = gmdate($date_format, ($this->time - DAY_IN_SECONDS) + $this->tz_adjust);
if ($today == $date) {
$date = $this->lang->today;
} elseif ($yesterday == $date) {
$date = $this->lang->yesterday;
}
} else {
$date = '';
}
return $date . gmdate($time_format, $time);
} else {
return gmdate($format, $time);
}
}
/**
* Formats a message, error, or notice
*
* @param string $title Title of the message
* @param string $message Text of the message
* @param string $link_text Text for a link
* @param string $link Destination for a link
* @param string $redirect Target for an automated redirect
* @author Jason Warner
* @since Beta 2.0
* @return string HTML-formatted message
**/
function message($title, $message, $link_text = null, $link = null, $redirect = null)
{
if ($link_text) {
$message .= '
' . $link_text . '';
}
if ($redirect) {
@header('Refresh: 4;url=' . $redirect);
}
return eval($this->template('MAIN_MESSAGE'));
}
/**
* Selects a post editing template
*
* @param int $f Forum to test moderator abilities in
* @author Jason Warner
* @since Beta 4.0
* @return array Moderator permissions
**/
function post_box()
{
return 'POST_BOX_PLAIN'; // Not quite ready for Beta 4
if (preg_match('/MSIE ([0-9]\.[0-9]{1,2})/', $this->agent, $browser)) {
if (floor($browser[1]) >= 4) {
if (!isset($this->get['rich'])) { //if ($this->user['post_style'] == 'rich') {
return 'POST_BOX_RICH';
} else {
return 'POST_BOX_PLAIN';
}
}
} else {
return 'POST_BOX_PLAIN';
}
}
/**
* Checks for quote tag formatting
*
* @param string $in Input
* @author Jared Kuolt
* @since 1.1.3
* @return bool Returns true if all quote tags have corresponding end tags
**/
function quote_check($in)
{
$preg_begin = array();
preg_match_all('#\[quote=(.+?)]#i', $in, $out, PREG_PATTERN_ORDER);
if (!empty($out[0])) {
foreach ($out[0] as $match)
{
$preg_begin[] = strpos($in, $match);
}
}
$begin = $this->strpos_array($in, '[quote]'); // Retrieve array for tag beginning
$begin = array_merge($begin, $preg_begin); // Add those with preg_match'd quotes
sort($begin);
$end = $this->strpos_array($in, '[/quote]');
if (count($begin) != count($end)) { // If the counts don't match, return value is false
return false;
}
foreach ($begin as $count => $pos) // Check each occurence
{
if ($pos > $end[$count]) { // If position of the same occurence count of end tag
return false; // is before the begin tag, return value is false
}
}
return true;
}
function select_avatars($current)
{
$out = null;
$dir = opendir('./avatars');
while (($file = readdir($dir)) !== false)
{
if (is_dir('./avatars/' . $file)) {
continue;
}
$split = explode('.', $file);
$ext = array_pop($split);
if (($ext != 'jpg')
&& ($ext != 'jpeg')
&& ($ext != 'gif')
&& ($ext != 'png')) {
continue;
}
$out .= "\n";
}
return $out;
}
function select_days($day)
{
$i = 1;
$out = "\n";
while ($i <= 31)
{
$out .= "\n";
$i++;
}
return $out;
}
/**
* Options for an HTML select box (all forums in correct order)
*
* @param array $array Array of forums
* @param int $select Option to set as selected (-1 for all)
* @param int $parent Used to degredate down through the recursive loop
* @param string $space Used to increment the spacing before the text in the box
* @param bool $identify_category Set to true to place a period before the value of a category
* @author Mark Elliot
* @since Beta 4.0
* @return string Options for an HTML select box (all forums in correct order)
**/
function select_forums($array, $select = 0, $parent = 0, $space = '', $identify_category = false)
{
$arr = $this->forum_array($array, $parent);
$return = null;
foreach ($arr as $val)
{
if (!$this->perms->auth('forum_view', $val['forum_id'])) {
continue;
}
if ($identify_category && !$val['forum_parent']) {
$dot = '.';
} else {
$dot = null;
}
if (($val['forum_id'] != $select) && ($select != -1)) {
$selected = null;
} else {
$selected = ' selected=\'selected\'';
}
$return .= '\n" .
$this->select_forums($array, $select, $val['forum_id'], $space . ' ');
}
return $return;
}
function select_groups($val, $custom_only = false)
{
if ($custom_only) {
$groups = $this->db->query('SELECT group_name, group_id FROM ' . $this->pre . 'groups WHERE group_type="" ORDER BY group_name');
} else {
$groups = $this->db->query('SELECT group_name, group_id FROM ' . $this->pre . 'groups ORDER BY group_name');
}
$out = null;
while ($group = $this->db->nqfetch($groups))
{
$out .= "";
}
return $out;
}
function select_langs($current, $relative = '.')
{
$out = null;
$langs = array();
$dir = opendir($relative . '/languages');
while (($file = readdir($dir)) !== false)
{
if (is_dir($relative . '/languages/' . $file)) {
continue;
}
$code = substr($file, 0, -4);
$ext = substr($file, -4);
if ($ext != '.php') {
continue;
}
$langs[$code] = $this->get_lang_name($code);
}
asort($langs);
foreach ($langs as $code => $name)
{
$out .= "\n";
}
return $out;
}
function select_months($mon)
{
$i = 1;
$out = null;
$month = array(
'00' => '',
'1' => $this->lang->cp_jan,
'2' => $this->lang->cp_feb,
'3' => $this->lang->cp_mar,
'4' => $this->lang->cp_apr,
'5' => $this->lang->cp_may,
'6' => $this->lang->cp_june,
'7' => $this->lang->cp_july,
'8' => $this->lang->cp_aug,
'9' => $this->lang->cp_sept,
'10' => $this->lang->cp_oct,
'11' => $this->lang->cp_nov,
'12' => $this->lang->cp_dec
);
foreach ($month as $digit => $name)
{
$out .= "\n";
}
return $out;
}
/**
* Generates a select box of skins
*
* @param string $skin user_skin to select
* @author Jason Warner
* @since Beta 4.0
* @return string HTML
**/
function select_skins($skin)
{
$out = null;
$query = $this->db->query("SELECT * FROM {$this->pre}skins");
while ($s = $this->db->nqfetch($query))
{
if ($s['skin_dir'] == 'default') {
$s['skin_name'] .= ' (default)';
}
$out .= "\n";
}
return $out;
}
function select_timezones($zone)
{
$out = null;
$query = $this->db->query("SELECT zone_id, zone_name, zone_offset, zone_updated, zone_abbrev FROM {$this->pre}timezones ORDER BY zone_name ASC");
while($row = $this->db->nqfetch($query))
{
if ($row['zone_updated'] < $this->time)
{
include_once('lib/tz_decode2.php');
$tz = new tz_decode2('timezone/'.$row['zone_name']);
$tz->magic2();
if (strlen($tz->abba)<1) $tz->abba='N/A';
$this->db->query("UPDATE {$this->pre}timezones SET zone_offset={$tz->gmt_offset}, zone_updated={$tz->next_update}, zone_abbrev='{$tz->abba}' WHERE zone_id={$row['zone_id']};");
$row['zone_abbrev'] = $tz->abba;
$row['zone_offset'] = $tz->gmt_offset;
}
$padding = str_repeat(' ', 30 - strlen($row['zone_name']));
$out .= ''."\n";
}
return $out;
}
function select_years($year)
{
$thisyear = $this->mbdate('Y');
$i = $thisyear;
$out = "\n";
while ($i >= $thisyear-100)
{
$out .= "\n";
$i--;
}
return $out;
}
/**
* Sets magic_quotes_gpc to on
*
* @param array $array Array to addslashes()
* @author Jason Warner
* @since Beta 4.0
* @return void
**/
function set_magic_quotes_gpc(&$array)
{
$keys = array_keys($array);
for($i = 0; $i < count($array); $i++)
{
if (is_array($array[$keys[$i]])) {
$this->set_magic_quotes_gpc($array[$keys[$i]]);
} else {
$array[$keys[$i]] = addslashes($array[$keys[$i]]);
}
}
}
/**
* Sets the title of the page
*
* @param string $title The title
* @author Jason Warner
* @since Beta 2.0
* @return void
**/
function set_title($title)
{
$this->title = "{$this->sets['forum_name']} - $title";
}
/**
* Handles debug information when $debug is set in the query string
*
* @param int $load Server load
* @param int $totaltime Time to execute the board
* @author Jason Warner
* @since Beta 2.0
* @return void
**/
function show_debug($load, $totaltime)
{
include './func/debug.php';
return $out; // This is set in debug.php
}
/**
* Returns an array of all the positions of needles in a haystack
*
* @param string $haystack Haystack
* @param string $needle Needle
* @author Jared Kuolt
* @since 1.1.3
* @return array Array of positions of needles
**/
function strpos_array($haystack, $needle)
{
$array = array();
$kill = false;
$offset = 0;
while (!$kill)
{
$result = strpos($haystack, $needle, $offset);
if ($result === false) { // If result is false (no more instances found), kill the while loop
$kill = true;
} else {
$array[] = $result; // Set array
$offset = $result + 1; // Offset is set 1 character after previous occurence
}
}
return $array;
}
/**
* Returns a parsed template, for use in eval()
*
* @param string $piece Template name
* @author Jason Warner
* @author Inverno
* @since Beta 1.0
* @return string if statements to eval + Parsed HTML template
**/
function template($piece)
{
if (!isset($this->temps[$piece])) {
error(E_USER_ERROR, "Template not found: $piece", __FILE__, __LINE__);
}
$macro_output = "\$macro_replace = array(); ";
if (isset($this->macro[$piece])) {
foreach ($this->macro[$piece] as $macro_id => $macro_code) {
$macro_output .= $macro_code;
}
}
return "$macro_output return \"\r\n{$this->temps[$piece]}\r\n\r\n\";";
}
/**
* Adds an entry to the navigation tree
*
* @param string $label Label for the tree entry
* @param string $link URL to link to
* @author Jason Warner
* @since Beta 2.1
* @return void
**/
function tree($label, $link = null)
{
$this->tree .= ' » ' . ($link ? "$label" : $label);
}
/**
* Traces a forum back to the parent category and adds entries to the tree - see tree()
*
* @param int $f Forum to generate tree for
* @param bool $linklast True to make the last entry a link (default is false)
* @author Jason Warner
* @since Beta 2.1
* @return void
**/
function tree_forums($f, $linklast = false)
{
$forums = $this->db->query("SELECT forum_tree, forum_id, forum_name FROM {$this->pre}forums ORDER BY forum_id");
while ($forum = $this->db->nqfetch($forums))
{
if (!$this->perms->auth('forum_view', $forum['forum_id'])) {
continue;
}
$id = $forum['forum_id'];
$fid[$id] = $forum['forum_id'];
$ftree[$id] = $forum['forum_tree'];
$fname[$id] = $forum['forum_name'];
}
if (!isset($ftree[$f])) { //error? lets get out while we can
return;
}
$cat = 1; //first forum is always a category
$ft = explode(',', $ftree[$f]);
foreach ($ft as $i)
{
if ($i) {
if (!$cat) {
$this->tree($fname[$i], "$this->self?a=forum&f={$fid[$i]}");
} else {
$this->tree($fname[$i], "$this->self?c={$fid[$i]}");
$cat = 0;
}
}
}
if (!$linklast) {
$this->tree($fname[$f]);
} else {
$this->tree($fname[$f], "$this->self?a=forum&f={$fid[$f]}");
}
}
/**
* Saves all data in the $this->sets array into a file
*
* @param string $sfile File to write settings into (default is settings.php)
* @author Jason Warner
* @since 1.1.0
* @return bool True on success, false on failure
**/
function write_db_sets($sfile = './settings.php')
{
$settings = " $this->sets['db_host'],
'db_name' => $this->sets['db_name'],
'db_pass' => $this->sets['db_pass'],
'db_port' => $this->sets['db_port'],
'db_socket' => $this->sets['db_socket'],
'db_user' => $this->sets['db_user'],
'dbtype' => $this->sets['dbtype'],
'prefix' => $this->sets['prefix'],
'installed' => $this->sets['installed']
);
foreach ($db_settings as $set => $val)
{
$settings .= "\$set['$set'] = '" . str_replace(array('\\', '\''), array('\\\\', '\\\''), $val) . "';\n";
}
$settings .= '?' . '>';
$this->chmod($sfile, 0666);
$fp = @fopen($sfile, 'w');
if (!$fp) {
return false;
}
if (!@fwrite($fp, $settings)) {
return false;
}
fclose($fp);
return true;
}
/**
* Saves all data in the $this->sets array to the database
*
* @author Jason Warner
* @since Beta 2.1
* @return void
**/
function write_sets()
{
$db_settings = array(
'db_host',
'db_name',
'db_pass',
'db_port',
'db_socket',
'db_user',
'dbtype',
'prefix',
'installed'
);
$sets = array();
foreach ($this->sets as $set => $val)
{
if (!in_array($set, $db_settings)) {
$sets[$set] = $val;
}
}
$sets = addslashes(serialize($sets));
$this->db->query("UPDATE {$this->pre}settings SET settings_data='$sets'");
}
/**
* Checks if parameter is valid according to the rules passed
*
* Typical uses are:
* validate($this->get['f'], TYPE_UINT)
* validate($this->get['order'], TYPE_STRING, array('title', 'starter', 'replies', 'views'), '')
* validate($this->post['adminemail'], TYPE_EMAIL, null, 'root@localhost')
*
*
* @author Geoffrey Dunn
* @since 1.1.5
* @param mixed $var Variable from the user, typically a get or post
* @param int $type Type to check against. See TYPE defaults in constants.php
* @param array $range optional A range of values of $type the variable must match
* @param mixed $default optional A default value if the check fails
* @return true if $var is valid and unchanged, false if a match failed
*/
function validate(&$var, $type, $range=null, $default=null)
{
$unchanged = true;
switch($type) {
case TYPE_BOOLEAN:
// $range and $default are unused
if (!is_bool($var)) {
$unchanged = false;
}
$var = (true && $var); // Convert to a proper boolean
break;
case TYPE_UINT:
$newvar = intval($var);
if ($newvar != $var || $newvar < 0 || ($range != null && !in_array($var, $range))) {
$unchanged = false;
if ($default != null) $newvar = $default;
}
$var = $newvar;
break;
case TYPE_INT:
$newvar = intval($var);
if ($newvar != $var || ($range != null && !in_array($var, $range))) {
$unchanged = false;
if ($default != null) $newvar = $default;
}
$var = $newvar;
break;
case TYPE_FLOAT:
if (!is_numeric($var) || ($range != null && !in_array($var, $range))) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_STRING:
if (!is_string($var) || ($range != null && !in_array($var, $range))) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_ARRAY:
// $range is unused
if (!is_array($var)) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_OBJECT:
// $range is seen as a class name
if (!is_object($var) || ($range != null && !is_subclass_of($var, $range))) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_USERNAME:
// $range is unused
if (strlen($username) > 20) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_PASSWORD:
// $range is unused
if (!preg_match("/^[a-z0-9_\- ]{5,}$/i", $pass)) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
case TYPE_EMAIL:
// $range is unused
if (!$this->is_valid_email_address($var)) {
$unchanged = false;
if ($default != null) $var = $default;
}
break;
default:
// Invalid type! Only developers should ever see this error
error(QUICKSILVER_ERROR, "Invalid type sent to validate()", __FILE__, __LINE__);
}
return $unchanged;
}
/* Forum utility functions */
/**
* Used to update topic and reply counts for every forum.
*
* @author Mark Elliot
* @since Beta 2.1
* @return string Completion message
**/
function RecountForums()
{
// Recount all topics and posts - NiteShdw
$q = $this->db->query("SELECT topic_id, COUNT(post_id) AS replies FROM {$this->pre}topics, {$this->pre}posts WHERE post_topic=topic_id GROUP BY topic_id");
while ($f = $this->db->nqfetch($q))
{
$treplies = $f['replies'] - 1;
$this->db->query("UPDATE {$this->pre}topics SET topic_replies={$treplies} WHERE topic_id={$f['topic_id']}");
}
$q = $this->db->query("SELECT forum_id FROM {$this->pre}forums WHERE forum_parent = 0");
$this->sets['posts'] = 0;
$this->sets['topics'] = 0;
while ($f = $this->db->nqfetch($q))
{
$results = $this->countTopicsAndReplies($f['forum_id']);
$this->sets['posts'] += $results['replies'];
$this->sets['topics'] += $results['topics'];
}
$this->write_sets();
return "Recounted forums! Total topics: {$this->sets['topics']}. Total posts: {$this->sets['posts']}.";
}
/**
* Used for recursive topic and reply counting
*
* @author Geoffrey Dunn
* @since 1.1.5
* @param Forum to count
* @return Array containing topic Count, reply Count, last post, last post time
**/
function countTopicsAndReplies($forum)
{
// Initalise locals
$topicCount = 0;
$replyCount = 0;
$lastPostTime = 0;
$lastPost = 0;
// Check for subforums
$q = $this->db->query("SELECT forum_id FROM {$this->pre}forums WHERE forum_parent=$forum");
while ($f = $this->db->nqfetch($q))
{
$results = $this->countTopicsAndReplies($f['forum_id']);
$topicCount += $results['topics'];
$replyCount += $results['replies'];
if ($results['lastPostTime'] > $lastPostTime) {
$lastPostTime = $results['lastPostTime'];
$lastPost = $results['lastPost'];
}
}
// Count topics on this forum
$tc = $this->db->fetch('SELECT COUNT(topic_id) tc
FROM ' . $this->pre . 'topics
WHERE NOT(topic_modes & ' . TOPIC_MOVED . ') AND topic_forum=' . $forum);
$rc = $this->db->fetch('SELECT COUNT(p.post_id) rc
FROM ' . $this->pre . 'posts p, ' . $this->pre . 'topics t
WHERE p.post_topic=t.topic_id AND topic_forum=' . $forum);
$lp = $this->db->fetch('SELECT p.post_time pt, p.post_id post
FROM ' . $this->pre . 'posts p, ' . $this->pre . 'topics t
WHERE p.post_topic=t.topic_id AND topic_forum=' . $forum . '
ORDER BY p.post_time DESC LIMIT 1');
$topicCount += $tc['tc'];
$replyCount += $rc['rc'];
if ($lp['pt'] > $lastPostTime) {
$lastPostTime = $lp['pt'];
$lastPost = $lp['post'];
}
// Update the details
$this->db->query("UPDATE {$this->pre}forums SET forum_replies='" . ($replyCount - $topicCount) . "',
forum_topics='{$topicCount}', forum_lastpost='{$lastPost}' WHERE forum_id='{$forum}'");
return array('topics' => $topicCount, 'replies' => $replyCount, 'lastPost' => $lastPost, 'lastPostTime' => $lastPostTime);
}
/**
* Update Forum Trees
*
* @author Geoffrey Dunn
* @since 1.1.5
**/
function updateForumTrees()
{
$forums = array();
$forumTree = array();
// Build tree structure of 'id' => 'parent' structure
$q = $this->db->query("SELECT forum_id, forum_parent FROM {$this->pre}forums ORDER BY forum_parent");
while ($f = $this->db->nqfetch($q))
{
if ($f['forum_parent']) {
$forums[$f['forum_id']] = $f['forum_parent'];
}
}
// Run through group
$q = $this->db->query("SELECT forum_parent FROM {$this->pre}forums GROUP BY forum_parent");
while ($f = $this->db->nqfetch($q))
{
if ($f['forum_parent']) {
$tree = $this->buildTree($forums, $f['forum_parent']);
} else {
$tree = '';
}
$this->db->query("UPDATE {$this->pre}forums SET forum_tree='$tree' WHERE forum_parent={$f['forum_parent']}");
}
}
function buildTree($forumsArray, $parent)
{
$tree = '';
if (isset($forumsArray[$parent]) && $forumsArray[$parent]) {
$tree = $this->buildTree($forumsArray, $forumsArray[$parent]);
$tree .= ',';
}
$tree .= $parent;
return $tree;
}
}
/**
* Handles error messages
*
* @param int $type The error code
* @param string $message A string describing the error
* @param string $file The filename in which the error occurred
* @param int $line The line number on which the error occurred
* @author Jason Warner
* @since Beta 2.0
* @return void
**/
function error($type, $message, $file = null, $line = 0)
{
if (isset($_GET['debug']) || function_exists('error_fatal') || !(error_reporting() & $type)) {
return;
}
$include = './lib/error.php';
if (!file_exists($include)) {
$include = '.' . $include; // Admin Center errors
}
include $include;
switch($type)
{
// Triggered Quicksilver Forums errors
case QUICKSILVER_ERROR:
exit(error_warning($message, $file, $line));
break;
// Triggered Quicksilver Forums notices and alerts
case QUICKSILVER_NOTICE:
exit(error_notice($message));
break;
// Database errors
case QUICKSILVER_QUERY_ERROR:
exit(error_fatal($type, $message, $file, $line));
break;
// PHP errors
default:
exit(error_fatal($type, $message, $file, $line));
break;
}
}
?>