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), ENT_QUOTES
, 'UTF-8'));
31 // Make sure multibyte characters are wellformed
34 if (!preg_match('/^./u', $result))
41 // no multibyte, allow only ASCII (0-127)
42 $result = preg_replace('/[\x80-\xFF]/', '?', $result);
46 $result = (STRIP
) ?
stripslashes($result) : $result;
53 * Used to get passed variable
55 function request_var($var_name, $default, $multibyte = false)
57 if (!isset($_REQUEST[$var_name]) ||
(is_array($_REQUEST[$var_name]) && !is_array($default)) ||
(is_array($default) && !is_array($_REQUEST[$var_name])))
59 return (is_array($default)) ?
array() : $default;
62 $var = $_REQUEST[$var_name];
63 if (!is_array($default))
65 $type = gettype($default);
69 list($key_type, $type) = each($default);
70 $type = gettype($type);
71 $key_type = gettype($key_type);
79 foreach ($_var as $k => $v)
83 foreach ($v as $_k => $_v)
85 set_var($k, $k, $key_type);
86 set_var($_k, $_k, $key_type);
87 set_var($var[$k][$_k], $_v, $type, $multibyte);
92 set_var($k, $k, $key_type);
93 set_var($var[$k], $v, $type, $multibyte);
99 set_var($var, $var, $type, $multibyte);
106 * Set config value. Creates missing config entry.
108 function set_config($config_name, $config_value, $is_dynamic = false)
110 global $db, $cache, $config;
112 $sql = 'UPDATE ' . CONFIG_TABLE
. "
113 SET config_value = '" . $db->sql_escape($config_value) . "'
114 WHERE config_name = '" . $db->sql_escape($config_name) . "'";
115 $db->sql_query($sql);
117 if (!$db->sql_affectedrows() && !isset($config[$config_name]))
119 $sql = 'INSERT INTO ' . CONFIG_TABLE
. ' ' . $db->sql_build_array('INSERT', array(
120 'config_name' => $config_name,
121 'config_value' => $config_value,
122 'is_dynamic' => ($is_dynamic) ?
1 : 0));
123 $db->sql_query($sql);
126 $config[$config_name] = $config_value;
130 $cache->destroy('config');
135 * Generates an alphanumeric random string of given length
137 function gen_rand_string($num_chars = 8)
139 $rand_str = unique_id();
140 $rand_str = str_replace('0', 'Z', strtoupper(base_convert($rand_str, 16, 35)));
142 return substr($rand_str, 0, $num_chars);
147 * @param $extra additional entropy
149 function unique_id($extra = 'c')
154 $val = $config['rand_seed'] . microtime();
156 $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
158 if ($dss_seeded !== true)
160 set_config('rand_seed', $config['rand_seed'], true);
164 return substr($val, 4, 16);
168 * Generate sort selection fields
170 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)
174 $sort_dir_text = array('a' => $user->lang
['ASCENDING'], 'd' => $user->lang
['DESCENDING']);
176 $s_limit_days = '<select name="st">';
177 foreach ($limit_days as $day => $text)
179 $selected = ($sort_days == $day) ?
' selected="selected"' : '';
180 $s_limit_days .= '<option value="' . $day . '"' . $selected . '>' . $text . '</option>';
182 $s_limit_days .= '</select>';
184 $s_sort_key = '<select name="sk">';
185 foreach ($sort_by_text as $key => $text)
187 $selected = ($sort_key == $key) ?
' selected="selected"' : '';
188 $s_sort_key .= '<option value="' . $key . '"' . $selected . '>' . $text . '</option>';
190 $s_sort_key .= '</select>';
192 $s_sort_dir = '<select name="sd">';
193 foreach ($sort_dir_text as $key => $value)
195 $selected = ($sort_dir == $key) ?
' selected="selected"' : '';
196 $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
198 $s_sort_dir .= '</select>';
200 $u_sort_param = "st=$sort_days&sk=$sort_key&sd=$sort_dir";
208 function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false)
210 global $config, $auth, $template, $user, $db, $phpEx;
212 if (!$config['load_jumpbox'])
217 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
218 FROM ' . FORUMS_TABLE
. '
219 ORDER BY left_id ASC';
220 $result = $db->sql_query($sql, 600);
222 $right = $padding = 0;
223 $padding_store = array('0' => 0);
224 $display_jumpbox = false;
227 // Sometimes it could happen that forums will be displayed here not be displayed within the index page
228 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
229 // If this happens, the padding could be "broken"
231 while ($row = $db->sql_fetchrow($result))
233 if ($row['left_id'] < $right)
236 $padding_store[$row['parent_id']] = $padding;
238 else if ($row['left_id'] > $right +
1)
240 $padding = $padding_store[$row['parent_id']];
243 $right = $row['right_id'];
245 if ($row['forum_type'] == FORUM_CAT
&& ($row['left_id'] +
1 == $row['right_id']))
247 // Non-postable forum with no subforums, don't display
251 if (!$auth->acl_get('f_list', $row['forum_id']))
253 // if the user does not have permissions to list this forum skip
257 if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
262 if (!$display_jumpbox)
264 $template->assign_block_vars('jumpbox_forums', array(
265 'FORUM_ID' => ($select_all) ?
0 : -1,
266 'FORUM_NAME' => ($select_all) ?
$user->lang
['ALL_FORUMS'] : $user->lang
['SELECT_FORUM'],
267 'S_FORUM_COUNT' => $iteration)
271 $display_jumpbox = true;
274 $template->assign_block_vars('jumpbox_forums', array(
275 'FORUM_ID' => $row['forum_id'],
276 'FORUM_NAME' => $row['forum_name'],
277 'SELECTED' => ($row['forum_id'] == $forum_id) ?
' selected="selected"' : '',
278 'S_FORUM_COUNT' => $iteration,
279 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT
) ?
true : false,
280 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK
) ?
true : false,
281 'S_IS_POST' => ($row['forum_type'] == FORUM_POST
) ?
true : false)
284 for ($i = 0; $i < $padding; $i++
)
286 $template->assign_block_vars('jumpbox_forums.level', array());
290 $db->sql_freeresult($result);
291 unset($padding_store);
293 $template->assign_vars(array(
294 'S_DISPLAY_JUMPBOX' => $display_jumpbox,
295 'S_JUMPBOX_ACTION' => $action)
302 // Compatibility functions
304 if (!function_exists('array_combine'))
307 * A wrapper for the PHP5 function array_combine()
308 * @param array $keys contains keys for the resulting array
309 * @param array $values contains values for the resulting array
311 * @return Returns an array by using the values from the keys array as keys and the
312 * values from the values array as the corresponding values. Returns false if the
313 * number of elements for each array isn't equal or if the arrays are empty.
315 function array_combine($keys, $values)
317 $keys = array_values($keys);
318 $values = array_values($values);
321 $m = sizeof($values);
322 if (!$n ||
!$m ||
($n != $m))
328 for ($i = 0; $i < $n; $i++
)
330 $combined[$keys[$i]] = $values[$i];
336 if (!function_exists('str_split'))
339 * A wrapper for the PHP5 function str_split()
340 * @param array $string contains the string to be converted
341 * @param array $split_length contains the length of each chunk
343 * @return Converts a string to an array. If the optional split_length parameter is specified,
344 * the returned array will be broken down into chunks with each being split_length in length,
345 * otherwise each chunk will be one character in length. FALSE is returned if split_length is
346 * less than 1. If the split_length length exceeds the length of string, the entire string is
347 * returned as the first (and only) array element.
349 function str_split($string, $split_length = 1)
351 if ($split_length < 1)
355 else if ($split_length >= strlen($string))
357 return array($string);
361 preg_match_all('#.{1,' . $split_length . '}#s', $string, $matches);
367 if (!function_exists('stripos'))
370 * A wrapper for the PHP5 function stripos
371 * Find position of first occurrence of a case-insensitive string
373 * @param string $haystack is the string to search in
374 * @param string needle is the string to search for
376 * @return Returns the numeric position of the first occurrence of needle in the haystack string. Unlike strpos(), stripos() is case-insensitive.
377 * Note that the needle may be a string of one or more characters.
378 * If needle is not found, stripos() will return boolean FALSE.
380 function stripos($haystack, $needle)
382 if (preg_match('#' . preg_quote($needle, '#') . '#i', $haystack, $m))
384 return strpos($haystack, $m[0]);
391 if (!function_exists('realpath'))
393 if (substr(PHP_OS
, 0, 3) != 'WIN' && !(bool) ini_get('safe_mode') && function_exists('shell_exec') && trim(`realpath
.`
))
396 * @author Chris Smith <chris@project-minerva.org>
397 * @copyright 2006 Project Minerva Team
398 * @param string $path The path which we should attempt to resolve.
401 function phpbb_realpath($path)
403 $arg = escapeshellarg($path);
404 return trim(`realpath
'$arg'`
);
410 * Checks if a path ($path) is absolute or relative
412 * @param string $path Path to check absoluteness of
415 function is_absolute($path)
417 return ($path[0] == '/' ||
(substr(PHP_OS
, 0, 3) == 'WIN' && preg_match('#^[a-z]:/#i', $path))) ?
true : false;
421 * @author Chris Smith <chris@project-minerva.org>
422 * @copyright 2006 Project Minerva Team
423 * @param string $path The path which we should attempt to resolve.
426 function phpbb_realpath($path)
428 // Now to perform funky shizzle
430 // Switch to use UNIX slashes
431 $path = str_replace(DIRECTORY_SEPARATOR
, '/', $path);
434 // Determine what sort of path we have
435 if (is_absolute($path))
441 // Absolute path, *NIX style
446 // Absolute path, Windows style
447 // Remove the drive letter and colon
448 $path_prefix = $path[0] . ':';
449 $path = substr($path, 2);
455 // Prepend the current working directory
456 if (function_exists('getcwd'))
458 // This is the best method, hopefully it is enabled!
459 $path = str_replace(DIRECTORY_SEPARATOR
, '/', getcwd()) . '/' . $path;
461 if (preg_match('#^[a-z]:#i', $path))
463 $path_prefix = $path[0] . ':';
464 $path = substr($path, 2);
471 else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
473 // Warning: If chdir() has been used this will lie!
474 // @todo This has some problems sometime (CLI can create them easily)
475 $path = str_replace(DIRECTORY_SEPARATOR
, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
481 // We have no way of getting the absolute path, just run on using relative ones.
487 // Remove any repeated slashes
488 $path = preg_replace('#/{2,}#', '/', $path);
490 // Remove the slashes from the start and end of the path
491 $path = trim($path, '/');
493 // Break the string into little bits for us to nibble on
494 $bits = explode('/', $path);
496 // Remove any . in the path
497 $bits = array_diff($bits, array('.'));
499 // Lets get looping, run over and resolve any .. (up directory)
500 for ($i = 0, $max = sizeof($bits); $i < $max; $i++
)
503 if ($bits[$i] == '..' )
505 if (isset($bits[$i - 1]))
507 if ($bits[$i - 1] != '..')
509 // We found a .. and we are able to traverse upwards, lets do it!
511 unset($bits[$i - 1]);
514 $bits = array_values($bits);
517 else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
519 // We have an absolute path trying to descend above the root of the filesystem
526 // Prepend the path prefix
527 array_unshift($bits, $path_prefix);
531 $max = sizeof($bits) - 1;
533 // Check if we are able to resolve symlinks, Windows cannot.
534 $symlink_resolve = (function_exists('readlink')) ?
true : false;
536 foreach ($bits as $i => $bit)
538 if (@is_dir
("$resolved/$bit") ||
($i == $max && @is_file
("$resolved/$bit")))
541 if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
543 // Resolved a symlink.
544 $resolved = $link . (($i == $max) ?
'' : '/');
550 // Something doesn't exist here!
551 // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
554 $resolved .= $bit . (($i == $max) ?
'' : '/');
557 // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
558 // because we must be inside that basedir, the question is where...
559 // @interal The slash in is_dir() gets around an open_basedir restriction
560 if (!@file_exists
($resolved) ||
(!is_dir($resolved . '/') && !is_file($resolved)))
565 // Put the slashes back to the native operating systems slashes
566 $resolved = str_replace('/', DIRECTORY_SEPARATOR
, $resolved);
568 return $resolved; // We got here, in the end!
575 * A wrapper for realpath
577 function phpbb_realpath($path)
579 return realpath($path);
583 // functions used for building option fields
586 * Pick a language, any language ...
588 function language_select($default = '')
592 $sql = 'SELECT lang_iso, lang_local_name
593 FROM ' . LANG_TABLE
. '
594 ORDER BY lang_english_name';
595 $result = $db->sql_query($sql, 600);
598 while ($row = $db->sql_fetchrow($result))
600 $selected = ($row['lang_iso'] == $default) ?
' selected="selected"' : '';
601 $lang_options .= '<option value="' . $row['lang_iso'] . '"' . $selected . '>' . $row['lang_local_name'] . '</option>';
603 $db->sql_freeresult($result);
605 return $lang_options;
609 * Pick a template/theme combo,
611 function style_select($default = '', $all = false)
615 $sql_where = (!$all) ?
'WHERE style_active = 1 ' : '';
616 $sql = 'SELECT style_id, style_name
617 FROM ' . STYLES_TABLE
. "
619 ORDER BY style_name";
620 $result = $db->sql_query($sql);
623 while ($row = $db->sql_fetchrow($result))
625 $selected = ($row['style_id'] == $default) ?
' selected="selected"' : '';
626 $style_options .= '<option value="' . $row['style_id'] . '"' . $selected . '>' . $row['style_name'] . '</option>';
628 $db->sql_freeresult($result);
630 return $style_options;
636 function tz_select($default = '', $truncate = false)
638 global $sys_timezone, $user;
641 foreach ($user->lang
['tz_zones'] as $offset => $zone)
645 $zone = (strlen($zone) > 70) ?
substr($zone, 0, 70) . '...' : $zone;
648 if (is_numeric($offset))
650 $selected = ($offset == $default) ?
' selected="selected"' : '';
651 $tz_select .= '<option value="' . $offset . '"' . $selected . '>' . $zone . '</option>';
658 // Functions handling topic/post tracking/marking
661 * Marks a topic/forum as read
662 * Marks a topic as posted to
664 * @param int $user_id can only be used with $mode == 'post'
666 function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
668 global $db, $user, $config;
672 if ($forum_id === false ||
!sizeof($forum_id))
674 if ($config['load_db_lastread'] && $user->data
['is_registered'])
676 // Mark all forums read (index page)
677 $db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE
. " WHERE user_id = {$user->data['user_id']}");
678 $db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE
. " WHERE user_id = {$user->data['user_id']}");
679 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
681 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
683 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
684 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
686 unset($tracking_topics['tf']);
687 unset($tracking_topics['t']);
688 unset($tracking_topics['f']);
689 $tracking_topics['l'] = base_convert(time() - $config['board_startdate'], 10, 36);
691 $user->set_cookie('track', serialize($tracking_topics), time() +
31536000);
692 unset($tracking_topics);
694 if ($user->data
['is_registered'])
696 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
703 else if ($mode == 'topics')
705 // Mark all topics in forums read
706 if (!is_array($forum_id))
708 $forum_id = array($forum_id);
711 // Add 0 to forums array to mark global announcements correctly
714 if ($config['load_db_lastread'] && $user->data
['is_registered'])
716 $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE
. "
717 WHERE user_id = {$user->data['user_id']}
718 AND " . $db->sql_in_set('forum_id', $forum_id);
719 $db->sql_query($sql);
721 $sql = 'SELECT forum_id
722 FROM ' . FORUMS_TRACK_TABLE
. "
723 WHERE user_id = {$user->data['user_id']}
724 AND " . $db->sql_in_set('forum_id', $forum_id);
725 $result = $db->sql_query($sql);
727 $sql_update = array();
728 while ($row = $db->sql_fetchrow($result))
730 $sql_update[] = $row['forum_id'];
732 $db->sql_freeresult($result);
734 if (sizeof($sql_update))
736 $sql = 'UPDATE ' . FORUMS_TRACK_TABLE
. '
737 SET mark_time = ' . time() . "
738 WHERE user_id = {$user->data['user_id']}
739 AND " . $db->sql_in_set('forum_id', $sql_update);
740 $db->sql_query($sql);
743 if ($sql_insert = array_diff($forum_id, $sql_update))
746 foreach ($sql_insert as $f_id)
749 'user_id' => $user->data
['user_id'],
751 'mark_time' => time()
755 if (sizeof($sql_ary))
762 $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE
. ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary));
766 foreach ($sql_ary as $ary)
768 $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE
. ' ' . $db->sql_build_array('INSERT', $ary));
775 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
777 $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
778 $tracking = ($tracking) ?
unserialize($tracking) : array();
780 foreach ($forum_id as $f_id)
782 $topic_ids36 = (isset($tracking['tf'][$f_id])) ?
$tracking['tf'][$f_id] : array();
784 if (isset($tracking['tf'][$f_id]))
786 unset($tracking['tf'][$f_id]);
789 foreach ($topic_ids36 as $topic_id36)
791 unset($tracking['t'][$topic_id36]);
794 if (isset($tracking['f'][$f_id]))
796 unset($tracking['f'][$f_id]);
799 $tracking['f'][$f_id] = base_convert(time() - $config['board_startdate'], 10, 36);
802 $user->set_cookie('track', serialize($tracking), time() +
31536000);
808 else if ($mode == 'topic')
810 if ($topic_id === false ||
$forum_id === false)
815 if ($config['load_db_lastread'] && $user->data
['is_registered'])
817 $sql = 'UPDATE ' . TOPICS_TRACK_TABLE
. '
818 SET mark_time = ' . (($post_time) ?
$post_time : time()) . "
819 WHERE user_id = {$user->data['user_id']}
820 AND topic_id = $topic_id";
821 $db->sql_query($sql);
824 if (!$db->sql_affectedrows())
826 $db->sql_return_on_error(true);
829 'user_id' => $user->data
['user_id'],
830 'topic_id' => $topic_id,
831 'forum_id' => (int) $forum_id,
832 'mark_time' => ($post_time) ?
$post_time : time(),
835 $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
837 $db->sql_return_on_error(false);
840 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
842 $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
843 $tracking = ($tracking) ?
unserialize($tracking) : array();
845 $topic_id36 = base_convert($topic_id, 10, 36);
847 if (!isset($tracking['t'][$topic_id36]))
849 $tracking['tf'][$forum_id][$topic_id36] = true;
852 $post_time = ($post_time) ?
$post_time : time();
853 $tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36);
855 // If the cookie grows larger than 10000 characters we will remove the smallest value
856 // This can result in old topics being unread - but most of the time it should be accurate...
857 if (isset($_COOKIE[$config['cookie_name'] . '_track']) && strlen($_COOKIE[$config['cookie_name'] . '_track']) > 10000)
859 //echo 'Cookie grown too large' . print_r($tracking, true);
861 // We get the ten most minimum stored time offsets and its associated topic ids
862 $time_keys = array();
863 for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++
)
865 $min_value = min($tracking['t']);
866 $m_tkey = array_search($min_value, $tracking['t']);
867 unset($tracking['t'][$m_tkey]);
869 $time_keys[$m_tkey] = $min_value;
872 // Now remove the topic ids from the array...
873 foreach ($tracking['tf'] as $f_id => $topic_id_ary)
875 foreach ($time_keys as $m_tkey => $min_value)
877 if (isset($topic_id_ary[$m_tkey]))
879 $tracking['f'][$f_id] = $min_value;
880 unset($tracking['tf'][$f_id][$m_tkey]);
885 if ($user->data
['is_registered'])
887 $user->data
['user_lastmark'] = intval(base_convert(max($time_keys) +
$config['board_startdate'], 36, 10));
888 $db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . $user->data
['user_lastmark'] . " WHERE user_id = {$user->data['user_id']}");
892 $tracking['l'] = max($time_keys);
896 $user->set_cookie('track', serialize($tracking), time() +
31536000);
901 else if ($mode == 'post')
903 if ($topic_id === false)
908 $use_user_id = (!$user_id) ?
$user->data
['user_id'] : $user_id;
910 if ($config['load_db_track'] && $use_user_id != ANONYMOUS
)
912 $db->sql_return_on_error(true);
915 'user_id' => $use_user_id,
916 'topic_id' => $topic_id,
920 $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
922 $db->sql_return_on_error(false);
930 * Get topic tracking info by using already fetched info
932 function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
934 global $config, $user;
936 $last_read = array();
938 if (!is_array($topic_ids))
940 $topic_ids = array($topic_ids);
943 foreach ($topic_ids as $topic_id)
945 if (!empty($rowset[$topic_id]['mark_time']))
947 $last_read[$topic_id] = $rowset[$topic_id]['mark_time'];
951 $topic_ids = array_diff($topic_ids, array_keys($last_read));
953 if (sizeof($topic_ids))
955 $mark_time = array();
957 // Get global announcement info
958 if ($global_announce_list && sizeof($global_announce_list))
960 if (!isset($forum_mark_time[0]))
964 $sql = 'SELECT mark_time
965 FROM ' . FORUMS_TRACK_TABLE
. "
966 WHERE user_id = {$user->data['user_id']}
968 $result = $db->sql_query($sql);
969 $row = $db->sql_fetchrow($result);
970 $db->sql_freeresult($result);
974 $mark_time[0] = $row['mark_time'];
979 if ($forum_mark_time[0] !== false)
981 $mark_time[0] = $forum_mark_time[0];
986 if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false)
988 $mark_time[$forum_id] = $forum_mark_time[$forum_id];
991 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user->data
['user_lastmark'];
993 foreach ($topic_ids as $topic_id)
995 if ($global_announce_list && isset($global_announce_list[$topic_id]))
997 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
1001 $last_read[$topic_id] = $user_lastmark;
1010 * Get topic tracking info from db (for cookie based tracking only this function is used)
1012 function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false)
1014 global $config, $user;
1016 $last_read = array();
1018 if (!is_array($topic_ids))
1020 $topic_ids = array($topic_ids);
1023 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1027 $sql = 'SELECT topic_id, mark_time
1028 FROM ' . TOPICS_TRACK_TABLE
. "
1029 WHERE user_id = {$user->data['user_id']}
1030 AND " . $db->sql_in_set('topic_id', $topic_ids);
1031 $result = $db->sql_query($sql);
1033 while ($row = $db->sql_fetchrow($result))
1035 $last_read[$row['topic_id']] = $row['mark_time'];
1037 $db->sql_freeresult($result);
1039 $topic_ids = array_diff($topic_ids, array_keys($last_read));
1041 if (sizeof($topic_ids))
1043 $sql = 'SELECT forum_id, mark_time
1044 FROM ' . FORUMS_TRACK_TABLE
. "
1045 WHERE user_id = {$user->data['user_id']}
1047 (($global_announce_list && sizeof($global_announce_list)) ?
"IN (0, $forum_id)" : "= $forum_id");
1048 $result = $db->sql_query($sql);
1050 $mark_time = array();
1051 while ($row = $db->sql_fetchrow($result))
1053 $mark_time[$row['forum_id']] = $row['mark_time'];
1055 $db->sql_freeresult($result);
1057 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user->data
['user_lastmark'];
1059 foreach ($topic_ids as $topic_id)
1061 if ($global_announce_list && isset($global_announce_list[$topic_id]))
1063 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
1067 $last_read[$topic_id] = $user_lastmark;
1072 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1074 global $tracking_topics;
1076 if (!isset($tracking_topics) ||
!sizeof($tracking_topics))
1078 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
1079 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
1082 if (!$user->data
['is_registered'])
1084 $user_lastmark = (isset($tracking_topics['l'])) ?
base_convert($tracking_topics['l'], 36, 10) +
$config['board_startdate'] : 0;
1088 $user_lastmark = $user->data
['user_lastmark'];
1091 foreach ($topic_ids as $topic_id)
1093 $topic_id36 = base_convert($topic_id, 10, 36);
1095 if (isset($tracking_topics['t'][$topic_id36]))
1097 $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) +
$config['board_startdate'];
1101 $topic_ids = array_diff($topic_ids, array_keys($last_read));
1103 if (sizeof($topic_ids))
1105 $mark_time = array();
1106 if ($global_announce_list && sizeof($global_announce_list))
1108 if (isset($tracking_topics['f'][0]))
1110 $mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) +
$config['board_startdate'];
1114 if (isset($tracking_topics['f'][$forum_id]))
1116 $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) +
$config['board_startdate'];
1119 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user_lastmark;
1121 foreach ($topic_ids as $topic_id)
1123 if ($global_announce_list && isset($global_announce_list[$topic_id]))
1125 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
1129 $last_read[$topic_id] = $user_lastmark;
1139 * Check for read forums and update topic tracking info accordingly
1141 * @param int $forum_id the forum id to check
1142 * @param int $forum_last_post_time the forums last post time
1143 * @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled
1144 * @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time
1146 * @return true if complete forum got marked read, else false.
1148 function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
1150 global $db, $tracking_topics, $user, $config;
1152 // Determine the users last forum mark time if not given.
1153 if ($mark_time_forum === false)
1155 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1157 $mark_time_forum = (!empty($f_mark_time)) ?
$f_mark_time : $user->data
['user_lastmark'];
1159 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1161 if (!isset($tracking_topics) ||
!sizeof($tracking_topics))
1163 $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ?
((STRIP
) ?
stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
1164 $tracking_topics = ($tracking_topics) ?
unserialize($tracking_topics) : array();
1167 if (!$user->data
['is_registered'])
1169 $user->data
['user_lastmark'] = (isset($tracking_topics['l'])) ?
(int) (base_convert($tracking_topics['l'], 36, 10) +
$config['board_startdate']) : 0;
1172 $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'];
1176 // Check the forum for any left unread topics.
1177 // If there are none, we mark the forum as read.
1178 if ($config['load_db_lastread'] && $user->data
['is_registered'])
1180 if ($mark_time_forum >= $forum_last_post_time)
1182 // We do not need to mark read, this happened before. Therefore setting this to true
1187 $sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE
. ' t
1188 LEFT JOIN ' . TOPICS_TRACK_TABLE
. ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data
['user_id'] . ')
1189 WHERE t.forum_id = ' . $forum_id . '
1190 AND t.topic_last_post_time > ' . $mark_time_forum . '
1191 AND t.topic_moved_id = 0
1192 AND tt.topic_id IS NULL
1193 GROUP BY t.forum_id';
1194 $result = $db->sql_query_limit($sql, 1);
1195 $row = $db->sql_fetchrow($result);
1196 $db->sql_freeresult($result);
1199 else if ($config['load_anon_lastread'] ||
$user->data
['is_registered'])
1201 // Get information from cookie
1204 if (!isset($tracking_topics['tf'][$forum_id]))
1206 // We do not need to mark read, this happened before. Therefore setting this to true
1211 $sql = 'SELECT topic_id
1212 FROM ' . TOPICS_TABLE
. '
1213 WHERE forum_id = ' . $forum_id . '
1214 AND topic_last_post_time > ' . $mark_time_forum . '
1215 AND topic_moved_id = 0';
1216 $result = $db->sql_query($sql);
1218 $check_forum = $tracking_topics['tf'][$forum_id];
1220 while ($row = $db->sql_fetchrow($result))
1222 if (!in_array(base_convert($row['topic_id'], 10, 36), array_keys($check_forum)))
1228 $db->sql_freeresult($result);
1240 markread('topics', $forum_id);
1247 // Pagination functions
1250 * Pagination routine, generates page number sequence
1251 * tpl_prefix is for using different pagination blocks at one page
1253 function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '')
1255 global $template, $user;
1257 $seperator = $user->theme
['pagination_sep'];
1258 $total_pages = ceil($num_items/$per_page);
1260 if ($total_pages == 1 ||
!$num_items)
1265 $on_page = floor($start_item / $per_page) +
1;
1266 $page_string = ($on_page == 1) ?
'<strong>1</strong>' : '<a href="' . $base_url . '">1</a>';
1268 if ($total_pages > 5)
1270 $start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
1271 $end_cnt = max(min($total_pages, $on_page +
4), 6);
1273 $page_string .= ($start_cnt > 1) ?
' ... ' : $seperator;
1275 for ($i = $start_cnt +
1; $i < $end_cnt; $i++
)
1277 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "&start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1278 if ($i < $end_cnt - 1)
1280 $page_string .= $seperator;
1284 $page_string .= ($end_cnt < $total_pages) ?
' ... ' : $seperator;
1288 $page_string .= $seperator;
1290 for ($i = 2; $i < $total_pages; $i++
)
1292 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "&start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1293 if ($i < $total_pages)
1295 $page_string .= $seperator;
1300 $page_string .= ($on_page == $total_pages) ?
'<strong>' . $total_pages . '</strong>' : '<a href="' . $base_url . '&start=' . (($total_pages - 1) * $per_page) . '">' . $total_pages . '</a>';
1302 if ($add_prevnext_text)
1306 $page_string = '<a href="' . $base_url . '&start=' . (($on_page - 2) * $per_page) . '">' . $user->lang
['PREVIOUS'] . '</a> ' . $page_string;
1309 if ($on_page != $total_pages)
1311 $page_string .= ' <a href="' . $base_url . '&start=' . ($on_page * $per_page) . '">' . $user->lang
['NEXT'] . '</a>';
1315 $template->assign_vars(array(
1316 $tpl_prefix . 'BASE_URL' => $base_url,
1317 $tpl_prefix . 'PER_PAGE' => $per_page,
1319 $tpl_prefix . 'PREVIOUS_PAGE' => ($on_page == 1) ?
'' : $base_url . '&start=' . (($on_page - 2) * $per_page),
1320 $tpl_prefix . 'NEXT_PAGE' => ($on_page == $total_pages) ?
'' : $base_url . '&start=' . ($on_page * $per_page))
1323 return $page_string;
1327 * Return current page (pagination)
1329 function on_page($num_items, $per_page, $start)
1331 global $template, $user;
1333 $on_page = floor($start / $per_page) +
1;
1335 $template->assign_vars(array(
1336 'ON_PAGE' => $on_page)
1339 return sprintf($user->lang
['PAGE_OF'], $on_page, max(ceil($num_items / $per_page), 1));
1342 // Server functions (building urls, redirecting...)
1345 * Append session id to url
1347 * @param string $url The url the session id needs to be appended to (can have params)
1348 * @param mixed $params String or array of additional url parameters
1349 * @param bool $is_amp Is url using & (true) or & (false)
1350 * @param string $session_id Possibility to use a custom session id instead of the global one
1354 * append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&f=2");
1355 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2');
1356 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false);
1357 * append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2));
1360 function append_sid($url, $params = false, $is_amp = true, $session_id = false)
1362 global $_SID, $_EXTRA_URL;
1364 // Assign sid if session id is not specified
1365 if ($session_id === false)
1367 $session_id = $_SID;
1370 $amp_delim = ($is_amp) ?
'&' : '&';
1371 $url_delim = (strpos($url, '?') === false) ?
'?' : $amp_delim;
1373 // Appending custom url parameter?
1374 $append_url = (!empty($_EXTRA_URL)) ?
implode($amp_delim, $_EXTRA_URL) : '';
1376 // Use the short variant if possible ;)
1377 if ($params === false)
1379 // Append session id
1380 return (!$session_id) ?
$url . (($append_url) ?
$url_delim . $append_url : '') : $url . (($append_url) ?
$url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id;
1383 // Build string if parameters are specified as array
1384 if (is_array($params))
1388 foreach ($params as $key => $item)
1395 $output[] = $key . '=' . $item;
1398 $params = implode($amp_delim, $output);
1401 // Append session id and parameters (even if they are empty)
1402 // If parameters are empty, the developer can still append his/her parameters without caring about the delimiter
1403 return $url . (($append_url) ?
$url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ?
'' : $amp_delim . 'sid=' . $session_id);
1407 * Generate board url (example: http://www.foo.bar/phpBB)
1408 * @param bool $without_script_path if set to true the script path gets not appended (example: http://www.foo.bar)
1410 function generate_board_url($without_script_path = false)
1412 global $config, $user;
1414 $server_name = (!empty($_SERVER['SERVER_NAME'])) ?
$_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
1415 $server_port = (!empty($_SERVER['SERVER_PORT'])) ?
(int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
1417 // Forcing server vars is the only way to specify/override the protocol
1418 if ($config['force_server_vars'] ||
!$server_name)
1420 $server_protocol = ($config['server_protocol']) ?
$config['server_protocol'] : (($config['cookie_secure']) ?
'https://' : 'http://');
1421 $server_name = $config['server_name'];
1422 $server_port = (int) $config['server_port'];
1424 $url = $server_protocol . $server_name;
1428 // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection
1429 $cookie_secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ?
1 : 0;
1430 $url = (($cookie_secure) ?
'https://' : 'http://') . $server_name;
1433 if ($server_port && (($config['cookie_secure'] && $server_port <> 443) ||
(!$config['cookie_secure'] && $server_port <> 80)))
1435 $url .= ':' . $server_port;
1438 if ($without_script_path)
1443 // Strip / from the end
1444 return $url . substr($user->page
['root_script_path'], 0, -1);
1448 * Redirects the user to another page then exits the script nicely
1450 function redirect($url)
1452 global $db, $cache, $config, $user;
1454 if (empty($user->lang
))
1456 $user->add_lang('common');
1459 garbage_collection();
1461 // Make sure no &'s are in, this will break the redirect
1462 $url = str_replace('&', '&', $url);
1464 // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
1465 if (strpos(urldecode($url), "\n") !== false ||
strpos(urldecode($url), "\r") !== false)
1467 trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR
);
1470 // Determine which type of redirect we need to handle...
1471 $url_parts = parse_url($url);
1473 if ($url_parts === false)
1475 // Malformed url, redirect to current page...
1476 $url = generate_board_url() . '/' . $user->page
['page'];
1478 else if (!empty($url_parts['scheme']) && !empty($url_parts['host']))
1482 else if ($url{0} == '/')
1484 // Absolute uri, prepend direct url...
1485 $url = generate_board_url(true) . $url;
1490 $pathinfo = pathinfo($url);
1492 // Is the uri pointing to the current directory?
1493 if ($pathinfo['dirname'] == '.')
1495 if ($user->page
['page_dir'])
1497 $url = generate_board_url() . '/' . $user->page
['page_dir'] . '/' . str_replace('./', '', $url);
1501 $url = generate_board_url() . '/' . str_replace('./', '', $url);
1506 // Get the realpath of dirname
1507 $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
1508 $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
1509 $intersection = array_intersect_assoc($root_dirs, $page_dirs);
1511 $root_dirs = array_diff_assoc($root_dirs, $intersection);
1512 $page_dirs = array_diff_assoc($page_dirs, $intersection);
1514 $dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
1516 if ($dir && substr($dir, -1, 1) == '/')
1518 $dir = substr($dir, 0, -1);
1521 $url = $dir . '/' . str_replace($pathinfo['dirname'] . '/', '', $url);
1522 $url = generate_board_url() . '/' . $url;
1526 // Redirect via an HTML form for PITA webservers
1527 if (@preg_match
('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE')))
1529 header('Refresh: 0; URL=' . $url);
1530 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>';
1535 // Behave as per HTTP/1.1 spec for others
1536 header('Location: ' . $url);
1541 * Re-Apply session id after page reloads
1543 function reapply_sid($url)
1545 global $phpEx, $phpbb_root_path;
1547 if ($url === "index.$phpEx")
1549 return append_sid("index.$phpEx");
1551 else if ($url === "{$phpbb_root_path}index.$phpEx")
1553 return append_sid("{$phpbb_root_path}index.$phpEx");
1556 // Remove previously added sid
1557 if (strpos($url, '?sid=') !== false)
1559 $url = preg_replace('/(\?)sid=[a-z0-9]+(&|&)?/', '\1', $url);
1561 else if (strpos($url, '&sid=') !== false)
1563 $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
1565 else if (strpos($url, '&sid=') !== false)
1567 $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
1570 return append_sid($url);
1574 * Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url
1576 function build_url($strip_vars = false)
1578 global $user, $phpbb_root_path;
1581 $redirect = (($user->page
['page_dir']) ?
$user->page
['page_dir'] . '/' : '') . $user->page
['page_name'] . (($user->page
['query_string']) ?
"?{$user->page['query_string']}" : '');
1582 $redirect = append_sid($redirect, false, false);
1584 // Add delimiter if not there...
1585 if (strpos($redirect, '?') === false)
1591 if ($strip_vars !== false && strpos($redirect, '?') !== false)
1593 if (!is_array($strip_vars))
1595 $strip_vars = array($strip_vars);
1598 $query = $_query = array();
1599 parse_str(substr($redirect, strpos($redirect, '?') +
1), $query);
1600 $redirect = substr($redirect, 0, strpos($redirect, '?'));
1602 // Strip the vars off
1603 foreach ($strip_vars as $strip)
1605 if (isset($query[$strip]))
1607 unset($query[$strip]);
1612 foreach ($query as $key => $value)
1614 $_query[] = $key . '=' . $value;
1616 $query = implode('&', $_query);
1618 $redirect .= ($query) ?
'?' . $query : '';
1621 return $phpbb_root_path . str_replace('&', '&', $redirect);
1625 * Meta refresh assignment
1627 function meta_refresh($time, $url)
1631 $template->assign_vars(array(
1632 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />')
1636 // Message/Login boxes
1640 * @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
1641 * @param string $title Title/Message used for confirm box.
1642 * message text is _CONFIRM appended to title.
1643 * If title can not be found in user->lang a default one is displayed
1644 * If title_CONFIRM can not be found in user->lang the text given is used.
1645 * @param string $hidden Hidden variables
1646 * @param string $html_body Template used for confirm box
1647 * @param string $u_action Custom form action
1649 function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
1651 global $user, $template, $db;
1652 global $phpEx, $phpbb_root_path;
1654 if (isset($_POST['cancel']))
1660 if (isset($_POST['confirm']))
1662 // language frontier
1663 if ($_POST['confirm'] == $user->lang
['YES'])
1669 if ($check && $confirm)
1671 $user_id = request_var('user_id', 0);
1672 $session_id = request_var('sess', '');
1673 $confirm_key = request_var('confirm_key', '');
1675 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'])
1680 // Reset user_last_confirm_key
1681 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = ''
1682 WHERE user_id = " . $user->data
['user_id'];
1683 $db->sql_query($sql);
1692 $s_hidden_fields = build_hidden_fields(array(
1693 'user_id' => $user->data
['user_id'],
1694 'sess' => $user->session_id
,
1695 'sid' => $user->session_id
)
1698 // generate activation key
1699 $confirm_key = gen_rand_string(10);
1701 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
1703 adm_page_header((!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title]);
1707 page_header((!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title]);
1710 $template->set_filenames(array(
1711 'body' => $html_body)
1714 // If activation key already exist, we better do not re-use the key (something very strange is going on...)
1715 if (request_var('confirm_key', ''))
1717 // This should not occur, therefore we cancel the operation to safe the user
1721 // re-add sid / transform & to & for user->page (user->page is always using &)
1722 $use_page = ($u_action) ?
$phpbb_root_path . $u_action : $phpbb_root_path . str_replace('&', '&', $user->page
['page']);
1723 $u_action = reapply_sid($use_page);
1724 $u_action .= ((strpos($u_action, '?') === false) ?
'?' : '&') . 'confirm_key=' . $confirm_key;
1726 $template->assign_vars(array(
1727 'MESSAGE_TITLE' => (!isset($user->lang
[$title])) ?
$user->lang
['CONFIRM'] : $user->lang
[$title],
1728 'MESSAGE_TEXT' => (!isset($user->lang
[$title . '_CONFIRM'])) ?
$title : $user->lang
[$title . '_CONFIRM'],
1730 'YES_VALUE' => $user->lang
['YES'],
1731 'S_CONFIRM_ACTION' => $u_action,
1732 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
1735 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
1736 WHERE user_id = " . $user->data
['user_id'];
1737 $db->sql_query($sql);
1739 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
1750 * Generate login box or verify password
1752 function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
1754 global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
1758 // Make sure user->setup() has been called
1759 if (empty($user->lang
))
1764 // Print out error if user tries to authenticate as an administrator without having the privileges...
1765 if ($admin && !$auth->acl_get('a_'))
1768 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1769 if ($user->data
['is_registered'])
1771 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1773 trigger_error('NO_AUTH_ADMIN');
1776 if (isset($_POST['login']))
1778 $username = request_var('username', '');
1779 $password = request_var('password', '');
1780 $autologin = (!empty($_POST['autologin'])) ?
true : false;
1781 $viewonline = (!empty($_POST['viewonline'])) ?
0 : 1;
1782 $admin = ($admin) ?
1 : 0;
1784 // Check if the supplied username is equal to the one stored within the database if re-authenticating
1785 if ($admin && strtolower($username) != strtolower($user->data
['username']))
1787 // We log the attempt to use a different username...
1788 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1789 trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
1792 // If authentication is successful we redirect user to previous page
1793 $result = $auth->login($username, $password, $autologin, $viewonline, $admin);
1795 // If admin authentication and login, we will log if it was a success or not...
1796 // We also break the operation on the first non-success login - it could be argued that the user already knows
1799 if ($result['status'] == LOGIN_SUCCESS
)
1801 add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
1805 // Only log the failed attempt if a real user tried to.
1806 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1807 if ($user->data
['is_registered'])
1809 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1814 // The result parameter is always an array, holding the relevant informations...
1815 if ($result['status'] == LOGIN_SUCCESS
)
1817 $redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx");
1818 $message = ($l_success) ?
$l_success : $user->lang
['LOGIN_REDIRECT'];
1819 $l_redirect = ($admin) ?
$user->lang
['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx") ?
$user->lang
['RETURN_INDEX'] : $user->lang
['RETURN_PAGE']);
1821 // append/replace SID (may change during the session for AOL users)
1822 $redirect = reapply_sid($redirect);
1824 meta_refresh(3, $redirect);
1825 trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>'));
1828 // Something failed, determine what...
1829 if ($result['status'] == LOGIN_BREAK
)
1831 trigger_error($result['error_msg'], E_USER_ERROR
);
1834 // Special cases... determine
1835 switch ($result['status'])
1837 case LOGIN_ERROR_ATTEMPTS
:
1839 // Show confirm image
1840 $sql = 'DELETE FROM ' . CONFIRM_TABLE
. "
1841 WHERE session_id = '" . $db->sql_escape($user->session_id
) . "'
1842 AND confirm_type = " . CONFIRM_LOGIN
;
1843 $db->sql_query($sql);
1846 $code = gen_rand_string(mt_rand(5, 8));
1847 $confirm_id = md5(unique_id($user->ip
));
1849 $sql = 'INSERT INTO ' . CONFIRM_TABLE
. ' ' . $db->sql_build_array('INSERT', array(
1850 'confirm_id' => (string) $confirm_id,
1851 'session_id' => (string) $user->session_id
,
1852 'confirm_type' => (int) CONFIRM_LOGIN
,
1853 'code' => (string) $code)
1855 $db->sql_query($sql);
1857 $template->assign_vars(array(
1858 'S_CONFIRM_CODE' => true,
1859 'CONFIRM_ID' => $confirm_id,
1860 'CONFIRM_IMAGE' => '<img src="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=confirm&id=' . $confirm_id . '&type=' . CONFIRM_LOGIN
) . '" alt="" title="" />',
1861 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang
['LOGIN_CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>'),
1864 $err = $user->lang
[$result['error_msg']];
1868 // Username, password, etc...
1870 $err = $user->lang
[$result['error_msg']];
1872 // Assign admin contact to some error messages
1873 if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' ||
$result['error_msg'] == 'LOGIN_ERROR_PASSWORD')
1875 $err = (!$config['board_contact']) ?
sprintf($user->lang
[$result['error_msg']], '', '') : sprintf($user->lang
[$result['error_msg']], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>');
1883 // We just use what the session code determined...
1884 // If we are not within the admin directory we use the page dir...
1889 $redirect .= ($user->page
['page_dir']) ?
$user->page
['page_dir'] . '/' : '';
1892 $redirect .= $user->page
['page_name'] . (($user->page
['query_string']) ?
'?' . $user->page
['query_string'] : '');
1895 $s_hidden_fields = build_hidden_fields(array('redirect' => $redirect, 'sid' => $user->session_id
));
1897 $template->assign_vars(array(
1898 'LOGIN_ERROR' => $err,
1899 'LOGIN_EXPLAIN' => $l_explain,
1901 'U_SEND_PASSWORD' => ($config['email_enable']) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '',
1902 'U_RESEND_ACTIVATION' => ($config['require_activation'] != USER_ACTIVATION_NONE
&& $config['email_enable']) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '',
1903 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
1904 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
1906 'S_DISPLAY_FULL_LOGIN' => ($s_display) ?
true : false,
1907 '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
1908 'S_HIDDEN_FIELDS' => $s_hidden_fields,
1910 'S_ADMIN_AUTH' => $admin,
1911 'USERNAME' => ($admin) ?
$user->data
['username'] : '')
1914 page_header($user->lang
['LOGIN']);
1916 $template->set_filenames(array(
1917 'body' => 'login_body.html')
1919 make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
1925 * Generate forum login box
1927 function login_forum_box($forum_data)
1929 global $db, $config, $user, $template, $phpEx;
1931 $password = request_var('password', '');
1933 $sql = 'SELECT forum_id
1934 FROM ' . FORUMS_ACCESS_TABLE
. '
1935 WHERE forum_id = ' . $forum_data['forum_id'] . '
1936 AND user_id = ' . $user->data
['user_id'] . "
1937 AND session_id = '" . $db->sql_escape($user->session_id
) . "'";
1938 $result = $db->sql_query($sql);
1939 $row = $db->sql_fetchrow($result);
1940 $db->sql_freeresult($result);
1949 // Remove expired authorised sessions
1950 $sql = 'SELECT session_id
1951 FROM ' . SESSIONS_TABLE
;
1952 $result = $db->sql_query($sql);
1954 if ($row = $db->sql_fetchrow($result))
1959 $sql_in[] = (string) $row['session_id'];
1961 while ($row = $db->sql_fetchrow($result));
1963 // Remove expired sessions
1964 $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE
. '
1965 WHERE ' . $db->sql_in_set('session_id', $sql_in, true);
1966 $db->sql_query($sql);
1968 $db->sql_freeresult($result);
1970 if ($password == $forum_data['forum_password'])
1973 'forum_id' => (int) $forum_data['forum_id'],
1974 'user_id' => (int) $user->data
['user_id'],
1975 'session_id' => (string) $user->session_id
,
1978 $db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
1983 $template->assign_var('LOGIN_ERROR', $user->lang
['WRONG_PASSWORD']);
1986 page_header($user->lang
['LOGIN']);
1988 $template->assign_vars(array(
1989 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id'])))
1992 $template->set_filenames(array(
1993 'body' => 'login_forum.html')
1999 // Content related functions
2002 * Bump Topic Check - used by posting and viewtopic
2004 function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster)
2006 global $config, $auth, $user;
2008 // Check permission and make sure the last post was not already bumped
2009 if (!$auth->acl_get('f_bump', $forum_id) ||
$topic_bumped)
2014 // Check bump time range, is the user really allowed to bump the topic at this time?
2015 $bump_time = ($config['bump_type'] == 'm') ?
$config['bump_interval'] * 60 : (($config['bump_type'] == 'h') ?
$config['bump_interval'] * 3600 : $config['bump_interval'] * 86400);
2018 if ($last_post_time +
$bump_time > time())
2023 // Check bumper, only topic poster and last poster are allowed to bump
2024 if ($topic_poster != $user->data
['user_id'] && $last_topic_poster != $user->data
['user_id'] && !$auth->acl_get('m_', $forum_id))
2029 // A bump time of 0 will completely disable the bump feature... not intended but might be useful.
2034 * Generates a text with approx. the specified length which contains the specified words and their context
2036 * @param string $text The full text from which context shall be extracted
2037 * @param string $words An array of words which should be contained in the result, * is allowed as a wildcard
2038 * @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value
2040 * @return string Context of the specified words seperated by "..."
2042 function get_context($text, $words, $length = 400)
2044 // first replace all whitespaces with single spaces
2045 $text = preg_replace('/\s+/', ' ', $text);
2047 $word_indizes = array();
2051 // find the starting indizes of all words
2052 foreach ($words as $word)
2054 if (preg_match('#(?:[^\w]|^)(' . str_replace('\*', '\w*?', preg_quote($word, '#')) . ')(?:[^\w]|$)#i', $text, $match))
2056 $pos = strpos($text, $match[1]);
2059 $word_indizes[] = $pos;
2065 if (sizeof($word_indizes))
2067 $word_indizes = array_unique($word_indizes);
2068 sort($word_indizes);
2070 $wordnum = sizeof($word_indizes);
2071 // number of characters on the right and left side of each word
2072 $sequence_length = (int) ($length / (2 * $wordnum)) - 2;
2075 $final_text_index = -1;
2077 // cycle through every character in the original text
2078 for ($i = $word_indizes[$word], $n = strlen($text); $i < $n; $i++
)
2080 // if the current position is the start of one of the words then append $sequence_length characters to the final text
2081 if (isset($word_indizes[$word]) && ($i == $word_indizes[$word]))
2083 if ($final_text_index < $i - $sequence_length - 1)
2085 $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', substr($text, $i - $sequence_length, $sequence_length));
2089 // if the final text is already nearer to the current word than $sequence_length we only append the text
2090 // from its current index on and distribute the unused length to all other sequenes
2091 $sequence_length +
= (int) (($final_text_index - $i +
$sequence_length +
1) / (2 * $wordnum));
2092 $final_text .= substr($text, $final_text_index +
1, $i - $final_text_index - 1);
2094 $final_text_index = $i - 1;
2096 // add the following characters to the final text (see below)
2103 // add the character to the final text and increment the sequence counter
2104 $final_text .= $text[$i];
2105 $final_text_index++
;
2108 // if this is a whitespace then check whether we are done with this sequence
2109 if ($text[$i] == ' ')
2111 // only check whether we have to exit the context generation completely if we haven't already reached the end anyway
2114 if (($j > $sequence_length && $word >= $wordnum) ||
strlen($final_text) > $length)
2116 $final_text .= ' ...';
2122 // make sure the text really reaches the end
2126 // stop context generation and wait for the next word
2127 if ($j > $sequence_length)
2138 if (!sizeof($words) ||
!sizeof($word_indizes))
2140 return (strlen($text) >= $length +
3) ?
substr($text, 0, $length) . '...' : $text;
2145 * Decode text whereby text is coming from the db and expected to be pre-parsed content
2146 * We are placing this outside of the message parser because we are often in need of it...
2148 function decode_message(&$message, $bbcode_uid = '')
2154 $match = array('<br />', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid");
2155 $replace = array("\n", '', '', '', '');
2159 $match = array('<br />');
2160 $replace = array("\n");
2163 $message = str_replace($match, $replace, $message);
2165 $match = get_preg_expression('bbcode_htm');
2166 $replace = array('\1', '\2', '\1', '', '');
2168 $message = preg_replace($match, $replace, $message);
2172 * Strips all bbcode from a text and returns the plain content
2174 function strip_bbcode(&$text, $uid = '')
2178 $uid = '[0-9a-z]{5,}';
2181 $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?$uid)\]#", ' ', $text);
2183 $match = get_preg_expression('bbcode_htm');
2184 $replace = array('\1', '\2', '\1', '', '');
2186 $text = preg_replace($match, $replace, $text);
2190 * For display of custom parsed text on user-facing pages
2191 * Expects $text to be the value directly from the database (stored value)
2193 function generate_text_for_display($text, $uid, $bitfield, $flags)
2202 $text = str_replace("\n", '<br />', censor_text($text));
2204 // Parse bbcode if bbcode uid stored and bbcode enabled
2205 if ($uid && ($flags & OPTION_FLAG_BBCODE
))
2207 if (!class_exists('bbcode'))
2209 global $phpbb_root_path, $phpEx;
2210 include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
2215 $bbcode = new bbcode($bitfield);
2219 $bbcode->bbcode($bitfield);
2222 $bbcode->bbcode_second_pass($text, $uid);
2225 $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES
));
2231 * For parsing custom parsed text to be stored within the database.
2232 * This function additionally returns the uid and bitfield that needs to be stored.
2233 * Expects $text to be the value directly from request_var() and in it's non-parsed form
2235 function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false)
2237 global $phpbb_root_path, $phpEx;
2247 if (!class_exists('parse_message'))
2249 include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx);
2252 $message_parser = new parse_message($text);
2253 $message_parser->parse($allow_bbcode, $allow_urls, $allow_smilies);
2255 $text = $message_parser->message
;
2256 $uid = $message_parser->bbcode_uid
;
2258 // If the bbcode_bitfield is empty, there is no need for the uid to be stored.
2259 if (!$message_parser->bbcode_bitfield
)
2264 $flags = (($allow_bbcode) ?
1 : 0) +
(($allow_smilies) ?
2 : 0) +
(($allow_urls) ?
4 : 0);
2265 $bitfield = $message_parser->bbcode_bitfield
;
2271 * For decoding custom parsed text for edits as well as extracting the flags
2272 * Expects $text to be the value directly from the database (pre-parsed content)
2274 function generate_text_for_edit($text, $uid, $flags)
2276 global $phpbb_root_path, $phpEx;
2278 decode_message($text, $uid);
2281 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE
) ?
1 : 0,
2282 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES
) ?
1 : 0,
2283 'allow_urls' => ($flags & OPTION_FLAG_LINKS
) ?
1 : 0,
2289 * make_clickable function
2291 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
2292 * Cuts down displayed size of link if over 50 chars, turns absolute links
2293 * into relative versions when the server/script path matches the link
2295 function make_clickable($text, $server_url = false)
2297 if ($server_url === false)
2299 $server_url = generate_board_url();
2302 static $magic_url_match;
2303 static $magic_url_replace;
2305 if (!is_array($magic_url_match))
2307 $magic_url_match = $magic_url_replace = array();
2308 // Be sure to not let the matches cross over. ;)
2310 // relative urls for this board
2311 $magic_url_match[] = '#(^|[\n ]|\()(' . preg_quote($server_url, '#') . ')/(([^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2312 $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 -->'";
2314 // matches a xxxx://aaaaa.bbb.cccc. ...
2315 $magic_url_match[] = '#(^|[\n ]|\()([\w]+:/{2}.*?([^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2316 $magic_url_replace[] = "'\$1<!-- m --><a href=\"\$2\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- m -->'";
2318 // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
2319 $magic_url_match[] = '#(^|[\n ]|\()(w{3}\.[\w\-]+\.[\w\-.\~]+(?:[^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie';
2320 $magic_url_replace[] = "'\$1<!-- w --><a href=\"http://\$2\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- w -->'";
2322 // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode.
2323 $magic_url_match[] = '/(^|[\n ]|\()(' . get_preg_expression('email') . ')/ie';
2324 $magic_url_replace[] = "'\$1<!-- e --><a href=\"mailto:\$2\">' . ((strlen('\$2') > 55) ? substr('\$2', 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . '</a><!-- e -->'";
2327 return preg_replace($magic_url_match, $magic_url_replace, $text);
2333 function censor_text($text)
2338 if (!isset($censors) ||
!is_array($censors))
2342 // obtain_word_list is taking care of the users censor option and the board-wide option
2343 $cache->obtain_word_list($censors);
2346 if (sizeof($censors))
2348 return preg_replace($censors['match'], $censors['replace'], $text);
2357 function smiley_text($text, $force_option = false)
2359 global $config, $user, $phpbb_root_path;
2361 if ($force_option ||
!$config['allow_smilies'] ||
!$user->optionget('viewsmilies'))
2363 return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', '\1', $text);
2367 return str_replace('<img src="{SMILIES_PATH}', '<img src="' . $phpbb_root_path . $config['smilies_path'], $text);
2372 * Inline Attachment processing
2374 function parse_inline_attachments(&$text, &$attachments, &$update_count, $forum_id = 0, $preview = false)
2376 global $config, $user;
2378 if (!function_exists('display_attachments'))
2380 global $phpbb_root_path, $phpEx;
2381 include_once("{$phpbb_root_path}includes/functions_display.$phpEx");
2384 $attachments = display_attachments($forum_id, NULL, $attachments, $update_count, false, true);
2385 $tpl_size = sizeof($attachments);
2387 $unset_tpl = array();
2389 preg_match_all('#<!\-\- ia([0-9]+) \-\->(.*?)<!\-\- ia\1 \-\->#', $text, $matches, PREG_PATTERN_ORDER
);
2392 foreach ($matches[0] as $num => $capture)
2394 // Flip index if we are displaying the reverse way
2395 $index = ($config['display_order']) ?
($tpl_size-($matches[1][$num] +
1)) : $matches[1][$num];
2397 $replace['from'][] = $matches[0][$num];
2398 $replace['to'][] = (isset($attachments[$index])) ?
$attachments[$index] : sprintf($user->lang
['MISSING_INLINE_ATTACHMENT'], $matches[2][array_search($index, $matches[1])]);
2400 $unset_tpl[] = $index;
2403 if (isset($replace['from']))
2405 $text = str_replace($replace['from'], $replace['to'], $text);
2408 return array_unique($unset_tpl);
2412 * Check if extension is allowed to be posted within forum X (forum_id 0 == private messaging)
2414 function extension_allowed($forum_id, $extension, &$extensions)
2416 if (!sizeof($extensions))
2420 $extensions = array();
2421 $cache->obtain_attach_extensions($extensions);
2424 if (!isset($extensions['_allowed_'][$extension]))
2429 $check = $extensions['_allowed_'][$extension];
2431 if (is_array($check))
2433 // Check for private messaging AND all forums allowed
2434 if (sizeof($check) == 1 && $check[0] == 0)
2439 return (!in_array($forum_id, $check)) ?
false : true;
2442 return ($forum_id == 0) ?
false : true;
2448 * Little helper for the build_hidden_fields function
2450 function _build_hidden_fields($key, $value, $specialchar)
2452 $hidden_fields = '';
2454 if (!is_array($value))
2456 $key = ($specialchar) ?
htmlspecialchars($key) : $key;
2457 $value = ($specialchar) ?
htmlspecialchars($value) : $value;
2459 $hidden_fields .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />' . "\n";
2463 foreach ($value as $_key => $_value)
2465 $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar);
2469 return $hidden_fields;
2473 * Build simple hidden fields from array
2475 function build_hidden_fields($field_ary, $specialchar = false)
2477 $s_hidden_fields = '';
2479 foreach ($field_ary as $name => $vars)
2481 $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar);
2484 return $s_hidden_fields;
2490 function parse_cfg_file($filename, $lines = false)
2492 $parsed_items = array();
2494 if ($lines === false)
2496 $lines = file($filename);
2499 foreach ($lines as $line)
2501 $line = trim($line);
2503 if (!$line ||
$line{0} == '#' ||
($delim_pos = strpos($line, '=')) === false)
2508 // Determine first occurrence, since in values the equal sign is allowed
2509 $key = strtolower(trim(substr($line, 0, $delim_pos)));
2510 $value = trim(substr($line, $delim_pos +
1));
2512 if (in_array($value, array('off', 'false', '0')))
2516 else if (in_array($value, array('on', 'true', '1')))
2520 else if (!trim($value))
2524 else if (($value{0} == "'" && $value{sizeof($value)-1} == "'") ||
($value{0} == '"' && $value{sizeof($value)-1} == '"'))
2526 $value = substr($value, 1, sizeof($value)-2);
2529 $parsed_items[$key] = $value;
2532 return $parsed_items;
2542 $args = func_get_args();
2544 $mode = array_shift($args);
2545 $reportee_id = ($mode == 'user') ?
intval(array_shift($args)) : '';
2546 $forum_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
2547 $topic_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
2548 $action = array_shift($args);
2549 $data = (!sizeof($args)) ?
'' : serialize($args);
2552 'user_id' => (empty($user->data
)) ? ANONYMOUS
: $user->data
['user_id'],
2553 'log_ip' => $user->ip
,
2554 'log_time' => time(),
2555 'log_operation' => $action,
2556 'log_data' => $data,
2562 $sql_ary['log_type'] = LOG_ADMIN
;
2567 'log_type' => LOG_MOD
,
2568 'forum_id' => $forum_id,
2569 'topic_id' => $topic_id
2575 'log_type' => LOG_USERS
,
2576 'reportee_id' => $reportee_id
2581 $sql_ary['log_type'] = LOG_CRITICAL
;
2588 $db->sql_query('INSERT INTO ' . LOG_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
2590 return $db->sql_nextid();
2594 * Return a nicely formatted backtrace (parts from the php manual by diz at ysagoon dot com)
2596 function get_backtrace()
2598 global $phpbb_root_path;
2600 $output = '<div style="font-family: monospace;">';
2601 $backtrace = debug_backtrace();
2602 $path = phpbb_realpath($phpbb_root_path);
2604 foreach ($backtrace as $number => $trace)
2606 // We skip the first one, because it only shows this file/function
2612 // Strip the current directory from path
2613 $trace['file'] = str_replace(array($path, '\\'), array('', '/'), $trace['file']);
2614 $trace['file'] = substr($trace['file'], 1);
2617 // If include/require/include_once is not called, do not show arguments - they may contain sensible informations
2618 if (!in_array($trace['function'], array('include', 'require', 'include_once')))
2620 unset($trace['args']);
2625 if (!empty($trace['args'][0]))
2627 $argument = htmlspecialchars($trace['args'][0]);
2628 $argument = str_replace(array($path, '\\'), array('', '/'), $argument);
2629 $argument = substr($argument, 1);
2630 $args[] = "'{$argument}'";
2634 $trace['class'] = (!isset($trace['class'])) ?
'' : $trace['class'];
2635 $trace['type'] = (!isset($trace['type'])) ?
'' : $trace['type'];
2637 $output .= '<br />';
2638 $output .= '<b>FILE:</b> ' . htmlspecialchars($trace['file']) . '<br />';
2639 $output .= '<b>LINE:</b> ' . $trace['line'] . '<br />';
2641 $output .= '<b>CALL:</b> ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']) . '(' . ((sizeof($args)) ?
implode(', ', $args) : '') . ')<br />';
2643 $output .= '</div>';
2648 * This function returns a regular expression pattern for commonly used expressions
2649 * Use with / as delimiter for email mode
2650 * mode can be: email|bbcode_htm
2652 function get_preg_expression($mode)
2657 return '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+';
2662 '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
2663 '#<!\-\- (l|m|w) \-\-><a href="(.*?)">.*?</a><!\-\- \1 \-\->#',
2664 '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
2665 '#<!\-\- .*? \-\->#s',
2675 * Truncates string while retaining special characters if going over the max length
2676 * The default max length is 60 at the moment
2678 function truncate_string($string, $max_length = 60)
2682 // split the multibyte characters first
2683 $string_ary = preg_split('/(&#[0-9]+;)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
);
2685 // Now go through the array and split the other characters
2686 foreach ($string_ary as $key => $value)
2688 if (strpos($value, '&#') === 0)
2694 // decode html entities and put them back later
2695 $_chars = str_split(html_entity_decode($value));
2696 $chars = array_merge($chars, array_map('htmlspecialchars', $_chars));
2699 // Now check the length ;)
2700 if (sizeof($chars) <= $max_length)
2705 // Cut off the last elements from the array
2706 return implode('', array_slice($chars, 0, $max_length));
2709 // Handler, header and footer
2712 * Error and message handler, call with trigger_error if reqd
2714 function msg_handler($errno, $msg_text, $errfile, $errline)
2716 global $cache, $db, $auth, $template, $config, $user;
2717 global $phpEx, $phpbb_root_path, $starttime, $msg_title, $msg_long_text;
2719 // Message handler is stripping text. In case we need it, we are possible to define long text...
2720 if (isset($msg_long_text) && $msg_long_text && !$msg_text)
2722 $msg_text = $msg_long_text;
2730 // Check the error reporting level and return if the error level does not match
2731 // Additionally do not display notices if we suppress them via @
2732 // If DEBUG_EXTRA is defined the default level is E_ALL
2733 if (($errno & ((defined('DEBUG_EXTRA') && error_reporting()) ? E_ALL
: error_reporting())) == 0)
2739 * @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
2741 if (defined('DEBUG'))
2743 if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
2745 // remove complete path to installation, with the risk of changing backslashes meant to be there
2746 $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);
2747 $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text);
2749 echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
2757 garbage_collection();
2759 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
2760 echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
2762 echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
2763 echo '<title>' . $msg_title . '</title>';
2764 echo '<link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />';
2766 echo '<body id="errorpage">';
2767 echo '<div id="wrap">';
2768 echo ' <div id="page-header">';
2769 echo ' <a href="' . $phpbb_root_path . '">Return to forum index</a>';
2771 echo ' <div id="page-body">';
2772 echo ' <div class="panel">';
2773 echo ' <span class="corners-top"><span></span></span>';
2774 echo ' <div id="content">';
2775 echo ' <h1>General Error</h1>';
2777 echo ' <h2>' . $msg_text . '</h2>';
2779 if (!empty($config['board_contact']))
2781 echo ' <p>Please notify the board administrator or webmaster : <a href="mailto:' . $config['board_contact'] . '">' . $config['board_contact'] . '</a></p>';
2785 echo ' <span class="corners-bottom"><span></span></span>';
2788 echo ' <div id="page-footer">';
2789 echo ' Powered by phpBB © ' . date('Y') . ' <a href="http://www.phpbb.com/">phpBB Group</a>';
2798 case E_USER_WARNING
:
2801 define('IN_ERROR_HANDLER', true);
2803 if (empty($user->data
))
2805 $user->session_begin();
2808 // We re-init the auth array to get correct results on login/logout
2809 $auth->acl($user->data
);
2811 if (empty($user->lang
))
2816 $msg_text = (!empty($user->lang
[$msg_text])) ?
$user->lang
[$msg_text] : $msg_text;
2817 $msg_title = (!isset($msg_title)) ?
$user->lang
['INFORMATION'] : ((!empty($user->lang
[$msg_title])) ?
$user->lang
[$msg_title] : $msg_title);
2819 if (!defined('HEADER_INC'))
2821 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
2823 adm_page_header($msg_title);
2827 page_header($msg_title);
2831 $template->set_filenames(array(
2832 'body' => 'message_body.html')
2835 $template->assign_vars(array(
2836 'MESSAGE_TITLE' => $msg_title,
2837 'MESSAGE_TEXT' => $msg_text,
2838 'S_USER_WARNING' => ($errno == E_USER_WARNING
) ?
true : false,
2839 'S_USER_NOTICE' => ($errno == E_USER_NOTICE
) ?
true : false)
2842 // We do not want the cron script to be called on error messages
2843 define('IN_CRON', true);
2845 if (defined('IN_ADMIN') && isset($user->data
['session_admin']) && $user->data
['session_admin'])
2860 * Generate page header
2862 function page_header($page_title = '', $display_online_list = true)
2864 global $db, $config, $template, $SID, $_SID, $user, $auth, $phpEx, $phpbb_root_path;
2866 if (defined('HEADER_INC'))
2871 define('HEADER_INC', true);
2874 if ($config['gzip_compress'])
2876 if (@extension_loaded
('zlib') && !headers_sent())
2878 ob_start('ob_gzhandler');
2882 // Generate logged in/logged out status
2883 if ($user->data
['user_id'] != ANONYMOUS
)
2885 $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout');
2886 $l_login_logout = sprintf($user->lang
['LOGOUT_USER'], $user->data
['username']);
2890 $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login');
2891 $l_login_logout = $user->lang
['LOGIN'];
2894 // Last visit date/time
2895 $s_last_visit = ($user->data
['user_id'] != ANONYMOUS
) ?
$user->format_date($user->data
['session_last_visit']) : '';
2897 // Get users online list ... if required
2898 $l_online_users = $online_userlist = $l_online_record = '';
2900 if ($config['load_online'] && $config['load_online_time'] && $display_online_list)
2902 $userlist_ary = $userlist_visible = array();
2903 $logged_visible_online = $logged_hidden_online = $guests_online = $prev_user_id = 0;
2904 $prev_session_ip = $reading_sql = '';
2906 if (!empty($_REQUEST['f']))
2908 $f = request_var('f', 0);
2910 // Do not change this (it is defined as _f_={forum_id}x within session.php)
2911 $reading_sql = " AND s.session_page LIKE '%\_f\_={$f}x%'";
2913 // Specify escape character for MSSQL
2914 if (SQL_LAYER
== 'mssql' || SQL_LAYER
== 'mssql_odbc')
2916 $reading_sql .= " ESCAPE '\\'";
2920 // Get number of online guests
2921 if (!$config['load_online_guests'])
2923 $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests
2924 FROM ' . SESSIONS_TABLE
. ' s
2925 WHERE s.session_user_id = ' . ANONYMOUS
. '
2926 AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) .
2928 $result = $db->sql_query($sql);
2929 $guests_online = (int) $db->sql_fetchfield('num_guests');
2930 $db->sql_freeresult($result);
2933 $sql = 'SELECT u.username, u.user_id, u.user_type, u.user_allow_viewonline, u.user_colour, s.session_ip, s.session_viewonline
2934 FROM ' . USERS_TABLE
. ' u, ' . SESSIONS_TABLE
. ' s
2935 WHERE s.session_time >= ' . (time() - (intval($config['load_online_time']) * 60)) .
2937 ((!$config['load_online_guests']) ?
' AND s.session_user_id <> ' . ANONYMOUS
: '') . '
2938 AND u.user_id = s.session_user_id
2939 ORDER BY u.username ASC, s.session_ip ASC';
2940 $result = $db->sql_query($sql);
2942 while ($row = $db->sql_fetchrow($result))
2944 // User is logged in and therefore not a guest
2945 if ($row['user_id'] != ANONYMOUS
)
2947 // Skip multiple sessions for one user
2948 if ($row['user_id'] != $prev_user_id)
2950 if ($row['user_colour'])
2952 $user_colour = ' style="color:#' . $row['user_colour'] . '"';
2953 $row['username'] = '<strong>' . $row['username'] . '</strong>';
2960 if ($row['user_allow_viewonline'] && $row['session_viewonline'])
2962 $user_online_link = $row['username'];
2963 $logged_visible_online++
;
2967 $user_online_link = '<em>' . $row['username'] . '</em>';
2968 $logged_hidden_online++
;
2971 if (($row['user_allow_viewonline'] && $row['session_viewonline']) ||
$auth->acl_get('u_viewonline'))
2973 if ($row['user_type'] <> USER_IGNORE
)
2975 $user_online_link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']) . '"' . $user_colour . '>' . $user_online_link . '</a>';
2979 $user_online_link = ($user_colour) ?
'<span' . $user_colour . '>' . $user_online_link . '</span>' : $user_online_link;
2982 $online_userlist .= ($online_userlist != '') ?
', ' . $user_online_link : $user_online_link;
2986 $prev_user_id = $row['user_id'];
2990 // Skip multiple sessions for one user
2991 if ($row['session_ip'] != $prev_session_ip)
2997 $prev_session_ip = $row['session_ip'];
2999 $db->sql_freeresult($result);
3001 if (!$online_userlist)
3003 $online_userlist = $user->lang
['NO_ONLINE_USERS'];
3006 if (empty($_REQUEST['f']))
3008 $online_userlist = $user->lang
['REGISTERED_USERS'] . ' ' . $online_userlist;
3012 $l_online = ($guests_online == 1) ?
$user->lang
['BROWSING_FORUM_GUEST'] : $user->lang
['BROWSING_FORUM_GUESTS'];
3013 $online_userlist = sprintf($l_online, $online_userlist, $guests_online);
3016 $total_online_users = $logged_visible_online +
$logged_hidden_online +
$guests_online;
3018 if ($total_online_users > $config['record_online_users'])
3020 set_config('record_online_users', $total_online_users, true);
3021 set_config('record_online_date', time(), true);
3024 // Build online listing
3025 $vars_online = array(
3026 'ONLINE' => array('total_online_users', 'l_t_user_s'),
3027 'REG' => array('logged_visible_online', 'l_r_user_s'),
3028 'HIDDEN' => array('logged_hidden_online', 'l_h_user_s'),
3029 'GUEST' => array('guests_online', 'l_g_user_s')
3032 foreach ($vars_online as $l_prefix => $var_ary)
3034 switch ($
{$var_ary[0]})
3037 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USERS_ZERO_TOTAL'];
3041 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USER_TOTAL'];
3045 $
{$var_ary[1]} = $user->lang
[$l_prefix . '_USERS_TOTAL'];
3049 unset($vars_online);
3051 $l_online_users = sprintf($l_t_user_s, $total_online_users);
3052 $l_online_users .= sprintf($l_r_user_s, $logged_visible_online);
3053 $l_online_users .= sprintf($l_h_user_s, $logged_hidden_online);
3054 $l_online_users .= sprintf($l_g_user_s, $guests_online);
3056 $l_online_record = sprintf($user->lang
['RECORD_ONLINE_USERS'], $config['record_online_users'], $user->format_date($config['record_online_date']));
3058 $l_online_time = ($config['load_online_time'] == 1) ?
'VIEW_ONLINE_TIME' : 'VIEW_ONLINE_TIMES';
3059 $l_online_time = sprintf($user->lang
[$l_online_time], $config['load_online_time']);
3063 $l_online_time = '';
3066 $l_privmsgs_text = $l_privmsgs_text_unread = '';
3067 $s_privmsg_new = false;
3069 // Obtain number of new private messages if user is logged in
3070 if (isset($user->data
['is_registered']) && $user->data
['is_registered'])
3072 if ($user->data
['user_new_privmsg'])
3074 $l_message_new = ($user->data
['user_new_privmsg'] == 1) ?
$user->lang
['NEW_PM'] : $user->lang
['NEW_PMS'];
3075 $l_privmsgs_text = sprintf($l_message_new, $user->data
['user_new_privmsg']);
3077 if (!$user->data
['user_last_privmsg'] ||
$user->data
['user_last_privmsg'] > $user->data
['session_last_visit'])
3079 $sql = 'UPDATE ' . USERS_TABLE
. '
3080 SET user_last_privmsg = ' . $user->data
['session_last_visit'] . '
3081 WHERE user_id = ' . $user->data
['user_id'];
3082 $db->sql_query($sql);
3084 $s_privmsg_new = true;
3088 $s_privmsg_new = false;
3093 $l_privmsgs_text = $user->lang
['NO_NEW_PM'];
3094 $s_privmsg_new = false;
3097 $l_privmsgs_text_unread = '';
3099 if ($user->data
['user_unread_privmsg'] && $user->data
['user_unread_privmsg'] != $user->data
['user_new_privmsg'])
3101 $l_message_unread = ($user->data
['user_unread_privmsg'] == 1) ?
$user->lang
['UNREAD_PM'] : $user->lang
['UNREAD_PMS'];
3102 $l_privmsgs_text_unread = sprintf($l_message_unread, $user->data
['user_unread_privmsg']);
3107 $tz = ($user->data
['user_id'] != ANONYMOUS
) ?
strval(doubleval($user->data
['user_timezone'])) : strval(doubleval($config['board_timezone']));
3109 // The following assigns all _common_ variables that may be used at any point in a template.
3110 $template->assign_vars(array(
3111 'SITENAME' => $config['sitename'],
3112 'SITE_DESCRIPTION' => $config['site_desc'],
3113 'PAGE_TITLE' => $page_title,
3114 'SCRIPT_NAME' => str_replace('.' . $phpEx, '', $user->page
['page_name']),
3115 'LAST_VISIT_DATE' => sprintf($user->lang
['YOU_LAST_VISIT'], $s_last_visit),
3116 'CURRENT_TIME' => sprintf($user->lang
['CURRENT_TIME'], $user->format_date(time(), false, true)),
3117 'TOTAL_USERS_ONLINE' => $l_online_users,
3118 'LOGGED_IN_USER_LIST' => $online_userlist,
3119 'RECORD_USERS' => $l_online_record,
3120 'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text,
3121 'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread,
3125 'SESSION_ID' => $user->session_id
,
3126 'ROOT_PATH' => $phpbb_root_path,
3128 'L_LOGIN_LOGOUT' => $l_login_logout,
3129 'L_INDEX' => $user->lang
['FORUM_INDEX'],
3130 'L_ONLINE_EXPLAIN' => $l_online_time,
3132 'U_PRIVATEMSGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
3133 'U_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
3134 'UA_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox', false),
3135 'U_POPUP_PM' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup'),
3136 'UA_POPUP_PM' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup', false),
3137 'U_MEMBERLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
3138 'U_MEMBERSLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"),
3139 'U_VIEWONLINE' => append_sid("{$phpbb_root_path}viewonline.$phpEx"),
3140 'U_LOGIN_LOGOUT' => $u_login_logout,
3141 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"),
3142 'U_SEARCH' => append_sid("{$phpbb_root_path}search.$phpEx"),
3143 'U_REGISTER' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
3144 'U_PROFILE' => append_sid("{$phpbb_root_path}ucp.$phpEx"),
3145 'U_MODCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id
),
3146 'U_FAQ' => append_sid("{$phpbb_root_path}faq.$phpEx"),
3147 'U_SEARCH_SELF' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'),
3148 'U_SEARCH_NEW' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'),
3149 'U_SEARCH_UNANSWERED' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
3150 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
3151 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
3152 'U_TEAM' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'),
3153 'U_RESTORE_PERMISSIONS' => ($user->data
['user_perm_from'] && $auth->acl_get('a_switchperm')) ?
append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
3155 'S_USER_LOGGED_IN' => ($user->data
['user_id'] != ANONYMOUS
) ?
true : false,
3156 'S_BOARD_DISABLED' => ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_')) ?
true : false,
3157 'S_REGISTERED_USER' => $user->data
['is_registered'],
3158 'S_IS_BOT' => $user->data
['is_bot'],
3159 'S_USER_PM_POPUP' => $user->optionget('popuppm'),
3160 'S_USER_LANG' => $user->data
['user_lang'],
3161 'S_USER_BROWSER' => (isset($user->data
['session_browser'])) ?
$user->data
['session_browser'] : $user->lang
['UNKNOWN_BROWSER'],
3162 'S_USERNAME' => $user->data
['username'],
3163 'S_CONTENT_DIRECTION' => $user->lang
['DIRECTION'],
3164 'S_CONTENT_ENCODING' => 'UTF-8',
3165 'S_CONTENT_DIR_LEFT' => $user->lang
['LEFT'],
3166 'S_CONTENT_DIR_RIGHT' => $user->lang
['RIGHT'],
3167 '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], ''),
3168 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ?
1 : 0,
3169 'S_DISPLAY_SEARCH' => (!$config['load_search']) ?
0 : (isset($auth) ?
($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1),
3170 'S_DISPLAY_PM' => ($config['allow_privmsg'] && $user->data
['is_registered']) ?
1 : 0,
3171 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ?
$auth->acl_get('u_viewprofile') : 0,
3172 'S_NEW_PM' => ($s_privmsg_new) ?
1 : 0,
3174 'T_THEME_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['theme_path'] . '/theme',
3175 'T_TEMPLATE_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['template_path'] . '/template',
3176 'T_IMAGESET_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['imageset_path'] . '/imageset',
3177 'T_IMAGESET_LANG_PATH' => "{$phpbb_root_path}styles/" . $user->theme
['imageset_path'] . '/imageset/' . $user->data
['user_lang'],
3178 'T_IMAGES_PATH' => "{$phpbb_root_path}images/",
3179 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/",
3180 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/",
3181 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
3182 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/",
3183 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/",
3184 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/",
3185 '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'] . '&lang=' . $user->data
['user_lang'],
3186 'T_STYLESHEET_NAME' => $user->theme
['theme_name'],
3187 'T_THEME_DATA' => (!$user->theme
['theme_storedb']) ?
'' : $user->theme
['theme_data'],
3189 'SITE_LOGO_IMG' => $user->img('site_logo'))
3192 if ($config['send_encoding'])
3194 header('Content-type: text/html; charset=UTF-8');
3196 header('Cache-Control: private, no-cache="set-cookie"');
3197 header('Expires: 0');
3198 header('Pragma: no-cache');
3204 * Generate page footer
3206 function page_footer()
3208 global $db, $config, $template, $user, $auth, $cache, $messenger, $starttime, $phpbb_root_path, $phpEx;
3210 // Output page creation time
3211 if (defined('DEBUG'))
3213 $mtime = explode(' ', microtime());
3214 $totaltime = $mtime[0] +
$mtime[1] - $starttime;
3216 if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report'))
3218 $db->sql_report('display');
3221 $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress']) ?
'On' : 'Off') . (($user->load
) ?
' | Load : ' . $user->load
: ''), $totaltime);
3223 if ($auth->acl_get('a_') && defined('DEBUG_EXTRA'))
3225 if (function_exists('memory_get_usage'))
3227 if ($memory_usage = memory_get_usage())
3229 global $base_memory_usage;
3230 $memory_usage -= $base_memory_usage;
3231 $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']);
3233 $debug_output .= ' | Memory Usage: ' . $memory_usage;
3237 $debug_output .= ' | <a href="' . build_url() . '&explain=1">Explain</a>';
3241 $template->assign_vars(array(
3242 'DEBUG_OUTPUT' => (defined('DEBUG')) ?
$debug_output : '',
3244 'U_ACP' => ($auth->acl_get('a_') && $user->data
['is_registered']) ?
"{$phpbb_root_path}adm/index.$phpEx?sid=" . $user->session_id
: '')
3247 // Call cron-type script
3248 if (!defined('IN_CRON'))
3252 if (time() - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx))
3254 // Process email queue
3255 $cron_type = 'queue';
3257 else if (method_exists($cache, 'tidy') && time() - $config['cache_gc'] > $config['cache_last_gc'])
3260 $cron_type = 'tidy_cache';
3262 else if (time() - $config['warnings_gc'] > $config['warnings_last_gc'])
3264 $cron_type = 'tidy_warnings';
3266 else if (time() - $config['database_gc'] > $config['database_last_gc'])
3268 // Tidy the database
3269 $cron_type = 'tidy_database';
3271 else if (time() - $config['search_gc'] > $config['search_last_gc'])
3274 $cron_type = 'tidy_search';
3276 else if (time() - $config['session_gc'] > $config['session_last_gc'])
3278 $cron_type = 'tidy_sessions';
3283 $template->assign_var('RUN_CRON_TASK', '<img src="' . $phpbb_root_path . 'cron.' . $phpEx . '?cron_type=' . $cron_type . '" width="1" height="1" alt="cron" />');
3287 $template->display('body');
3289 garbage_collection();
3295 * Closing the cache object and the database
3296 * Cool function name, eh? We might want to add operations to it later
3298 function garbage_collection()
3302 // Unload cache, must be done before the DB connection if closed
3308 // Close our DB connection.
3322 function bitfield($bitfield = '')
3324 $this->data
= base64_decode($bitfield);
3331 // Get the ($n / 8)th char
3334 if (!isset($this->data
[$byte]))
3336 // Of course, if it doesn't exist then the result if FALSE
3340 $c = $this->data
[$byte];
3342 // Lookup the ($n % 8)th bit of the byte
3343 $bit = 7 - ($n & 7);
3344 return (bool) (ord($c) & (1 << $bit));
3350 $bit = 7 - ($n & 7);
3352 if (isset($this->data
[$byte]))
3354 $this->data
[$byte] = $this->data
[$byte] |
chr(1 << $bit);
3358 if ($byte - strlen($this->data
) > 0)
3360 $this->data
.= str_repeat("\0", $byte - strlen($this->data
));
3362 $this->data
.= chr(1 << $bit);
3370 if (!isset($this->data
[$byte]))
3375 $bit = 7 - ($n & 7);
3376 $this->data
[$byte] = $this->data
[$byte] &~
chr(1 << $bit);
3384 function get_base64()
3386 return base64_encode($this->data
);
3392 $len = strlen($this->data
);
3394 for ($i = 0; $i < $len; ++
$i)
3396 $bin .= str_pad(decbin(ord($this->data
[$i])), 8, '0', STR_PAD_LEFT
);
3402 function get_all_set()
3404 return array_keys(array_filter(str_split($this->get_bin())));
3407 function merge($bitfield)
3409 $this->data
= $this->data |
$bitfield->get_blob();