6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
11 // Common global functions
16 * Set variable, used by {@link request_var the request_var function}
20 function set_var(&$result, $var, $type, $multibyte = false)
25 if ($type == 'string')
27 $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result)));
28 $result = (STRIP
) ?
stripslashes($result) : $result;
30 // Check for possible multibyte characters to save a preg_replace call if nothing is in there...
31 if ($multibyte && strpos($result, '&#') !== false)
33 $result = preg_replace('#&(\#[0-9]+;)#', '&\1', $result);
41 * Used to get passed variable
43 function request_var($var_name, $default, $multibyte = false)
45 if (!isset($_REQUEST[$var_name]) ||
(is_array($_REQUEST[$var_name]) && !is_array($default)) ||
(is_array($default) && !is_array($_REQUEST[$var_name])))
47 return (is_array($default)) ?
array() : $default;
50 $var = $_REQUEST[$var_name];
51 if (!is_array($default))
53 $type = gettype($default);
57 list($key_type, $type) = each($default);
58 $type = gettype($type);
59 $key_type = gettype($key_type);
67 foreach ($_var as $k => $v)
71 foreach ($v as $_k => $_v)
73 set_var($k, $k, $key_type);
74 set_var($_k, $_k, $key_type);
75 set_var($var[$k][$_k], $_v, $type, $multibyte);
80 set_var($k, $k, $key_type);
81 set_var($var[$k], $v, $type, $multibyte);
87 set_var($var, $var, $type, $multibyte);
94 * Set config value. Creates missing config entry.
96 function set_config($config_name, $config_value, $is_dynamic = false)
98 global $db, $cache, $config;
100 $sql = 'UPDATE ' . CONFIG_TABLE
. "
101 SET config_value = '" . $db->sql_escape($config_value) . "'
102 WHERE config_name = '" . $db->sql_escape($config_name) . "'";
103 $db->sql_query($sql);
105 if (!$db->sql_affectedrows() && !isset($config[$config_name]))
107 $sql = 'INSERT INTO ' . CONFIG_TABLE
. ' ' . $db->sql_build_array('INSERT', array(
108 'config_name' => $config_name,
109 'config_value' => $config_value,
110 'is_dynamic' => ($is_dynamic) ?
1 : 0));
111 $db->sql_query($sql);
114 $config[$config_name] = $config_value;
118 $cache->destroy('config');
123 * Generates an alphanumeric random string of given length
125 function gen_rand_string($num_chars = 8)
127 $rand_str = unique_id();
128 $rand_str = str_replace('0', 'Z', strtoupper(base_convert($rand_str, 16, 35)));
130 return substr($rand_str, 0, $num_chars);
135 * @param $extra additional entropy
137 function unique_id($extra = 'c')
142 $val = $config['rand_seed'] . microtime();
144 $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
146 if ($dss_seeded !== true)
148 set_config('rand_seed', $config['rand_seed'], true);
152 return substr($val, 4, 16);
156 * Generate sort selection fields
158 function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, &$sort_dir, &$s_limit_days, &$s_sort_key, &$s_sort_dir, &$u_sort_param)
162 $sort_dir_text = array('a' => $user->lang
['ASCENDING'], 'd' => $user->lang
['DESCENDING']);
164 $s_limit_days = '<select name="st">';
165 foreach ($limit_days as $day => $text)
167 $selected = ($sort_days == $day) ?
' selected="selected"' : '';
168 $s_limit_days .= '<option value="' . $day . '"' . $selected . '>' . $text . '</option>';
170 $s_limit_days .= '</select>';
172 $s_sort_key = '<select name="sk">';
173 foreach ($sort_by_text as $key => $text)
175 $selected = ($sort_key == $key) ?
' selected="selected"' : '';
176 $s_sort_key .= '<option value="' . $key . '"' . $selected . '>' . $text . '</option>';
178 $s_sort_key .= '</select>';
180 $s_sort_dir = '<select name="sd">';
181 foreach ($sort_dir_text as $key => $value)
183 $selected = ($sort_dir == $key) ?
' selected="selected"' : '';
184 $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
186 $s_sort_dir .= '</select>';
188 $u_sort_param = "st=$sort_days&sk=$sort_key&sd=$sort_dir";
196 function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false)
198 global $config, $auth, $template, $user, $db, $phpEx;
200 if (!$config['load_jumpbox'])
205 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
206 FROM ' . FORUMS_TABLE
. '
207 ORDER BY left_id ASC';
208 $result = $db->sql_query($sql, 600);
210 $right = $padding = 0;
211 $padding_store = array('0' => 0);
212 $display_jumpbox = false;
215 // Sometimes it could happen that forums will be displayed here not be displayed within the index page
216 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
217 // If this happens, the padding could be "broken"
219 while ($row = $db->sql_fetchrow($result))
221 if ($row['left_id'] < $right)
224 $padding_store[$row['parent_id']] = $padding;
226 else if ($row['left_id'] > $right +
1)
228 $padding = $padding_store[$row['parent_id']];
231 $right = $row['right_id'];
233 if ($row['forum_type'] == FORUM_CAT
&& ($row['left_id'] +
1 == $row['right_id']))
235 // Non-postable forum with no subforums, don't display
239 if (!$auth->acl_get('f_list', $row['forum_id']))
241 // if the user does not have permissions to list this forum skip
245 if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
250 if (!$display_jumpbox)
252 $template->assign_block_vars('jumpbox_forums', array(
253 'FORUM_ID' => ($select_all) ?
0 : -1,
254 'FORUM_NAME' => ($select_all) ?
$user->lang
['ALL_FORUMS'] : $user->lang
['SELECT_FORUM'],
255 'S_FORUM_COUNT' => $iteration)
259 $display_jumpbox = true;
262 $template->assign_block_vars('jumpbox_forums', array(
263 'FORUM_ID' => $row['forum_id'],
264 'FORUM_NAME' => $row['forum_name'],
265 'SELECTED' => ($row['forum_id'] == $forum_id) ?
' selected="selected"' : '',
266 'S_FORUM_COUNT' => $iteration,
267 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT
) ?
true : false,
268 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK
) ?
true : false,
269 'S_IS_POST' => ($row['forum_type'] == FORUM_POST
) ?
true : false)
272 for ($i = 0; $i < $padding; $i++
)
274 $template->assign_block_vars('jumpbox_forums.level', array());
278 $db->sql_freeresult($result);
279 unset($padding_store);
281 $template->assign_vars(array(
282 'S_DISPLAY_JUMPBOX' => $display_jumpbox,
283 'S_JUMPBOX_ACTION' => $action)
290 // Compatibility functions
292 if (!function_exists('array_combine'))
295 * A wrapper for the PHP5 function array_combine()
296 * @param array $keys contains keys for the resulting array
297 * @param array $values contains values for the resulting array
299 * @return Returns an array by using the values from the keys array as keys and the
300 * values from the values array as the corresponding values. Returns false if the
301 * number of elements for each array isn't equal or if the arrays are empty.
303 function array_combine($keys, $values)
305 $keys = array_values($keys);
306 $values = array_values($values);
309 $m = sizeof($values);
310 if (!$n ||
!$m ||
($n != $m))
316 for ($i = 0; $i < $n; $i++
)
318 $combined[$keys[$i]] = $values[$i];
324 if (!function_exists('str_split'))
327 * A wrapper for the PHP5 function str_split()
328 * @param array $string contains the string to be converted
329 * @param array $split_length contains the length of each chunk
331 * @return Converts a string to an array. If the optional split_length parameter is specified,
332 * the returned array will be broken down into chunks with each being split_length in length,
333 * otherwise each chunk will be one character in length. FALSE is returned if split_length is
334 * less than 1. If the split_length length exceeds the length of string, the entire string is
335 * returned as the first (and only) array element.
337 function str_split($string, $split_length = 1)
339 if ($split_length < 1)
343 else if ($split_length >= strlen($string))
345 return array($string);
349 preg_match_all('#.{1,' . $split_length . '}#s', $string, $matches);
355 if (!function_exists('stripos'))
358 * A wrapper for the PHP5 function stripos
359 * Find position of first occurrence of a case-insensitive string
361 * @param string $haystack is the string to search in
362 * @param string needle is the string to search for
364 * @return Returns the numeric position of the first occurrence of needle in the haystack string. Unlike strpos(), stripos() is case-insensitive.
365 * Note that the needle may be a string of one or more characters.
366 * If needle is not found, stripos() will return boolean FALSE.
368 function stripos($haystack, $needle)
370 if (preg_match('#' . preg_quote($needle, '#') . '#i', $haystack, $m))
372 return strpos($haystack, $m[0]);
379 if (!function_exists('realpath'))
381 if (substr(PHP_OS
, 0, 3) != 'WIN' && !(bool) ini_get('safe_mode') && function_exists('shell_exec') && trim(`realpath
.`
))
384 * @author Chris Smith <chris@project-minerva.org>
385 * @copyright 2006 Project Minerva Team
386 * @param string $path The path which we should attempt to resolve.
389 function phpbb_realpath($path)
391 $arg = escapeshellarg($path);
392 return trim(`realpath
'$arg'`
);
398 * Checks if a path ($path) is absolute or relative
400 * @param string $path Path to check absoluteness of
403 function is_absolute($path)
405 return ($path[0] == '/' ||
(substr(PHP_OS
, 0, 3) == 'WIN' && preg_match('#^[a-z]:/#i', $path))) ?
true : false;
409 * @author Chris Smith <chris@project-minerva.org>
410 * @copyright 2006 Project Minerva Team
411 * @param string $path The path which we should attempt to resolve.
414 function phpbb_realpath($path)
416 // Now to perform funky shizzle
418 // Switch to use UNIX slashes
419 $path = str_replace(DIRECTORY_SEPARATOR
, '/', $path);
422 // Determine what sort of path we have
423 if (is_absolute($path))
429 // Absolute path, *NIX style
434 // Absolute path, Windows style
435 // Remove the drive letter and colon
436 $path_prefix = $path[0] . ':';
437 $path = substr($path, 2);
443 // Prepend the current working directory
444 if (function_exists('getcwd'))
446 // This is the best method, hopefully it is enabled!
447 $path = str_replace(DIRECTORY_SEPARATOR
, '/', getcwd()) . '/' . $path;
449 if (preg_match('#^[a-z]:#i', $path))
451 $path_prefix = $path[0] . ':';
452 $path = substr($path, 2);
459 else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
461 // Warning: If chdir() has been used this will lie!
462 // @todo This has some problems sometime (CLI can create them easily)
463 $path = str_replace(DIRECTORY_SEPARATOR
, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
469 // We have no way of getting the absolute path, just run on using relative ones.
475 // Remove any repeated slashes
476 $path = preg_replace('#/{2,}#', '/', $path);
478 // Remove the slashes from the start and end of the path
479 $path = trim($path, '/');
481 // Break the string into little bits for us to nibble on
482 $bits = explode('/', $path);
484 // Remove any . in the path
485 $bits = array_diff($bits, array('.'));
487 // Lets get looping, run over and resolve any .. (up directory)
488 for ($i = 0, $max = sizeof($bits); $i < $max; $i++
)
491 if ($bits[$i] == '..' )
493 if (isset($bits[$i - 1]))
495 if ($bits[$i - 1] != '..')
497 // We found a .. and we are able to traverse upwards, lets do it!
499 unset($bits[$i - 1]);
502 $bits = array_values($bits);
505 else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
507 // We have an absolute path trying to descend above the root of the filesystem
514 // Prepend the path prefix
515 array_unshift($bits, $path_prefix);
519 $max = sizeof($bits) - 1;
521 // Check if we are able to resolve symlinks, Windows cannot.
522 $symlink_resolve = (function_exists('readlink')) ?
true : false;
524 foreach ($bits as $i => $bit)
526 if (@is_dir
("$resolved/$bit") ||
($i == $max && @is_file
("$resolved/$bit")))
529 if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
531 // Resolved a symlink.
532 $resolved = $link . (($i == $max) ?
'' : '/');
538 // Something doesn't exist here!
539 // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
542 $resolved .= $bit . (($i == $max) ?
'' : '/');
545 // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
546 // because we must be inside that basedir, the question is where...
547 // @interal The slash in is_dir() gets around an open_basedir restriction
548 if (!@file_exists
($resolved) ||
(!is_dir($resolved . '/') && !is_file($resolved)))
553 // Put the slashes back to the native operating systems slashes
554 $resolved = str_replace('/', DIRECTORY_SEPARATOR
, $resolved);
556 return $resolved; // We got here, in the end!
563 * A wrapper for realpath
565 function phpbb_realpath($path)
567 return realpath($path);
571 // functions used for building option fields
574 * Pick a language, any language ...
576 function language_select($default = '')
580 $sql = 'SELECT lang_iso, lang_local_name
581 FROM ' . LANG_TABLE
. '
582 ORDER BY lang_english_name';
583 $result = $db->sql_query($sql, 600);
586 while ($row = $db->sql_fetchrow($result))
588 $selected = ($row['lang_iso'] == $default) ?
' selected="selected"' : '';
589 $lang_options .= '<option value="' . $row['lang_iso'] . '"' . $selected . '>' . $row['lang_local_name'] . '</option>';
591 $db->sql_freeresult($result);
593 return $lang_options;
597 * Pick a template/theme combo,
599 function style_select($default = '', $all = false)
603 $sql_where = (!$all) ?
'WHERE style_active = 1 ' : '';
604 $sql = 'SELECT style_id, style_name
605 FROM ' . STYLES_TABLE
. "
607 ORDER BY style_name";
608 $result = $db->sql_query($sql);
611 while ($row = $db->sql_fetchrow($result))
613 $selected = ($row['style_id'] == $default) ?
' selected="selected"' : '';
614 $style_options .= '<option value="' . $row['style_id'] . '"' . $selected . '>' . $row['style_name'] . '</option>';
616 $db->sql_freeresult($result);
618 return $style_options;
624 function tz_select($default = '', $truncate = false)
626 global $sys_timezone, $user;
629 foreach ($user->lang
['tz_zones'] as $offset => $zone)
633 $zone = (strlen($zone) > 70) ?
substr($zone, 0, 70) . '...' : $zone;
636 if (is_numeric($offset))
638 $selected = ($offset == $default) ?
' selected="selected"' : '';
639 $tz_select .= '<option value="' . $offset . '"' . $selected . '>' . $zone . '</option>';
646 // Functions handling topic/post tracking/marking
649 * Marks a topic/forum as read
650 * Marks a topic as posted to
652 * @param int $user_id can only be used with $mode == 'post'
654 function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
656 global $db, $user, $config;
660 if ($forum_id === false ||
!sizeof($forum_id))
662 if ($config['load_db_lastread'] && $user->data
['is_registered'])
664 // Mark all forums read (index page)
665 $db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE
. " WHERE user_id = {$user->data['user_id']}");
666 $db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE
. " WHERE user_id = {$user->data['user_id']}");
667 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
669 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
671 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
672 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
674 unset($tracking_topics['tf']);
675 unset($tracking_topics['t']);
676 unset($tracking_topics['f']);
677 $tracking_topics['l'] = base_convert(time() - $config['board_startdate'], 10, 36);
679 $user->set_cookie('track', serialize($tracking_topics), time() +
31536000);
680 unset($tracking_topics);
682 if ($user->data
['is_registered'])
684 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
691 else if ($mode == 'topics')
693 // Mark all topics in forums read
694 if (!is_array($forum_id))
696 $forum_id = array($forum_id);
699 // Add 0 to forums array to mark global announcements correctly
702 if ($config['load_db_lastread'] && $user->data
['is_registered'])
704 $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE
. "
705 WHERE user_id = {$user->data['user_id']}
706 AND " . $db->sql_in_set('forum_id', $forum_id);
707 $db->sql_query($sql);
709 $sql = 'SELECT forum_id
710 FROM ' . FORUMS_TRACK_TABLE
. "
711 WHERE user_id = {$user->data['user_id']}
712 AND " . $db->sql_in_set('forum_id', $forum_id);
713 $result = $db->sql_query($sql);
715 $sql_update = array();
716 while ($row = $db->sql_fetchrow($result))
718 $sql_update[] = $row['forum_id'];
720 $db->sql_freeresult($result);
722 if (sizeof($sql_update))
724 $sql = 'UPDATE ' . FORUMS_TRACK_TABLE
. '
725 SET mark_time = ' . time() . "
726 WHERE user_id = {$user->data['user_id']}
727 AND " . $db->sql_in_set('forum_id', $sql_update);
728 $db->sql_query($sql);
731 if ($sql_insert = array_diff($forum_id, $sql_update))
734 foreach ($sql_insert as $f_id)
737 'user_id' => $user->data
['user_id'],
739 'mark_time' => time()
743 if (sizeof($sql_ary))
750 $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE
. ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary));
754 foreach ($sql_ary as $ary)
756 $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE
. ' ' . $db->sql_build_array('INSERT', $ary));
763 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
765 $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
766 $tracking = ($tracking) ?
unserialize($tracking) : array();
768 foreach ($forum_id as $f_id)
770 $topic_ids36 = (isset($tracking['tf'][$f_id])) ?
$tracking['tf'][$f_id] : array();
772 if (isset($tracking['tf'][$f_id]))
774 unset($tracking['tf'][$f_id]);
777 foreach ($topic_ids36 as $topic_id36)
779 unset($tracking['t'][$topic_id36]);
782 if (isset($tracking['f'][$f_id]))
784 unset($tracking['f'][$f_id]);
787 $tracking['f'][$f_id] = base_convert(time() - $config['board_startdate'], 10, 36);
790 $user->set_cookie('track', serialize($tracking), time() +
31536000);
796 else if ($mode == 'topic')
798 if ($topic_id === false ||
$forum_id === false)
803 if ($config['load_db_lastread'] && $user->data
['is_registered'])
805 $sql = 'UPDATE ' . TOPICS_TRACK_TABLE
. '
806 SET mark_time = ' . (($post_time) ?
$post_time : time()) . "
807 WHERE user_id = {$user->data['user_id']}
808 AND topic_id = $topic_id";
809 $db->sql_query($sql);
812 if (!$db->sql_affectedrows())
814 $db->sql_return_on_error(true);
817 'user_id' => $user->data
['user_id'],
818 'topic_id' => $topic_id,
819 'forum_id' => (int) $forum_id,
820 'mark_time' => ($post_time) ?
$post_time : time(),
823 $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
825 $db->sql_return_on_error(false);
828 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
830 $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
831 $tracking = ($tracking) ?
unserialize($tracking) : array();
833 $topic_id36 = base_convert($topic_id, 10, 36);
835 if (!isset($tracking['t'][$topic_id36]))
837 $tracking['tf'][$forum_id][$topic_id36] = true;
840 $post_time = ($post_time) ?
$post_time : time();
841 $tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36);
843 // If the cookie grows larger than 10000 characters we will remove the smallest value
844 // This can result in old topics being unread - but most of the time it should be accurate...
845 if (isset($_COOKIE[$config['cookie_name'] . '_track']) && strlen($_COOKIE[$config['cookie_name'] . '_track']) > 10000)
847 //echo 'Cookie grown too large' . print_r($tracking, true);
849 // We get the ten most minimum stored time offsets and its associated topic ids
850 $time_keys = array();
851 for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++
)
853 $min_value = min($tracking['t']);
854 $m_tkey = array_search($min_value, $tracking['t']);
855 unset($tracking['t'][$m_tkey]);
857 $time_keys[$m_tkey] = $min_value;
860 // Now remove the topic ids from the array...
861 foreach ($tracking['tf'] as $f_id => $topic_id_ary)
863 foreach ($time_keys as $m_tkey => $min_value)
865 if (isset($topic_id_ary[$m_tkey]))
867 $tracking['f'][$f_id] = $min_value;
868 unset($tracking['tf'][$f_id][$m_tkey]);
873 if ($user->data
['is_registered'])
875 $user->data
['user_lastmark'] = intval(base_convert(max($time_keys) +
$config['board_startdate'], 36, 10));
876 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . $user->data
['user_lastmark'] . " WHERE user_id = {$user->data['user_id']}");
880 $tracking['l'] = max($time_keys);
884 $user->set_cookie('track', serialize($tracking), time() +
31536000);
889 else if ($mode == 'post')
891 if ($topic_id === false)
896 $use_user_id = (!$user_id) ?
$user->data
['user_id'] : $user_id;
898 if ($config['load_db_track'] && $use_user_id != ANONYMOUS
)
900 $db->sql_return_on_error(true);
903 'user_id' => $use_user_id,
904 'topic_id' => $topic_id,
908 $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
910 $db->sql_return_on_error(false);
918 * Get topic tracking info by using already fetched info
920 function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
922 global $config, $user;
924 $last_read = array();
926 if (!is_array($topic_ids))
928 $topic_ids = array($topic_ids);
931 foreach ($topic_ids as $topic_id)
933 if (!empty($rowset[$topic_id]['mark_time']))
935 $last_read[$topic_id] = $rowset[$topic_id]['mark_time'];
939 $topic_ids = array_diff($topic_ids, array_keys($last_read));
941 if (sizeof($topic_ids))
943 $mark_time = array();
945 // Get global announcement info
946 if ($global_announce_list && sizeof($global_announce_list))
948 if (!isset($forum_mark_time[0]))
952 $sql = 'SELECT mark_time
953 FROM ' . FORUMS_TRACK_TABLE
. "
954 WHERE user_id = {$user->data['user_id']}
956 $result = $db->sql_query($sql);
957 $row = $db->sql_fetchrow($result);
958 $db->sql_freeresult($result);
962 $mark_time[0] = $row['mark_time'];
967 if ($forum_mark_time[0] !== false)
969 $mark_time[0] = $forum_mark_time[0];
974 if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false)
976 $mark_time[$forum_id] = $forum_mark_time[$forum_id];
979 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user->data
['user_lastmark'];
981 foreach ($topic_ids as $topic_id)
983 if ($global_announce_list && isset($global_announce_list[$topic_id]))
985 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
989 $last_read[$topic_id] = $user_lastmark;
998 * Get topic tracking info from db (for cookie based tracking only this function is used)
1000 function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false)
1002 global $config, $user;
1004 $last_read = array();
1006 if (!is_array($topic_ids))
1008 $topic_ids = array($topic_ids);
1011 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1015 $sql = 'SELECT topic_id, mark_time
1016 FROM ' . TOPICS_TRACK_TABLE
. "
1017 WHERE user_id = {$user->data['user_id']}
1018 AND " . $db->sql_in_set('topic_id', $topic_ids);
1019 $result = $db->sql_query($sql);
1021 while ($row = $db->sql_fetchrow($result))
1023 $last_read[$row['topic_id']] = $row['mark_time'];
1025 $db->sql_freeresult($result);
1027 $topic_ids = array_diff($topic_ids, array_keys($last_read));
1029 if (sizeof($topic_ids))
1031 $sql = 'SELECT forum_id, mark_time
1032 FROM ' . FORUMS_TRACK_TABLE
. "
1033 WHERE user_id = {$user->data['user_id']}
1035 (($global_announce_list && sizeof($global_announce_list)) ?
"IN (0, $forum_id)" : "= $forum_id");
1036 $result = $db->sql_query($sql);
1038 $mark_time = array();
1039 while ($row = $db->sql_fetchrow($result))
1041 $mark_time[$row['forum_id']] = $row['mark_time'];
1043 $db->sql_freeresult($result);
1045 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user->data
['user_lastmark'];
1047 foreach ($topic_ids as $topic_id)
1049 if ($global_announce_list && isset($global_announce_list[$topic_id]))
1051 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
1055 $last_read[$topic_id] = $user_lastmark;
1060 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1062 global $tracking_topics;
1064 if (!isset($tracking_topics) ||
!sizeof($tracking_topics))
1066 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
1067 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
1070 if (!$user->data
['is_registered'])
1072 $user_lastmark = (isset($tracking_topics['l'])) ?
base_convert($tracking_topics['l'], 36, 10) +
$config['board_startdate'] : 0;
1076 $user_lastmark = $user->data
['user_lastmark'];
1079 foreach ($topic_ids as $topic_id)
1081 $topic_id36 = base_convert($topic_id, 10, 36);
1083 if (isset($tracking_topics['t'][$topic_id36]))
1085 $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) +
$config['board_startdate'];
1089 $topic_ids = array_diff($topic_ids, array_keys($last_read));
1091 if (sizeof($topic_ids))
1093 $mark_time = array();
1094 if ($global_announce_list && sizeof($global_announce_list))
1096 if (isset($tracking_topics['f'][0]))
1098 $mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) +
$config['board_startdate'];
1102 if (isset($tracking_topics['f'][$forum_id]))
1104 $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) +
$config['board_startdate'];
1107 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user_lastmark;
1109 foreach ($topic_ids as $topic_id)
1111 if ($global_announce_list && isset($global_announce_list[$topic_id]))
1113 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
1117 $last_read[$topic_id] = $user_lastmark;
1127 * Check for read forums and update topic tracking info accordingly
1129 * @param int $forum_id the forum id to check
1130 * @param int $forum_last_post_time the forums last post time
1131 * @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled
1132 * @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time
1134 * @return true if complete forum got marked read, else false.
1136 function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
1138 global $db, $tracking_topics, $user, $config;
1140 // Determine the users last forum mark time if not given.
1141 if ($mark_time_forum === false)
1143 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1145 $mark_time_forum = (!empty($f_mark_time)) ?
$f_mark_time : $user->data
['user_lastmark'];
1147 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1149 if (!isset($tracking_topics) ||
!sizeof($tracking_topics))
1151 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
1152 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
1155 if (!$user->data
['is_registered'])
1157 $user->data
['user_lastmark'] = (isset($tracking_topics['l'])) ?
(int) (base_convert($tracking_topics['l'], 36, 10) +
$config['board_startdate']) : 0;
1160 $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ?
(int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) +
$config['board_startdate']) : $user->data
['user_lastmark'];
1164 // Check the forum for any left unread topics.
1165 // If there are none, we mark the forum as read.
1166 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1168 if ($mark_time_forum >= $forum_last_post_time)
1170 // We do not need to mark read, this happened before. Therefore setting this to true
1175 $sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE
. ' t
1176 LEFT JOIN ' . TOPICS_TRACK_TABLE
. ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data
['user_id'] . ')
1177 WHERE t.forum_id = ' . $forum_id . '
1178 AND t.topic_last_post_time > ' . $mark_time_forum . '
1179 AND t.topic_moved_id = 0
1180 AND tt.topic_id IS NULL
1181 GROUP BY t.forum_id';
1182 $result = $db->sql_query_limit($sql, 1);
1183 $row = $db->sql_fetchrow($result);
1184 $db->sql_freeresult($result);
1187 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1189 // Get information from cookie
1192 if (!isset($tracking_topics['tf'][$forum_id]))
1194 // We do not need to mark read, this happened before. Therefore setting this to true
1199 $sql = 'SELECT topic_id
1200 FROM ' . TOPICS_TABLE
. '
1201 WHERE forum_id = ' . $forum_id . '
1202 AND topic_last_post_time > ' . $mark_time_forum . '
1203 AND topic_moved_id = 0';
1204 $result = $db->sql_query($sql);
1206 $check_forum = $tracking_topics['tf'][$forum_id];
1208 while ($row = $db->sql_fetchrow($result))
1210 if (!in_array(base_convert($row['topic_id'], 10, 36), array_keys($check_forum)))
1216 $db->sql_freeresult($result);
1228 markread('topics', $forum_id);
1235 // Pagination functions
1238 * Pagination routine, generates page number sequence
1239 * tpl_prefix is for using different pagination blocks at one page
1241 function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '')
1243 global $template, $user;
1245 $seperator = $user->theme
['pagination_sep'];
1246 $total_pages = ceil($num_items/$per_page);
1248 if ($total_pages == 1 ||
!$num_items)
1253 $on_page = floor($start_item / $per_page) +
1;
1254 $page_string = ($on_page == 1) ?
'<strong>1</strong>' : '<a href="' . $base_url . '">1</a>';
1256 if ($total_pages > 5)
1258 $start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
1259 $end_cnt = max(min($total_pages, $on_page +
4), 6);
1261 $page_string .= ($start_cnt > 1) ?
' ... ' : $seperator;
1263 for ($i = $start_cnt +
1; $i < $end_cnt; $i++
)
1265 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "&start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1266 if ($i < $end_cnt - 1)
1268 $page_string .= $seperator;
1272 $page_string .= ($end_cnt < $total_pages) ?
' ... ' : $seperator;
1276 $page_string .= $seperator;
1278 for ($i = 2; $i < $total_pages; $i++
)
1280 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "&start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1281 if ($i < $total_pages)
1283 $page_string .= $seperator;
1288 $page_string .= ($on_page == $total_pages) ?
'<strong>' . $total_pages . '</strong>' : '<a href="' . $base_url . '&start=' . (($total_pages - 1) * $per_page) . '">' . $total_pages . '</a>';
1290 if ($add_prevnext_text)
1294 $page_string = '<a href="' . $base_url . '&start=' . (($on_page - 2) * $per_page) . '">' . $user->lang
['PREVIOUS'] . '</a> ' . $page_string;
1297 if ($on_page != $total_pages)
1299 $page_string .= ' <a href="' . $base_url . '&start=' . ($on_page * $per_page) . '">' . $user->lang
['NEXT'] . '</a>';
1303 $template->assign_vars(array(
1304 $tpl_prefix . 'BASE_URL' => $base_url,
1305 $tpl_prefix . 'PER_PAGE' => $per_page,
1307 $tpl_prefix . 'PREVIOUS_PAGE' => ($on_page == 1) ?
'' : $base_url . '&start=' . (($on_page - 2) * $per_page),
1308 $tpl_prefix . 'NEXT_PAGE' => ($on_page == $total_pages) ?
'' : $base_url . '&start=' . ($on_page * $per_page))
1311 return $page_string;
1315 * Return current page (pagination)
1317 function on_page($num_items, $per_page, $start)
1319 global $template, $user;
1321 $on_page = floor($start / $per_page) +
1;
1323 $template->assign_vars(array(
1324 'ON_PAGE' => $on_page)
1327 return sprintf($user->lang
['PAGE_OF'], $on_page, max(ceil($num_items / $per_page), 1));
1330 // Server functions (building urls, redirecting...)
1333 * Append session id to url
1335 * @param string $url The url the session id needs to be appended to (can have params)
1336 * @param mixed $params String or array of additional url parameters
1337 * @param bool $is_amp Is url using & (true) or & (false)
1338 * @param string $session_id Possibility to use a custom session id instead of the global one
1342 * append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&f=2");
1343 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2');
1344 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false);
1345 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2));
1348 function append_sid($url, $params = false, $is_amp = true, $session_id = false)
1350 global $_SID, $_EXTRA_URL;
1352 // Assign sid if session id is not specified
1353 if ($session_id === false)
1355 $session_id = $_SID;
1358 $amp_delim = ($is_amp) ?
'&' : '&';
1359 $url_delim = (strpos($url, '?') === false) ?
'?' : $amp_delim;
1361 // Appending custom url parameter?
1362 $append_url = (!empty($_EXTRA_URL)) ?
implode($amp_delim, $_EXTRA_URL) : '';
1364 // Use the short variant if possible ;)
1365 if ($params === false)
1367 // Append session id
1368 return (!$session_id) ?
$url . (($append_url) ?
$url_delim . $append_url : '') : $url . (($append_url) ?
$url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id;
1371 // Build string if parameters are specified as array
1372 if (is_array($params))
1376 foreach ($params as $key => $item)
1383 $output[] = $key . '=' . $item;
1386 $params = implode($amp_delim, $output);
1389 // Append session id and parameters (even if they are empty)
1390 // If parameters are empty, the developer can still append his/her parameters without caring about the delimiter
1391 return $url . (($append_url) ?
$url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ?
'' : $amp_delim . 'sid=' . $session_id);
1395 * Generate board url (example: http://www.foo.bar/phpBB)
1396 * @param bool $without_script_path if set to true the script path gets not appended (example: http://www.foo.bar)
1398 function generate_board_url($without_script_path = false)
1400 global $config, $user;
1402 $server_name = (!empty($_SERVER['SERVER_NAME'])) ?
$_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
1403 $server_port = (!empty($_SERVER['SERVER_PORT'])) ?
(int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
1405 // Forcing server vars is the only way to specify/override the protocol
1406 if ($config['force_server_vars'] ||
!$server_name)
1408 $server_protocol = ($config['server_protocol']) ?
$config['server_protocol'] : (($config['cookie_secure']) ?
'https://' : 'http://');
1409 $server_name = $config['server_name'];
1410 $server_port = (int) $config['server_port'];
1412 $url = $server_protocol . $server_name;
1416 // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection
1417 $cookie_secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ?
1 : 0;
1418 $url = (($cookie_secure) ?
'https://' : 'http://') . $server_name;
1421 if ($server_port && (($config['cookie_secure'] && $server_port <> 443) ||
(!$config['cookie_secure'] && $server_port <> 80)))
1423 $url .= ':' . $server_port;
1426 if ($without_script_path)
1431 // Strip / from the end
1432 return $url . substr($user->page
['root_script_path'], 0, -1);
1436 * Redirects the user to another page then exits the script nicely
1438 function redirect($url)
1440 global $db, $cache, $config, $user;
1442 if (empty($user->lang
))
1444 $user->add_lang('common');
1447 garbage_collection();
1449 // Make sure no &'s are in, this will break the redirect
1450 $url = str_replace('&', '&', $url);
1452 // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
1453 if (strpos(urldecode($url), "\n") !== false ||
strpos(urldecode($url), "\r") !== false)
1455 trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR
);
1458 // Determine which type of redirect we need to handle...
1459 $url_parts = parse_url($url);
1461 if ($url_parts === false)
1463 // Malformed url, redirect to current page...
1464 $url = generate_board_url() . '/' . $user->page
['page'];
1466 else if (!empty($url_parts['scheme']) && !empty($url_parts['host']))
1470 else if ($url{0} == '/')
1472 // Absolute uri, prepend direct url...
1473 $url = generate_board_url(true) . $url;
1478 $pathinfo = pathinfo($url);
1480 // Is the uri pointing to the current directory?
1481 if ($pathinfo['dirname'] == '.')
1483 if ($user->page
['page_dir'])
1485 $url = generate_board_url() . '/' . $user->page
['page_dir'] . '/' . str_replace('./', '', $url);
1489 $url = generate_board_url() . '/' . str_replace('./', '', $url);
1494 // Get the realpath of dirname
1495 $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
1496 $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
1497 $intersection = array_intersect_assoc($root_dirs, $page_dirs);
1499 $root_dirs = array_diff_assoc($root_dirs, $intersection);
1500 $page_dirs = array_diff_assoc($page_dirs, $intersection);
1502 $dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
1504 if ($dir && substr($dir, -1, 1) == '/')
1506 $dir = substr($dir, 0, -1);
1509 $url = $dir . '/' . str_replace($pathinfo['dirname'] . '/', '', $url);
1510 $url = generate_board_url() . '/' . $url;
1514 // Redirect via an HTML form for PITA webservers
1515 if (@preg_match
('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE')))
1517 header('Refresh: 0; URL=' . $url);
1518 echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><meta http-equiv="refresh" content="0; url=' . $url . '"><title>Redirect</title></head><body><div align="center">' . sprintf($user->lang
['URL_REDIRECT'], '<a href="' . $url . '">', '</a>') . '</div></body></html>';
1523 // Behave as per HTTP/1.1 spec for others
1524 header('Location: ' . $url);
1529 * Re-Apply session id after page reloads
1531 function reapply_sid($url)
1533 global $phpEx, $phpbb_root_path;
1535 if ($url === "index.$phpEx")
1537 return append_sid("index.$phpEx");
1539 else if ($url === "{$phpbb_root_path}index.$phpEx")
1541 return append_sid("{$phpbb_root_path}index.$phpEx");
1544 // Remove previously added sid
1545 if (strpos($url, '?sid=') !== false)
1547 $url = preg_replace('/(\?)sid=[a-z0-9]+(&|&)?/', '\1', $url);
1549 else if (strpos($url, '&sid=') !== false)
1551 $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
1553 else if (strpos($url, '&sid=') !== false)
1555 $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
1558 return append_sid($url);
1562 * Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url
1564 function build_url($strip_vars = false)
1566 global $user, $phpbb_root_path;
1569 $redirect = (($user->page
['page_dir']) ?
$user->page
['page_dir'] . '/' : '') . $user->page
['page_name'] . (($user->page
['query_string']) ?
"?{$user->page['query_string']}" : '');
1570 $redirect = append_sid($redirect, false, false);
1572 // Add delimiter if not there...
1573 if (strpos($redirect, '?') === false)
1579 if ($strip_vars !== false && strpos($redirect, '?') !== false)
1581 if (!is_array($strip_vars))
1583 $strip_vars = array($strip_vars);
1586 $query = $_query = array();
1587 parse_str(substr($redirect, strpos($redirect, '?') +
1), $query);
1588 $redirect = substr($redirect, 0, strpos($redirect, '?'));
1590 // Strip the vars off
1591 foreach ($strip_vars as $strip)
1593 if (isset($query[$strip]))
1595 unset($query[$strip]);
1600 foreach ($query as $key => $value)
1602 $_query[] = $key . '=' . $value;
1604 $query = implode('&', $_query);
1606 $redirect .= ($query) ?
'?' . $query : '';
1609 return $phpbb_root_path . str_replace('&', '&', $redirect);
1613 * Meta refresh assignment
1615 function meta_refresh($time, $url)
1619 $template->assign_vars(array(
1620 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />')
1624 // Message/Login boxes
1628 * @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
1629 * @param string $title Title/Message used for confirm box.
1630 * message text is _CONFIRM appended to title.
1631 * If title can not be found in user->lang a default one is displayed
1632 * If title_CONFIRM can not be found in user->lang the text given is used.
1633 * @param string $hidden Hidden variables
1634 * @param string $html_body Template used for confirm box
1635 * @param string $u_action Custom form action
1637 function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
1639 global $user, $template, $db;
1640 global $phpEx, $phpbb_root_path;
1642 if (isset($_POST['cancel']))
1648 if (isset($_POST['confirm']))
1650 // language frontier
1651 if ($_POST['confirm'] == $user->lang
['YES'])
1657 if ($check && $confirm)
1659 $user_id = request_var('user_id', 0);
1660 $session_id = request_var('sess', '');
1661 $confirm_key = request_var('confirm_key', '');
1663 if ($user_id != $user->data
['user_id'] ||
$session_id != $user->session_id ||
!$confirm_key ||
!$user->data
['user_last_confirm_key'] ||
$confirm_key != $user->data
['user_last_confirm_key'])
1668 // Reset user_last_confirm_key
1669 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = ''
1670 WHERE user_id = " . $user->data
['user_id'];
1671 $db->sql_query($sql);
1680 $s_hidden_fields = build_hidden_fields(array(
1681 'user_id' => $user->data
['user_id'],
1682 'sess' => $user->session_id
,
1683 'sid' => $user->session_id
)
1686 // generate activation key
1687 $confirm_key = gen_rand_string(10);
1689 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
1691 adm_page_header((!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title]);
1695 page_header((!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title]);
1698 $template->set_filenames(array(
1699 'body' => $html_body)
1702 // If activation key already exist, we better do not re-use the key (something very strange is going on...)
1703 if (request_var('confirm_key', ''))
1705 // This should not occur, therefore we cancel the operation to safe the user
1709 // re-add sid / transform & to & for user->page (user->page is always using &)
1710 $use_page = ($u_action) ?
$phpbb_root_path . $u_action : $phpbb_root_path . str_replace('&', '&', $user->page
['page']);
1711 $u_action = reapply_sid($use_page);
1712 $u_action .= ((strpos($u_action, '?') === false) ?
'?' : '&') . 'confirm_key=' . $confirm_key;
1714 $template->assign_vars(array(
1715 'MESSAGE_TITLE' => (!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title],
1716 'MESSAGE_TEXT' => (!isset($user->lang
[$title . '_CONFIRM'])) ?
$title : $user->lang
[$title . '_CONFIRM'],
1718 'YES_VALUE' => $user->lang
['YES'],
1719 'S_CONFIRM_ACTION' => $u_action,
1720 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
1723 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
1724 WHERE user_id = " . $user->data
['user_id'];
1725 $db->sql_query($sql);
1727 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
1738 * Generate login box or verify password
1740 function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
1742 global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
1746 // Make sure user->setup() has been called
1747 if (empty($user->lang
))
1752 // Print out error if user tries to authenticate as an administrator without having the privileges...
1753 if ($admin && !$auth->acl_get('a_'))
1756 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1757 if ($user->data
['is_registered'])
1759 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1761 trigger_error('NO_AUTH_ADMIN');
1764 if (isset($_POST['login']))
1766 $username = request_var('username', '');
1767 $password = request_var('password', '');
1768 $autologin = (!empty($_POST['autologin'])) ?
true : false;
1769 $viewonline = (!empty($_POST['viewonline'])) ?
0 : 1;
1770 $admin = ($admin) ?
1 : 0;
1772 // Check if the supplied username is equal to the one stored within the database if re-authenticating
1773 if ($admin && strtolower($username) != strtolower($user->data
['username']))
1775 // We log the attempt to use a different username...
1776 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1777 trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
1780 // If authentication is successful we redirect user to previous page
1781 $result = $auth->login($username, $password, $autologin, $viewonline, $admin);
1783 // If admin authentication and login, we will log if it was a success or not...
1784 // We also break the operation on the first non-success login - it could be argued that the user already knows
1787 if ($result['status'] == LOGIN_SUCCESS
)
1789 add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
1793 // Only log the failed attempt if a real user tried to.
1794 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1795 if ($user->data
['is_registered'])
1797 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1802 // The result parameter is always an array, holding the relevant informations...
1803 if ($result['status'] == LOGIN_SUCCESS
)
1805 $redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx");
1806 $message = ($l_success) ?
$l_success : $user->lang
['LOGIN_REDIRECT'];
1807 $l_redirect = ($admin) ?
$user->lang
['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx") ?
$user->lang
['RETURN_INDEX'] : $user->lang
['RETURN_PAGE']);
1809 // append/replace SID (may change during the session for AOL users)
1810 $redirect = reapply_sid($redirect);
1812 meta_refresh(3, $redirect);
1813 trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>'));
1816 // Something failed, determine what...
1817 if ($result['status'] == LOGIN_BREAK
)
1819 trigger_error($result['error_msg'], E_USER_ERROR
);
1822 // Special cases... determine
1823 switch ($result['status'])
1825 case LOGIN_ERROR_ATTEMPTS
:
1827 // Show confirm image
1828 $sql = 'DELETE FROM ' . CONFIRM_TABLE
. "
1829 WHERE session_id = '" . $db->sql_escape($user->session_id
) . "'
1830 AND confirm_type = " . CONFIRM_LOGIN
;
1831 $db->sql_query($sql);
1834 $code = gen_rand_string(mt_rand(5, 8));
1835 $confirm_id = md5(unique_id($user->ip
));
1837 $sql = 'INSERT INTO ' . CONFIRM_TABLE
. ' ' . $db->sql_build_array('INSERT', array(
1838 'confirm_id' => (string) $confirm_id,
1839 'session_id' => (string) $user->session_id
,
1840 'confirm_type' => (int) CONFIRM_LOGIN
,
1841 'code' => (string) $code)
1843 $db->sql_query($sql);
1845 $template->assign_vars(array(
1846 'S_CONFIRM_CODE' => true,
1847 'CONFIRM_ID' => $confirm_id,
1848 'CONFIRM_IMAGE' => '<img src="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=confirm&id=' . $confirm_id . '&type=' . CONFIRM_LOGIN
) . '" alt="" title="" />',
1849 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang
['LOGIN_CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>'),
1852 $err = $user->lang
[$result['error_msg']];
1856 // Username, password, etc...
1858 $err = $user->lang
[$result['error_msg']];
1860 // Assign admin contact to some error messages
1861 if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' ||
$result['error_msg'] == 'LOGIN_ERROR_PASSWORD')
1863 $err = (!$config['board_contact']) ?
sprintf($user->lang
[$result['error_msg']], '', '') : sprintf($user->lang
[$result['error_msg']], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>');
1871 // We just use what the session code determined...
1872 // If we are not within the admin directory we use the page dir...
1877 $redirect .= ($user->page
['page_dir']) ?
$user->page
['page_dir'] . '/' : '';
1880 $redirect .= $user->page
['page_name'] . (($user->page
['query_string']) ?
'?' . $user->page
['query_string'] : '');
1883 $s_hidden_fields = build_hidden_fields(array('redirect' => $redirect, 'sid' => $user->session_id
));
1885 $template->assign_vars(array(
1886 'LOGIN_ERROR' => $err,
1887 'LOGIN_EXPLAIN' => $l_explain,
1889 'U_SEND_PASSWORD' => ($config['email_enable']) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '',
1890 'U_RESEND_ACTIVATION' => ($config['require_activation'] != USER_ACTIVATION_NONE
&& $config['email_enable']) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '',
1891 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
1892 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
1894 'S_DISPLAY_FULL_LOGIN' => ($s_display) ?
true : false,
1895 'S_LOGIN_ACTION' => (!$admin) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx"), // Needs to stay index.$phpEx because we are within the admin directory
1896 'S_HIDDEN_FIELDS' => $s_hidden_fields,
1898 'S_ADMIN_AUTH' => $admin,
1899 'USERNAME' => ($admin) ?
$user->data
['username'] : '')
1902 page_header($user->lang
['LOGIN']);
1904 $template->set_filenames(array(
1905 'body' => 'login_body.html')
1907 make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
1913 * Generate forum login box
1915 function login_forum_box($forum_data)
1917 global $db, $config, $user, $template, $phpEx;
1919 $password = request_var('password', '');
1921 $sql = 'SELECT forum_id
1922 FROM ' . FORUMS_ACCESS_TABLE
. '
1923 WHERE forum_id = ' . $forum_data['forum_id'] . '
1924 AND user_id = ' . $user->data
['user_id'] . "
1925 AND session_id = '" . $db->sql_escape($user->session_id
) . "'";
1926 $result = $db->sql_query($sql);
1927 $row = $db->sql_fetchrow($result);
1928 $db->sql_freeresult($result);
1937 // Remove expired authorised sessions
1938 $sql = 'SELECT session_id
1939 FROM ' . SESSIONS_TABLE
;
1940 $result = $db->sql_query($sql);
1942 if ($row = $db->sql_fetchrow($result))
1947 $sql_in[] = (string) $row['session_id'];
1949 while ($row = $db->sql_fetchrow($result));
1951 // Remove expired sessions
1952 $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE
. '
1953 WHERE ' . $db->sql_in_set('session_id', $sql_in, true);
1954 $db->sql_query($sql);
1956 $db->sql_freeresult($result);
1958 if ($password == $forum_data['forum_password'])
1961 'forum_id' => (int) $forum_data['forum_id'],
1962 'user_id' => (int) $user->data
['user_id'],
1963 'session_id' => (string) $user->session_id
,
1966 $db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
1971 $template->assign_var('LOGIN_ERROR', $user->lang
['WRONG_PASSWORD']);
1976 $template->set_filenames(array(
1977 'body' => 'login_forum.html')
1983 // Content related functions
1986 * Bump Topic Check - used by posting and viewtopic
1988 function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster)
1990 global $config, $auth, $user;
1992 // Check permission and make sure the last post was not already bumped
1993 if (!$auth->acl_get('f_bump', $forum_id) ||
$topic_bumped)
1998 // Check bump time range, is the user really allowed to bump the topic at this time?
1999 $bump_time = ($config['bump_type'] == 'm') ?
$config['bump_interval'] * 60 : (($config['bump_type'] == 'h') ?
$config['bump_interval'] * 3600 : $config['bump_interval'] * 86400);
2002 if ($last_post_time +
$bump_time > time())
2007 // Check bumper, only topic poster and last poster are allowed to bump
2008 if ($topic_poster != $user->data
['user_id'] && $last_topic_poster != $user->data
['user_id'] && !$auth->acl_get('m_', $forum_id))
2013 // A bump time of 0 will completely disable the bump feature... not intended but might be useful.
2018 * Generates a text with approx. the specified length which contains the specified words and their context
2020 * @param string $text The full text from which context shall be extracted
2021 * @param string $words An array of words which should be contained in the result, * is allowed as a wildcard
2022 * @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value
2024 * @return string Context of the specified words seperated by "..."
2026 function get_context($text, $words, $length = 400)
2028 // first replace all whitespaces with single spaces
2029 $text = preg_replace('/\s+/', ' ', $text);
2031 $word_indizes = array();
2035 // find the starting indizes of all words
2036 foreach ($words as $word)
2038 if (preg_match('#(?: |^)(' . str_replace('\*', '\w*?', preg_quote($word, '#')) . ')(?: |$)#i', $text, $match))
2040 $pos = strpos($text, $match[1]);
2043 $word_indizes[] = $pos;
2049 if (sizeof($word_indizes))
2051 $word_indizes = array_unique($word_indizes);
2052 sort($word_indizes);
2054 $wordnum = sizeof($word_indizes);
2055 // number of characters on the right and left side of each word
2056 $sequence_length = (int) ($length / (2 * $wordnum)) - 2;
2059 $final_text_index = -1;
2061 // cycle through every character in the original text
2062 for ($i = $word_indizes[$word], $n = strlen($text); $i < $n; $i++
)
2064 // if the current position is the start of one of the words then append $sequence_length characters to the final text
2065 if (isset($word_indizes[$word]) && ($i == $word_indizes[$word]))
2067 if ($final_text_index < $i - $sequence_length - 1)
2069 $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', substr($text, $i - $sequence_length, $sequence_length));
2073 // if the final text is already nearer to the current word than $sequence_length we only append the text
2074 // from its current index on and distribute the unused length to all other sequenes
2075 $sequence_length +
= (int) (($final_text_index - $i +
$sequence_length +
1) / (2 * $wordnum));
2076 $final_text .= substr($text, $final_text_index +
1, $i - $final_text_index - 1);
2078 $final_text_index = $i - 1;
2080 // add the following characters to the final text (see below)
2087 // add the character to the final text and increment the sequence counter
2088 $final_text .= $text[$i];
2089 $final_text_index++
;
2092 // if this is a whitespace then check whether we are done with this sequence
2093 if ($text[$i] == ' ')
2095 // only check whether we have to exit the context generation completely if we haven't already reached the end anyway
2098 if (($j > $sequence_length && $word >= $wordnum) ||
strlen($final_text) > $length)
2100 $final_text .= ' ...';
2106 // make sure the text really reaches the end
2110 // stop context generation and wait for the next word
2111 if ($j > $sequence_length)
2122 if (!sizeof($words) ||
!sizeof($word_indizes))
2124 return (strlen($text) >= $length +
3) ?
substr($text, 0, $length) . '...' : $text;
2129 * Decode text whereby text is coming from the db and expected to be pre-parsed content
2130 * We are placing this outside of the message parser because we are often in need of it...
2132 function decode_message(&$message, $bbcode_uid = '')
2138 $match = array('<br />', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid");
2139 $replace = array("\n", '', '', '', '');
2143 $match = array('<br />');
2144 $replace = array("\n");
2147 $message = str_replace($match, $replace, $message);
2150 '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
2151 '#<!\-\- m \-\-><a href="(.*?)" target="_blank">.*?</a><!\-\- m \-\->#',
2152 '#<!\-\- w \-\-><a href="http:\/\/(.*?)" target="_blank">.*?</a><!\-\- w \-\->#',
2153 '#<!\-\- l \-\-><a href="(.*?)">.*?</a><!\-\- l \-\->#',
2154 '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
2155 '#<!\-\- .*? \-\->#s',
2159 $replace = array('\1', '\1', '\1', '\1', '\1', '', '');
2161 $message = preg_replace($match, $replace, $message);
2167 * Strips all bbcode from a text and returns the plain content
2169 function strip_bbcode(&$text, $uid = '')
2173 $uid = '[0-9a-z]{5,}';
2176 $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?$uid)\]#", ' ', $text);
2179 '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
2180 '#<!\-\- m \-\-><a href="(.*?)" target="_blank">.*?</a><!\-\- m \-\->#',
2181 '#<!\-\- w \-\-><a href="http:\/\/(.*?)" target="_blank">.*?</a><!\-\- w \-\->#',
2182 '#<!\-\- l \-\-><a href="(.*?)">.*?</a><!\-\- l \-\->#',
2183 '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
2184 '#<!\-\- .*? \-\->#s',
2188 $replace = array('\1', '\1', '\1', '\1', '\1', '', '');
2190 $text = preg_replace($match, $replace, $text);
2194 * For display of custom parsed text on user-facing pages
2195 * Expects $text to be the value directly from the database (stored value)
2197 function generate_text_for_display($text, $uid, $bitfield, $flags)
2206 $text = str_replace("\n", '<br />', censor_text($text));
2208 // Parse bbcode if bbcode uid stored and bbcode enabled
2209 if ($uid && ($flags & 1))
2211 if (!class_exists('bbcode'))
2213 global $phpbb_root_path, $phpEx;
2214 include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
2219 $bbcode = new bbcode($bitfield);
2223 $bbcode->bbcode($bitfield);
2226 $bbcode->bbcode_second_pass($text, $uid);
2229 $text = smiley_text($text, !($flags & 2));
2235 * For parsing custom parsed text to be stored within the database.
2236 * This function additionally returns the uid and bitfield that needs to be stored.
2237 * Expects $text to be the value directly from request_var() and in it's non-parsed form
2239 function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false)
2241 global $phpbb_root_path, $phpEx;
2251 if (!class_exists('parse_message'))
2253 include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx);
2256 $message_parser = new parse_message($text);
2257 $message_parser->parse($allow_bbcode, $allow_urls, $allow_smilies);
2259 $text = $message_parser->message
;
2260 $uid = $message_parser->bbcode_uid
;
2262 // If the bbcode_bitfield is empty, there is no need for the uid to be stored.
2263 if (!$message_parser->bbcode_bitfield
)
2268 $flags = (($allow_bbcode) ?
1 : 0) +
(($allow_smilies) ?
2 : 0) +
(($allow_urls) ?
4 : 0);
2269 $bitfield = $message_parser->bbcode_bitfield
;
2275 * For decoding custom parsed text for edits as well as extracting the flags
2276 * Expects $text to be the value directly from the database (pre-parsed content)
2278 function generate_text_for_edit($text, $uid, $flags)
2280 global $phpbb_root_path, $phpEx;
2282 decode_message($text, $uid);
2285 'allow_bbcode' => ($flags & 1) ?
1 : 0,
2286 'allow_smilies' => ($flags & 2) ?
1 : 0,
2287 'allow_urls' => ($flags & 4) ?
1 : 0,
2293 * make_clickable function
2295 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
2296 * Cuts down displayed size of link if over 50 chars, turns absolute links
2297 * into relative versions when the server/script path matches the link
2299 function make_clickable($text, $server_url = false)
2301 if ($server_url === false)
2303 $server_url = generate_board_url();
2306 static $magic_url_match;
2307 static $magic_url_replace;
2309 if (!is_array($magic_url_match))
2311 $magic_url_match = $magic_url_replace = array();
2312 // Be sure to not let the matches cross over. ;)
2314 // relative urls for this board
2315 $magic_url_match[] = '#(^|[\n ]|\()(' . preg_quote($server_url, '#') . ')/(([^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2316 $magic_url_replace[] = "'\$1<!-- l --><a href=\"\$2/' . preg_replace('/(&|\?)sid=[0-9a-f]{32}/', '\\1', '\$3') . '\">' . preg_replace('/(&|\?)sid=[0-9a-f]{32}/', '\\1', '\$3') . '</a><!-- l -->'";
2318 // matches a xxxx://aaaaa.bbb.cccc. ...
2319 $magic_url_match[] = '#(^|[\n ]|\()([\w]+:/{2}.*?([^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2320 $magic_url_replace[] = "'\$1<!-- m --><a href=\"\$2\" target=\"_blank\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- m -->'";
2322 // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
2323 $magic_url_match[] = '#(^|[\n ]|\()(w{3}\.[\w\-]+\.[\w\-.\~]+(?:[^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2324 $magic_url_replace[] = "'\$1<!-- w --><a href=\"http://\$2\" target=\"_blank\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- w -->'";
2326 // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode.
2327 $magic_url_match[] = '/(^|[\n ]|\()(' . get_preg_expression('email') . ')/ie';
2328 $magic_url_replace[] = "'\$1<!-- e --><a href=\"mailto:\$2\">' . ((strlen('\$2') > 55) ? substr('\$2', 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . '</a><!-- e -->'";
2331 return preg_replace($magic_url_match, $magic_url_replace, $text);
2337 function censor_text($text)
2339 global $censors, $user, $cache;
2341 if (!isset($censors))
2345 if ($user->optionget('viewcensors'))
2347 $cache->obtain_word_list($censors);
2351 if (sizeof($censors) && $user->optionget('viewcensors'))
2353 return preg_replace($censors['match'], $censors['replace'], $text);
2362 function smiley_text($text, $force_option = false)
2364 global $config, $user, $phpbb_root_path;
2366 if ($force_option ||
!$config['allow_smilies'] ||
!$user->optionget('viewsmilies'))
2368 return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', '\1', $text);
2372 return str_replace('<img src="{SMILIES_PATH}', '<img src="' . $phpbb_root_path . $config['smilies_path'], $text);
2377 * Inline Attachment processing
2379 function parse_inline_attachments(&$text, &$attachments, &$update_count, $forum_id = 0, $preview = false)
2381 global $config, $user;
2383 $attachments = display_attachments($forum_id, NULL, $attachments, $update_count, false, true);
2384 $tpl_size = sizeof($attachments);
2386 $unset_tpl = array();
2388 preg_match_all('#<!\-\- ia([0-9]+) \-\->(.*?)<!\-\- ia\1 \-\->#', $text, $matches, PREG_PATTERN_ORDER
);
2391 foreach ($matches[0] as $num => $capture)
2393 // Flip index if we are displaying the reverse way
2394 $index = ($config['display_order']) ?
($tpl_size-($matches[1][$num] +
1)) : $matches[1][$num];
2396 $replace['from'][] = $matches[0][$num];
2397 $replace['to'][] = (isset($attachments[$index])) ?
$attachments[$index] : sprintf($user->lang
['MISSING_INLINE_ATTACHMENT'], $matches[2][array_search($index, $matches[1])]);
2399 $unset_tpl[] = $index;
2402 if (isset($replace['from']))
2404 $text = str_replace($replace['from'], $replace['to'], $text);
2407 return array_unique($unset_tpl);
2411 * Check if extension is allowed to be posted within forum X (forum_id 0 == private messaging)
2413 function extension_allowed($forum_id, $extension, &$extensions)
2415 if (!sizeof($extensions))
2419 $extensions = array();
2420 $cache->obtain_attach_extensions($extensions);
2423 if (!isset($extensions['_allowed_'][$extension]))
2428 $check = $extensions['_allowed_'][$extension];
2430 if (is_array($check))
2432 // Check for private messaging AND all forums allowed
2433 if (sizeof($check) == 1 && $check[0] == 0)
2438 return (!in_array($forum_id, $check)) ?
false : true;
2441 return ($forum_id == 0) ?
false : true;
2447 * Little helper for the build_hidden_fields function
2449 function _build_hidden_fields($key, $value, $specialchar)
2451 $hidden_fields = '';
2453 if (!is_array($value))
2455 $key = ($specialchar) ?
htmlspecialchars($key) : $key;
2456 $value = ($specialchar) ?
htmlspecialchars($value) : $value;
2458 $hidden_fields .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />' . "\n";
2462 foreach ($value as $_key => $_value)
2464 $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar);
2468 return $hidden_fields;
2472 * Build simple hidden fields from array
2474 function build_hidden_fields($field_ary, $specialchar = false)
2476 $s_hidden_fields = '';
2478 foreach ($field_ary as $name => $vars)
2480 $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar);
2483 return $s_hidden_fields;
2489 function parse_cfg_file($filename, $lines = false)
2491 $parsed_items = array();
2493 if ($lines === false)
2495 $lines = file($filename);
2498 foreach ($lines as $line)
2500 $line = trim($line);
2502 if (!$line ||
$line{0} == '#' ||
($delim_pos = strpos($line, '=')) === false)
2507 // Determine first occurrence, since in values the equal sign is allowed
2508 $key = strtolower(trim(substr($line, 0, $delim_pos)));
2509 $value = trim(substr($line, $delim_pos +
1));
2511 if (in_array($value, array('off', 'false', '0')))
2515 else if (in_array($value, array('on', 'true', '1')))
2519 else if (!trim($value))
2523 else if (($value{0} == "'" && $value{sizeof($value)-1} == "'") ||
($value{0} == '"' && $value{sizeof($value)-1} == '"'))
2525 $value = substr($value, 1, sizeof($value)-2);
2528 $parsed_items[$key] = $value;
2531 return $parsed_items;
2541 $args = func_get_args();
2543 $mode = array_shift($args);
2544 $reportee_id = ($mode == 'user') ?
intval(array_shift($args)) : '';
2545 $forum_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
2546 $topic_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
2547 $action = array_shift($args);
2548 $data = (!sizeof($args)) ?
'' : serialize($args);
2551 'user_id' => (empty($user->data
)) ? ANONYMOUS
: $user->data
['user_id'],
2552 'log_ip' => $user->ip
,
2553 'log_time' => time(),
2554 'log_operation' => $action,
2555 'log_data' => $data,
2561 $sql_ary['log_type'] = LOG_ADMIN
;
2566 'log_type' => LOG_MOD
,
2567 'forum_id' => $forum_id,
2568 'topic_id' => $topic_id
2574 'log_type' => LOG_USERS
,
2575 'reportee_id' => $reportee_id
2580 $sql_ary['log_type'] = LOG_CRITICAL
;
2587 $db->sql_query('INSERT INTO ' . LOG_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
2589 return $db->sql_nextid();
2593 * Return a nicely formatted backtrace (parts from the php manual by diz at ysagoon dot com)
2595 function get_backtrace()
2597 global $phpbb_root_path;
2599 $output = '<div style="font-family: monospace;">';
2600 $backtrace = debug_backtrace();
2601 $path = phpbb_realpath($phpbb_root_path);
2603 foreach ($backtrace as $number => $trace)
2605 // We skip the first one, because it only shows this file/function
2611 // Strip the current directory from path
2612 $trace['file'] = str_replace(array($path, '\\'), array('', '/'), $trace['file']);
2613 $trace['file'] = substr($trace['file'], 1);
2616 // If include/require/include_once is not called, do not show arguments - they may contain sensible informations
2617 if (!in_array($trace['function'], array('include', 'require', 'include_once')))
2619 unset($trace['args']);
2624 if (!empty($trace['args'][0]))
2626 $argument = htmlspecialchars($trace['args'][0]);
2627 $argument = str_replace(array($path, '\\'), array('', '/'), $argument);
2628 $argument = substr($argument, 1);
2629 $args[] = "'{$argument}'";
2633 $trace['class'] = (!isset($trace['class'])) ?
'' : $trace['class'];
2634 $trace['type'] = (!isset($trace['type'])) ?
'' : $trace['type'];
2636 $output .= '<br />';
2637 $output .= '<b>FILE:</b> ' . htmlspecialchars($trace['file']) . '<br />';
2638 $output .= '<b>LINE:</b> ' . $trace['line'] . '<br />';
2640 $output .= '<b>CALL:</b> ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']) . '(' . ((sizeof($args)) ?
implode(', ', $args) : '') . ')<br />';
2642 $output .= '</div>';
2647 * This function returns a regular expression pattern for commonly used expressions
2648 * Use with / as delimiter
2649 * mode can be: email|
2651 function get_preg_expression($mode)
2656 return '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+';
2664 * Truncates string while retaining special characters if going over the max length
2665 * The default max length is 60 at the moment
2667 function truncate_string($string, $max_length = 60)
2671 // split the multibyte characters first
2672 $string_ary = preg_split('#(&\#[0-9]+;)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE
);
2674 // Now go through the array and split the other characters
2675 foreach ($string_ary as $key => $value)
2677 if (strpos($value, '&#') === 0)
2683 // decode html entities and put them back later
2684 $_chars = str_split(html_entity_decode($value));
2685 $chars = array_merge($chars, array_map('htmlspecialchars', $_chars));
2688 // Now check the length ;)
2689 if (sizeof($chars) <= $max_length)
2694 // Cut off the last elements from the array
2695 return implode('', array_slice($chars, 0, $max_length));
2698 // Handler, header and footer
2701 * Error and message handler, call with trigger_error if reqd
2703 function msg_handler($errno, $msg_text, $errfile, $errline)
2705 global $cache, $db, $auth, $template, $config, $user;
2706 global $phpEx, $phpbb_root_path, $starttime, $msg_title, $msg_long_text;
2708 // Message handler is stripping text. In case we need it, we are possible to define long text...
2709 if (isset($msg_long_text) && $msg_long_text && !$msg_text)
2711 $msg_text = $msg_long_text;
2719 // Check the error reporting level and return if the error level does not match
2720 // Additionally do not display notices if we suppress them via @
2721 // If DEBUG_EXTRA is defined the default level is E_ALL
2722 if (($errno & ((defined('DEBUG_EXTRA') && error_reporting()) ? E_ALL
: error_reporting())) == 0)
2728 * @todo Think about removing the if-condition within the final product, since we no longer enable DEBUG by default and we will maybe adjust the error reporting level
2730 if (defined('DEBUG'))
2732 if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
2734 // remove complete path to installation, with the risk of changing backslashes meant to be there
2735 $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);
2736 $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text);
2738 echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
2746 garbage_collection();
2748 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
2749 echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
2751 echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
2752 echo '<title>' . $msg_title . '</title>';
2753 echo '<link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />';
2755 echo '<body id="errorpage">';
2756 echo '<div id="wrap">';
2757 echo ' <div id="page-header">';
2758 echo ' <a href="' . $phpbb_root_path . '">Return to forum index</a>';
2760 echo ' <div id="page-body">';
2761 echo ' <div class="panel">';
2762 echo ' <span class="corners-top"><span></span></span>';
2763 echo ' <div id="content">';
2764 echo ' <h1>General Error</h1>';
2766 echo ' <h2>' . $msg_text . '</h2>';
2768 if (!empty($config['board_contact']))
2770 echo ' <p>Please notify the board administrator or webmaster : <a href="mailto:' . $config['board_contact'] . '">' . $config['board_contact'] . '</a></p>';
2774 echo ' <span class="corners-bottom"><span></span></span>';
2777 echo ' <div id="page-footer">';
2778 echo ' Powered by phpBB © ' . date('Y') . ' <a href="http://www.phpbb.com/">phpBB Group</a>';
2787 case E_USER_WARNING
:
2790 define('IN_ERROR_HANDLER', true);
2792 if (empty($user->data
))
2794 $user->session_begin();
2797 // We re-init the auth array to get correct results on login/logout
2798 $auth->acl($user->data
);
2800 if (empty($user->lang
))
2805 $msg_text = (!empty($user->lang
[$msg_text])) ?
$user->lang
[$msg_text] : $msg_text;
2806 $msg_title = (!isset($msg_title)) ?
$user->lang
['INFORMATION'] : ((!empty($user->lang
[$msg_title])) ?
$user->lang
[$msg_title] : $msg_title);
2808 if (!defined('HEADER_INC'))
2810 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
2812 adm_page_header($msg_title);
2816 page_header($msg_title);
2820 $template->set_filenames(array(
2821 'body' => 'message_body.html')
2824 $template->assign_vars(array(
2825 'MESSAGE_TITLE' => $msg_title,
2826 'MESSAGE_TEXT' => $msg_text,
2827 'S_USER_WARNING' => ($errno == E_USER_WARNING
) ?
true : false,
2828 'S_USER_NOTICE' => ($errno == E_USER_NOTICE
) ?
true : false)
2831 // We do not want the cron script to be called on error messages
2832 define('IN_CRON', true);
2834 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
2849 * Generate page header
2851 function page_header($page_title = '', $display_online_list = true)
2853 global $db, $config, $template, $SID, $_SID, $user, $auth, $phpEx, $phpbb_root_path;
2855 if (defined('HEADER_INC'))
2860 define('HEADER_INC', true);
2863 if ($config['gzip_compress'])
2865 if (@extension_loaded
('zlib') && !headers_sent())
2867 ob_start('ob_gzhandler');
2871 // Generate logged in/logged out status
2872 if ($user->data
['user_id'] != ANONYMOUS
)
2874 $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout');
2875 $l_login_logout = sprintf($user->lang
['LOGOUT_USER'], $user->data
['username']);
2879 $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login');
2880 $l_login_logout = $user->lang
['LOGIN'];
2883 // Last visit date/time
2884 $s_last_visit = ($user->data
['user_id'] != ANONYMOUS
) ?
$user->format_date($user->data
['session_last_visit']) : '';
2886 // Get users online list ... if required
2887 $l_online_users = $online_userlist = $l_online_record = '';
2889 if ($config['load_online'] && $config['load_online_time'] && $display_online_list)
2891 $userlist_ary = $userlist_visible = array();
2892 $logged_visible_online = $logged_hidden_online = $guests_online = $prev_user_id = 0;
2893 $prev_session_ip = $reading_sql = '';
2895 if (!empty($_REQUEST['f']))
2897 $f = request_var('f', 0);
2899 // Do not change this (it is defined as _f_={forum_id}x within session.php)
2900 $reading_sql = " AND s.session_page LIKE '%\_f\_={$f}x%'";
2902 // Specify escape character for MSSQL
2903 if (SQL_LAYER
== 'mssql' || SQL_LAYER
== 'mssql_odbc')
2905 $reading_sql .= " ESCAPE '\\'";
2909 // Get number of online guests
2910 if (!$config['load_online_guests'])
2912 $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests
2913 FROM ' . SESSIONS_TABLE
. ' s
2914 WHERE s.session_user_id = ' . ANONYMOUS
. '
2915 AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) .
2917 $result = $db->sql_query($sql);
2918 $guests_online = (int) $db->sql_fetchfield('num_guests');
2919 $db->sql_freeresult($result);
2922 $sql = 'SELECT u.username, u.user_id, u.user_type, u.user_allow_viewonline, u.user_colour, s.session_ip, s.session_viewonline
2923 FROM ' . USERS_TABLE
. ' u, ' . SESSIONS_TABLE
. ' s
2924 WHERE s.session_time >= ' . (time() - (intval($config['load_online_time']) * 60)) .
2926 ((!$config['load_online_guests']) ?
' AND s.session_user_id <> ' . ANONYMOUS
: '') . '
2927 AND u.user_id = s.session_user_id
2928 ORDER BY u.username ASC, s.session_ip ASC';
2929 $result = $db->sql_query($sql);
2931 while ($row = $db->sql_fetchrow($result))
2933 // User is logged in and therefore not a guest
2934 if ($row['user_id'] != ANONYMOUS
)
2936 // Skip multiple sessions for one user
2937 if ($row['user_id'] != $prev_user_id)
2939 if ($row['user_colour'])
2941 $user_colour = ' style="color:#' . $row['user_colour'] . '"';
2942 $row['username'] = '<strong>' . $row['username'] . '</strong>';
2949 if ($row['user_allow_viewonline'] && $row['session_viewonline'])
2951 $user_online_link = $row['username'];
2952 $logged_visible_online++
;
2956 $user_online_link = '<em>' . $row['username'] . '</em>';
2957 $logged_hidden_online++
;
2960 if (($row['user_allow_viewonline'] && $row['session_viewonline']) ||
$auth->acl_get('u_viewonline'))
2962 if ($row['user_type'] <> USER_IGNORE
)
2964 $user_online_link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']) . '"' . $user_colour . '>' . $user_online_link . '</a>';
2968 $user_online_link = ($user_colour) ?
'<span' . $user_colour . '>' . $user_online_link . '</span>' : $user_online_link;
2971 $online_userlist .= ($online_userlist != '') ?
', ' . $user_online_link : $user_online_link;
2975 $prev_user_id = $row['user_id'];
2979 // Skip multiple sessions for one user
2980 if ($row['session_ip'] != $prev_session_ip)
2986 $prev_session_ip = $row['session_ip'];
2988 $db->sql_freeresult($result);
2990 if (!$online_userlist)
2992 $online_userlist = $user->lang
['NO_ONLINE_USERS'];
2995 if (empty($_REQUEST['f']))
2997 $online_userlist = $user->lang
['REGISTERED_USERS'] . ' ' . $online_userlist;
3001 $l_online = ($guests_online == 1) ?
$user->lang
['BROWSING_FORUM_GUEST'] : $user->lang
['BROWSING_FORUM_GUESTS'];
3002 $online_userlist = sprintf($l_online, $online_userlist, $guests_online);
3005 $total_online_users = $logged_visible_online +
$logged_hidden_online +
$guests_online;
3007 if ($total_online_users > $config['record_online_users'])
3009 set_config('record_online_users', $total_online_users, true);
3010 set_config('record_online_date', time(), true);
3013 // Build online listing
3014 $vars_online = array(
3015 'ONLINE' => array('total_online_users', 'l_t_user_s'),
3016 'REG' => array('logged_visible_online', 'l_r_user_s'),
3017 'HIDDEN' => array('logged_hidden_online', 'l_h_user_s'),
3018 'GUEST' => array('guests_online', 'l_g_user_s')
3021 foreach ($vars_online as $l_prefix => $var_ary)
3023 switch ($
{$var_ary[0]})
3026 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USERS_ZERO_TOTAL'];
3030 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USER_TOTAL'];
3034 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USERS_TOTAL'];
3038 unset($vars_online);
3040 $l_online_users = sprintf($l_t_user_s, $total_online_users);
3041 $l_online_users .= sprintf($l_r_user_s, $logged_visible_online);
3042 $l_online_users .= sprintf($l_h_user_s, $logged_hidden_online);
3043 $l_online_users .= sprintf($l_g_user_s, $guests_online);
3045 $l_online_record = sprintf($user->lang
['RECORD_ONLINE_USERS'], $config['record_online_users'], $user->format_date($config['record_online_date']));
3047 $l_online_time = ($config['load_online_time'] == 1) ?
'VIEW_ONLINE_TIME' : 'VIEW_ONLINE_TIMES';
3048 $l_online_time = sprintf($user->lang
[$l_online_time], $config['load_online_time']);
3052 $l_online_time = '';
3055 $l_privmsgs_text = $l_privmsgs_text_unread = '';
3056 $s_privmsg_new = false;
3058 // Obtain number of new private messages if user is logged in
3059 if (isset($user->data
['is_registered']) && $user->data
['is_registered'])
3061 if ($user->data
['user_new_privmsg'])
3063 $l_message_new = ($user->data
['user_new_privmsg'] == 1) ?
$user->lang
['NEW_PM'] : $user->lang
['NEW_PMS'];
3064 $l_privmsgs_text = sprintf($l_message_new, $user->data
['user_new_privmsg']);
3066 if (!$user->data
['user_last_privmsg'] ||
$user->data
['user_last_privmsg'] > $user->data
['session_last_visit'])
3068 $sql = 'UPDATE ' . USERS_TABLE
. '
3069 SET user_last_privmsg = ' . $user->data
['session_last_visit'] . '
3070 WHERE user_id = ' . $user->data
['user_id'];
3071 $db->sql_query($sql);
3073 $s_privmsg_new = true;
3077 $s_privmsg_new = false;
3082 $l_privmsgs_text = $user->lang
['NO_NEW_PM'];
3083 $s_privmsg_new = false;
3086 $l_privmsgs_text_unread = '';
3088 if ($user->data
['user_unread_privmsg'] && $user->data
['user_unread_privmsg'] != $user->data
['user_new_privmsg'])
3090 $l_message_unread = ($user->data
['user_unread_privmsg'] == 1) ?
$user->lang
['UNREAD_PM'] : $user->lang
['UNREAD_PMS'];
3091 $l_privmsgs_text_unread = sprintf($l_message_unread, $user->data
['user_unread_privmsg']);
3096 $tz = ($user->data
['user_id'] != ANONYMOUS
) ?
strval(doubleval($user->data
['user_timezone'])) : strval(doubleval($config['board_timezone']));
3098 // The following assigns all _common_ variables that may be used at any point in a template.
3099 $template->assign_vars(array(
3100 'SITENAME' => $config['sitename'],
3101 'SITE_DESCRIPTION' => $config['site_desc'],
3102 'PAGE_TITLE' => $page_title,
3103 'SCRIPT_NAME' => str_replace('.' . $phpEx, '', $user->page
['page_name']),
3104 'LAST_VISIT_DATE' => sprintf($user->lang
['YOU_LAST_VISIT'], $s_last_visit),
3105 'CURRENT_TIME' => sprintf($user->lang
['CURRENT_TIME'], $user->format_date(time(), false, true)),
3106 'TOTAL_USERS_ONLINE' => $l_online_users,
3107 'LOGGED_IN_USER_LIST' => $online_userlist,
3108 'RECORD_USERS' => $l_online_record,
3109 'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text,
3110 'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread,
3114 'SESSION_ID' => $user->session_id
,
3115 'ROOT_PATH' => $phpbb_root_path,
3117 'L_LOGIN_LOGOUT' => $l_login_logout,
3118 'L_INDEX' => $user->lang
['FORUM_INDEX'],
3119 'L_ONLINE_EXPLAIN' => $l_online_time,
3121 'U_PRIVATEMSGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
3122 'U_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
3123 'UA_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox', false),
3124 'U_POPUP_PM' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup'),
3125 'UA_POPUP_PM' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup', false),
3126 'U_MEMBERLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
3127 'U_MEMBERSLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
3128 'U_VIEWONLINE' => append_sid("{$phpbb_root_path}viewonline.$phpEx"),
3129 'U_LOGIN_LOGOUT' => $u_login_logout,
3130 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"),
3131 'U_SEARCH' => append_sid("{$phpbb_root_path}search.$phpEx"),
3132 'U_REGISTER' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
3133 'U_PROFILE' => append_sid("{$phpbb_root_path}ucp.$phpEx"),
3134 'U_MODCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id
),
3135 'U_FAQ' => append_sid("{$phpbb_root_path}faq.$phpEx"),
3136 'U_SEARCH_SELF' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'),
3137 'U_SEARCH_NEW' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'),
3138 'U_SEARCH_UNANSWERED' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
3139 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
3140 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
3141 'U_TEAM' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'),
3142 'U_RESTORE_PERMISSIONS' => ($user->data
['user_perm_from'] && $auth->acl_get('a_switchperm')) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
3144 'S_USER_LOGGED_IN' => ($user->data
['user_id'] != ANONYMOUS
) ?
true : false,
3145 'S_BOARD_DISABLED' => ($config['board_disable'] && !defined('IN_LOGIN') && $auth->acl_gets('a_', 'm_')) ?
true : false,
3146 'S_REGISTERED_USER' => $user->data
['is_registered'],
3147 'S_IS_BOT' => $user->data
['is_bot'],
3148 'S_USER_PM_POPUP' => $user->optionget('popuppm'),
3149 'S_USER_LANG' => $user->data
['user_lang'],
3150 'S_USER_BROWSER' => (isset($user->data
['session_browser'])) ?
$user->data
['session_browser'] : $user->lang
['UNKNOWN_BROWSER'],
3151 'S_USERNAME' => $user->data
['username'],
3152 'S_CONTENT_DIRECTION' => $user->lang
['DIRECTION'],
3153 'S_CONTENT_ENCODING' => $user->lang
['ENCODING'],
3154 'S_CONTENT_DIR_LEFT' => $user->lang
['LEFT'],
3155 'S_CONTENT_DIR_RIGHT' => $user->lang
['RIGHT'],
3156 'S_TIMEZONE' => ($user->data
['user_dst'] ||
($user->data
['user_id'] == ANONYMOUS
&& $config['board_dst'])) ?
sprintf($user->lang
['ALL_TIMES'], $user->lang
['tz'][$tz], $user->lang
['tz']['dst']) : sprintf($user->lang
['ALL_TIMES'], $user->lang
['tz'][$tz], ''),
3157 'S_DISPLAY_ONLINE_LIST' => ($config['load_online']) ?
1 : 0,
3158 'S_DISPLAY_SEARCH' => (!$config['load_search']) ?
0 : (isset($auth) ?
($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1),
3159 'S_DISPLAY_PM' => ($config['allow_privmsg'] && $user->data
['is_registered']) ?
1 : 0,
3160 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ?
$auth->acl_get('u_viewprofile') : 0,
3161 'S_NEW_PM' => ($s_privmsg_new) ?
1 : 0,
3163 'T_THEME_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['theme_path'] . '/theme',
3164 'T_TEMPLATE_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['template_path'] . '/template',
3165 'T_IMAGESET_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['imageset_path'] . '/imageset',
3166 'T_IMAGESET_LANG_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['imageset_path'] . '/imageset/' . $user->data
['user_lang'],
3167 'T_IMAGES_PATH' => "{$phpbb_root_path}images/",
3168 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/",
3169 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/",
3170 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
3171 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/",
3172 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/",
3173 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/",
3174 'T_STYLESHEET_LINK' => (!$user->theme
['theme_storedb']) ?
"{$phpbb_root_path}styles/" . $user->theme
['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&id=" . $user->theme
['style_id'],
3175 'T_STYLESHEET_NAME' => $user->theme
['theme_name'],
3176 'T_THEME_DATA' => (!$user->theme
['theme_storedb']) ?
'' : $user->theme
['theme_data'],
3178 'SITE_LOGO_IMG' => $user->img('site_logo'))
3181 if ($config['send_encoding'])
3183 header('Content-type: text/html; charset=' . $user->lang
['ENCODING']);
3185 header('Cache-Control: private, no-cache="set-cookie"');
3186 header('Expires: 0');
3187 header('Pragma: no-cache');
3193 * Generate page footer
3195 function page_footer()
3197 global $db, $config, $template, $user, $auth, $cache, $messenger, $starttime, $phpbb_root_path, $phpEx;
3199 // Output page creation time
3200 if (defined('DEBUG'))
3202 $mtime = explode(' ', microtime());
3203 $totaltime = $mtime[0] +
$mtime[1] - $starttime;
3205 if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report'))
3207 $db->sql_report('display');
3210 $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress']) ?
'On' : 'Off') . (($user->load
) ?
' | Load : ' . $user->load
: ''), $totaltime);
3212 if ($auth->acl_get('a_') && defined('DEBUG_EXTRA'))
3214 if (function_exists('memory_get_usage'))
3216 if ($memory_usage = memory_get_usage())
3218 global $base_memory_usage;
3219 $memory_usage -= $base_memory_usage;
3220 $memory_usage = ($memory_usage >= 1048576) ?
round((round($memory_usage / 1048576 * 100) / 100), 2) . ' ' . $user->lang
['MB'] : (($memory_usage >= 1024) ?
round((round($memory_usage / 1024 * 100) / 100), 2) . ' ' . $user->lang
['KB'] : $memory_usage . ' ' . $user->lang
['BYTES']);
3222 $debug_output .= ' | Memory Usage: ' . $memory_usage;
3226 $debug_output .= ' | <a href="' . build_url() . '&explain=1">Explain</a>';
3230 $template->assign_vars(array(
3231 'DEBUG_OUTPUT' => (defined('DEBUG')) ?
$debug_output : '',
3233 'U_ACP' => ($auth->acl_get('a_') && $user->data
['is_registered']) ?
"{$phpbb_root_path}adm/index.$phpEx?sid=" . $user->session_id
: '')
3236 // Call cron-type script
3237 if (!defined('IN_CRON'))
3241 if (time() - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx))
3243 // Process email queue
3244 $cron_type = 'queue';
3246 else if (method_exists($cache, 'tidy') && time() - $config['cache_gc'] > $config['cache_last_gc'])
3249 $cron_type = 'tidy_cache';
3251 else if (time() - $config['warnings_gc'] > $config['warnings_last_gc'])
3253 $cron_type = 'tidy_warnings';
3255 else if (time() - $config['database_gc'] > $config['database_last_gc'])
3257 // Tidy the database
3258 $cron_type = 'tidy_database';
3260 else if (time() - $config['search_gc'] > $config['search_last_gc'])
3263 $cron_type = 'tidy_search';
3265 else if (time() - $config['session_gc'] > $config['session_last_gc'])
3267 $cron_type = 'tidy_sessions';
3272 $template->assign_var('RUN_CRON_TASK', '<img src="' . $phpbb_root_path . 'cron.' . $phpEx . '?cron_type=' . $cron_type . '" width="1" height="1" alt="cron" />');
3276 $template->display('body');
3278 garbage_collection();
3284 * Closing the cache object and the database
3285 * Cool function name, eh? We might want to add operations to it later
3287 function garbage_collection()
3291 // Unload cache, must be done before the DB connection if closed
3297 // Close our DB connection.
3310 function bitfield($bitfield = '')
3312 $this->data
= base64_decode($bitfield);
3319 // Get the ($n / 8)th char
3322 if (!isset($this->data
[$byte]))
3324 // Of course, if it doesn't exist then the result if FALSE
3328 $c = $this->data
[$byte];
3330 // Lookup the ($n % 8)th bit of the byte
3331 $bit = 7 - ($n & 7);
3332 return (bool) (ord($c) & (1 << $bit));
3338 $bit = 7 - ($n & 7);
3340 if (isset($this->data
[$byte]))
3342 $this->data
[$byte] = $this->data
[$byte] |
chr(1 << $bit);
3346 if ($byte - strlen($this->data
) > 0)
3348 $this->data
.= str_repeat("\0", $byte - strlen($this->data
));
3350 $this->data
.= chr(1 << $bit);
3358 if (!isset($this->data
[$byte]))
3363 $bit = 7 - ($n & 7);
3364 $this->data
[$byte] = $this->data
[$byte] &~
chr(1 << $bit);
3372 function get_base64()
3374 return base64_encode($this->data
);
3380 $len = strlen($this->data
);
3382 for ($i = 0; $i < $len; ++
$i)
3384 $bin .= str_pad(decbin(ord($this->data
[$i])), 8, '0', STR_PAD_LEFT
);
3390 function get_all_set()
3392 return array_keys(array_filter(str_split($this->get_bin())));
3395 function merge($bitfield)
3397 $this->data
= $this->data |
$bitfield->get_blob();