6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
14 if (!defined('IN_PHPBB'))
19 // Common global functions
22 * Wrapper function of phpbb_request::variable which exists for backwards compatability.
23 * See {@link phpbb_request::variable phpbb_request::variable} for documentation of this function's use.
25 * @param string|array $var_name The form variable's name from which data shall be retrieved.
26 * If the value is an array this may be an array of indizes which will give
27 * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
28 * then specifying array("var", 1) as the name will return "a".
29 * @param mixed $default A default value that is returned if the variable was not set.
30 * This function will always return a value of the same type as the default.
31 * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
32 * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
33 * @param bool $cookie This param is mapped to phpbb_request::COOKIE as the last param for phpbb_request::variable for backwards compatability reasons.
35 * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
36 * the same as that of $default. If the variable is not set $default is returned.
38 function request_var($var_name, $default, $multibyte = false, $cookie = false)
40 return phpbb_request
::variable($var_name, $default, $multibyte, ($cookie) ? phpbb_request
::COOKIE
: phpbb_request
::REQUEST
);
45 * Creates missing config entry if update did not succeed and phpbb::$config for this entry empty.
47 * @param string $config_name The configuration keys name
48 * @param string $config_value The configuration value
49 * @param bool $is_dynamic True if the configuration entry is not cached
51 function set_config($config_name, $config_value, $is_dynamic = false)
53 $sql = 'UPDATE ' . CONFIG_TABLE
. "
54 SET config_value = '" . phpbb
::$db->sql_escape($config_value) . "'
55 WHERE config_name = '" . phpbb
::$db->sql_escape($config_name) . "'";
56 phpbb
::$db->sql_query($sql);
58 if (!phpbb
::$db->sql_affectedrows() && !isset(phpbb
::$config[$config_name]))
60 $sql = 'INSERT INTO ' . CONFIG_TABLE
. ' ' . phpbb
::$db->sql_build_array('INSERT', array(
61 'config_name' => (string) $config_name,
62 'config_value' => (string) $config_value,
63 'is_dynamic' => (int) $is_dynamic,
65 phpbb
::$db->sql_query($sql);
68 phpbb
::$config[$config_name] = $config_value;
72 phpbb
::$acm->destroy('#config');
77 * Return formatted string for filesizes
79 function get_formatted_filesize($bytes, $add_size_lang = true)
81 if ($bytes >= pow(2, 20))
83 return ($add_size_lang) ?
round($bytes / 1024 / 1024, 2) . ' ' . phpbb
::$user->lang
['MIB'] : round($bytes / 1024 / 1024, 2);
86 if ($bytes >= pow(2, 10))
88 return ($add_size_lang) ?
round($bytes / 1024, 2) . ' ' . phpbb
::$user->lang
['KIB'] : round($bytes / 1024, 2);
91 return ($add_size_lang) ?
($bytes) . ' ' . phpbb
::$user->lang
['BYTES'] : ($bytes);
95 * Determine whether we are approaching the maximum execution time. Should be called once
96 * at the beginning of the script in which it's used.
97 * @return bool Either true if the maximum execution time is nearly reached, or false
98 * if some time is still left.
100 function still_on_time($extra_time = 15)
102 static $max_execution_time, $start_time;
104 $time = explode(' ', microtime());
105 $current_time = $time[0] +
$time[1];
107 if (empty($max_execution_time))
109 $max_execution_time = (function_exists('ini_get')) ?
(int) @ini_get
('max_execution_time') : (int) @get_cfg_var
('max_execution_time');
111 // If zero, then set to something higher to not let the user catch the ten seconds barrier.
112 if ($max_execution_time === 0)
114 $max_execution_time = 50 +
$extra_time;
117 $max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50);
119 // For debugging purposes
120 // $max_execution_time = 10;
123 $start_time = (empty($starttime)) ?
$current_time : $starttime;
126 return (ceil($current_time - $start_time) < $max_execution_time) ?
true : false;
130 * Global function for chmodding directories and files for internal use
131 * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
132 * The function determines owner and group from common.php file and sets the same to the provided file. Permissions are mapped to the group, user always has rw(x) permission.
133 * The function uses bit fields to build the permissions.
134 * The function sets the appropiate execute bit on directories.
136 * Supported constants representing bit fields are:
138 * phpbb::CHMOD_ALL - all permissions (7)
139 * phpbb::CHMOD_READ - read permission (4)
140 * phpbb::CHMOD_WRITE - write permission (2)
141 * phpbb::CHMOD_EXECUTE - execute permission (1)
143 * NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
145 * @param $filename The file/directory to be chmodded
146 * @param $perms Permissions to set
147 * @return true on success, otherwise false
149 * @author faw, phpBB Group
151 function phpbb_chmod($filename, $perms = phpbb
::CHMOD_READ
)
153 // Return if the file no longer exists.
154 if (!file_exists($filename))
159 if (!function_exists('fileowner') ||
!function_exists('filegroup'))
161 $file_uid = $file_gid = false;
162 $common_php_owner = $common_php_group = false;
166 // Determine owner/group of common.php file and the filename we want to change here
167 $common_php_owner = fileowner(PHPBB_ROOT_PATH
. 'common.' . PHP_EXT
);
168 $common_php_group = filegroup(PHPBB_ROOT_PATH
. 'common.' . PHP_EXT
);
170 $file_uid = fileowner($filename);
171 $file_gid = filegroup($filename);
173 // Try to set the owner to the same common.php has
174 if ($common_php_owner !== $file_uid && $common_php_owner !== false && $file_uid !== false)
176 // Will most likely not work
177 if (@chown
($filename, $common_php_owner));
180 $file_uid = fileowner($filename);
184 // Try to set the group to the same common.php has
185 if ($common_php_group !== $file_gid && $common_php_group !== false && $file_gid !== false)
187 if (@chgrp
($filename, $common_php_group));
190 $file_gid = filegroup($filename);
195 // And the owner and the groups PHP is running under.
196 $php_uid = (function_exists('posix_getuid')) ? @posix_getuid
() : false;
197 $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups
() : false;
200 if ($file_uid === false ||
$file_gid === false ||
$php_uid === false ||
$php_gids === false)
204 else if ($file_uid == $php_uid /* && $common_php_owner !== false && $common_php_owner === $file_uid*/)
208 else if (in_array($file_gid, $php_gids))
217 // Owner always has read/write permission
218 $owner = phpbb
::CHMOD_READ | phpbb
::CHMOD_WRITE
;
219 if (is_dir($filename))
221 $owner |
= phpbb
::CHMOD_EXECUTE
;
223 // Only add execute bit to the permission if the dir needs to be readable
224 if ($perms & phpbb
::CHMOD_READ
)
226 $perms |
= phpbb
::CHMOD_EXECUTE
;
234 /* ATTENTION: if php is owner or NULL we set it to group here. This is the most failsafe combination for the vast majority of server setups.
236 $result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
240 if (!is_null($php) || (is_readable($filename) && is_writable($filename)))
247 $result = @chmod
($filename, ($owner << 6) +
($perms << 3) +
(0 << 0));
251 if (!is_null($php) ||
((!($perms & phpbb
::CHMOD_READ
) ||
is_readable($filename)) && (!($perms & phpbb
::CHMOD_WRITE
) ||
is_writable($filename))))
257 $result = @chmod
($filename, ($owner << 6) +
($perms << 3) +
($perms << 0));
261 if (!is_null($php) ||
((!($perms & phpbb
::CHMOD_READ
) ||
is_readable($filename)) && (!($perms & phpbb
::CHMOD_WRITE
) ||
is_writable($filename))))
275 * Add a secret hash for use in links/GET requests
276 * @param string $link_name The name of the link; has to match the name used in check_link_hash, otherwise no restrictions apply
277 * @return string the hash
280 @todo should use our hashing instead of a "custom" one
282 function generate_link_hash($link_name)
284 if (!isset(phpbb
::$user->data
["hash_$link_name"]))
286 phpbb
::$user->data
["hash_$link_name"] = substr(sha1(phpbb
::$user->data
['user_form_salt'] . $link_name), 0, 8);
289 return phpbb
::$user->data
["hash_$link_name"];
294 * checks a link hash - for GET requests
295 * @param string $token the submitted token
296 * @param string $link_name The name of the link
297 * @return boolean true if all is fine
300 function check_link_hash($token, $link_name)
302 return $token === generate_link_hash($link_name);
305 // functions used for building option fields
308 * Pick a language, any language ...
310 function language_select($default = '')
312 $sql = 'SELECT lang_iso, lang_local_name
313 FROM ' . LANG_TABLE
. '
314 ORDER BY lang_english_name';
315 $result = phpbb
::$db->sql_query($sql);
318 while ($row = phpbb
::$db->sql_fetchrow($result))
320 $selected = ($row['lang_iso'] == $default) ?
' selected="selected"' : '';
321 $lang_options .= '<option value="' . $row['lang_iso'] . '"' . $selected . '>' . $row['lang_local_name'] . '</option>';
323 phpbb
::$db->sql_freeresult($result);
325 return $lang_options;
329 * Pick a template/theme combo,
331 function style_select($default = '', $all = false)
333 $sql_where = (!$all) ?
'WHERE style_active = 1 ' : '';
334 $sql = 'SELECT style_id, style_name
335 FROM ' . STYLES_TABLE
. "
337 ORDER BY style_name";
338 $result = phpbb
::$db->sql_query($sql);
341 while ($row = phpbb
::$db->sql_fetchrow($result))
343 $selected = ($row['style_id'] == $default) ?
' selected="selected"' : '';
344 $style_options .= '<option value="' . $row['style_id'] . '"' . $selected . '>' . $row['style_name'] . '</option>';
346 phpbb
::$db->sql_freeresult($result);
348 return $style_options;
354 function tz_select($default = '', $truncate = false)
357 foreach (phpbb
::$user->lang
['tz_zones'] as $offset => $zone)
361 $zone_trunc = truncate_string($zone, 50, 255, false, '...');
368 if (is_numeric($offset))
370 $selected = ($offset == $default) ?
' selected="selected"' : '';
371 $tz_select .= '<option title="'.$zone.'" value="' . $offset . '"' . $selected . '>' . $zone_trunc . '</option>';
378 // Functions handling topic/post tracking/marking
381 * Marks a topic/forum as read
382 * Marks a topic as posted to
384 * @param int $user_id can only be used with $mode == 'post'
386 function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
390 if ($forum_id === false ||
!sizeof($forum_id))
392 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
394 // Mark all forums read (index page)
395 phpbb
::$db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE
. ' WHERE user_id = ' . phpbb
::$user->data
['user_id']);
396 phpbb
::$db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE
. ' WHERE user_id = ' . phpbb
::$user->data
['user_id']);
397 phpbb
::$db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . ' WHERE user_id = ' . phpbb
::$user->data
['user_id']);
399 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
401 $tracking_topics = phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
);
402 $tracking_topics = ($tracking_topics) ?
tracking_unserialize($tracking_topics) : array();
404 unset($tracking_topics['tf']);
405 unset($tracking_topics['t']);
406 unset($tracking_topics['f']);
407 $tracking_topics['l'] = base_convert(time() - phpbb
::$config['board_startdate'], 10, 36);
409 phpbb
::$user->set_cookie('track', tracking_serialize($tracking_topics), time() +
31536000);
410 phpbb_request
::overwrite(phpbb
::$config['cookie_name'] . '_track', tracking_serialize($tracking_topics), phpbb_request
::COOKIE
);
412 unset($tracking_topics);
414 if (phpbb
::$user->data
['is_registered'])
416 phpbb
::$db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . time() . ' WHERE user_id = ' . phpbb
::$user->data
['user_id']);
423 else if ($mode == 'topics')
425 // Mark all topics in forums read
426 if (!is_array($forum_id))
428 $forum_id = array($forum_id);
431 // Add 0 to forums array to mark global announcements correctly
434 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
436 $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE
. '
437 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
438 AND ' . phpbb
::$db->sql_in_set('forum_id', $forum_id);
439 phpbb
::$db->sql_query($sql);
441 $sql = 'SELECT forum_id
442 FROM ' . FORUMS_TRACK_TABLE
. '
443 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
444 AND ' . phpbb
::$db->sql_in_set('forum_id', $forum_id);
445 $result = phpbb
::$db->sql_query($sql);
447 $sql_update = array();
448 while ($row = phpbb
::$db->sql_fetchrow($result))
450 $sql_update[] = $row['forum_id'];
452 phpbb
::$db->sql_freeresult($result);
454 if (sizeof($sql_update))
456 $sql = 'UPDATE ' . FORUMS_TRACK_TABLE
. '
457 SET mark_time = ' . time() . '
458 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
459 AND ' . phpbb
::$db->sql_in_set('forum_id', $sql_update);
460 phpbb
::$db->sql_query($sql);
463 if ($sql_insert = array_diff($forum_id, $sql_update))
466 foreach ($sql_insert as $f_id)
469 'user_id' => (int) phpbb
::$user->data
['user_id'],
470 'forum_id' => (int) $f_id,
471 'mark_time' => time()
475 phpbb
::$db->sql_multi_insert(FORUMS_TRACK_TABLE
, $sql_ary);
478 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
480 $tracking = phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
);
481 $tracking = ($tracking) ?
tracking_unserialize($tracking) : array();
483 foreach ($forum_id as $f_id)
485 $topic_ids36 = (isset($tracking['tf'][$f_id])) ?
$tracking['tf'][$f_id] : array();
487 if (isset($tracking['tf'][$f_id]))
489 unset($tracking['tf'][$f_id]);
492 foreach ($topic_ids36 as $topic_id36)
494 unset($tracking['t'][$topic_id36]);
497 if (isset($tracking['f'][$f_id]))
499 unset($tracking['f'][$f_id]);
502 $tracking['f'][$f_id] = base_convert(time() - phpbb
::$config['board_startdate'], 10, 36);
505 if (isset($tracking['tf']) && empty($tracking['tf']))
507 unset($tracking['tf']);
510 phpbb
::$user->set_cookie('track', tracking_serialize($tracking), time() +
31536000);
511 phpbb_request
::overwrite(phpbb
::$config['cookie_name'] . '_track', tracking_serialize($tracking), phpbb_request
::COOKIE
);
518 else if ($mode == 'topic')
520 if ($topic_id === false ||
$forum_id === false)
525 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
527 $sql = 'UPDATE ' . TOPICS_TRACK_TABLE
. '
528 SET mark_time = ' . (($post_time) ?
$post_time : time()) . '
529 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
530 AND topic_id = ' . $topic_id;
531 phpbb
::$db->sql_query($sql);
534 if (!phpbb
::$db->sql_affectedrows())
536 phpbb
::$db->sql_return_on_error(true);
539 'user_id' => (int) phpbb
::$user->data
['user_id'],
540 'topic_id' => (int) $topic_id,
541 'forum_id' => (int) $forum_id,
542 'mark_time' => ($post_time) ?
(int) $post_time : time(),
545 phpbb
::$db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE
. ' ' . phpbb
::$db->sql_build_array('INSERT', $sql_ary));
547 phpbb
::$db->sql_return_on_error(false);
550 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
552 $tracking = phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
);
553 $tracking = ($tracking) ?
tracking_unserialize($tracking) : array();
555 $topic_id36 = base_convert($topic_id, 10, 36);
557 if (!isset($tracking['t'][$topic_id36]))
559 $tracking['tf'][$forum_id][$topic_id36] = true;
562 $post_time = ($post_time) ?
$post_time : time();
563 $tracking['t'][$topic_id36] = base_convert($post_time - phpbb
::$config['board_startdate'], 10, 36);
565 // If the cookie grows larger than 10000 characters we will remove the smallest value
566 // This can result in old topics being unread - but most of the time it should be accurate...
567 if (strlen(phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
)) > 10000)
569 //echo 'Cookie grown too large' . print_r($tracking, true);
571 // We get the ten most minimum stored time offsets and its associated topic ids
572 $time_keys = array();
573 for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++
)
575 $min_value = min($tracking['t']);
576 $m_tkey = array_search($min_value, $tracking['t']);
577 unset($tracking['t'][$m_tkey]);
579 $time_keys[$m_tkey] = $min_value;
582 // Now remove the topic ids from the array...
583 foreach ($tracking['tf'] as $f_id => $topic_id_ary)
585 foreach ($time_keys as $m_tkey => $min_value)
587 if (isset($topic_id_ary[$m_tkey]))
589 $tracking['f'][$f_id] = $min_value;
590 unset($tracking['tf'][$f_id][$m_tkey]);
595 if (phpbb
::$user->data
['is_registered'])
597 phpbb
::$user->data
['user_lastmark'] = intval(base_convert(max($time_keys) + phpbb
::$config['board_startdate'], 36, 10));
598 phpbb
::$db->sql_query('UPDATE ' . USERS_TABLE
. ' SET user_lastmark = ' . phpbb
::$user->data
['user_lastmark'] . ' WHERE user_id = ' . phpbb
::$user->data
['user_id']);
602 $tracking['l'] = max($time_keys);
606 phpbb
::$user->set_cookie('track', tracking_serialize($tracking), time() +
31536000);
607 phpbb_request
::overwrite(phpbb
::$config['cookie_name'] . '_track', tracking_serialize($tracking));
612 else if ($mode == 'post')
614 if ($topic_id === false)
619 $use_user_id = (!$user_id) ? phpbb
::$user->data
['user_id'] : $user_id;
621 if (phpbb
::$config['load_db_track'] && $use_user_id != ANONYMOUS
)
623 phpbb
::$db->sql_return_on_error(true);
626 'user_id' => (int) $use_user_id,
627 'topic_id' => (int) $topic_id,
631 phpbb
::$db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE
. ' ' . phpbb
::$db->sql_build_array('INSERT', $sql_ary));
633 phpbb
::$db->sql_return_on_error(false);
641 * Get topic tracking info by using already fetched info
643 function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
645 $last_read = array();
647 if (!is_array($topic_ids))
649 $topic_ids = array($topic_ids);
652 foreach ($topic_ids as $topic_id)
654 if (!empty($rowset[$topic_id]['mark_time']))
656 $last_read[$topic_id] = $rowset[$topic_id]['mark_time'];
660 $topic_ids = array_diff($topic_ids, array_keys($last_read));
662 if (sizeof($topic_ids))
664 $mark_time = array();
666 // Get global announcement info
667 if ($global_announce_list && sizeof($global_announce_list))
669 if (!isset($forum_mark_time[0]))
671 $sql = 'SELECT mark_time
672 FROM ' . FORUMS_TRACK_TABLE
. '
673 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
675 $result = phpbb
::$db->sql_query($sql);
676 $row = phpbb
::$db->sql_fetchrow($result);
677 phpbb
::$db->sql_freeresult($result);
681 $mark_time[0] = $row['mark_time'];
686 if ($forum_mark_time[0] !== false)
688 $mark_time[0] = $forum_mark_time[0];
693 if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false)
695 $mark_time[$forum_id] = $forum_mark_time[$forum_id];
698 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : phpbb
::$user->data
['user_lastmark'];
700 foreach ($topic_ids as $topic_id)
702 if ($global_announce_list && isset($global_announce_list[$topic_id]))
704 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
708 $last_read[$topic_id] = $user_lastmark;
717 * Get topic tracking info from db (for cookie based tracking only this function is used)
719 function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false)
721 $last_read = array();
723 if (!is_array($topic_ids))
725 $topic_ids = array($topic_ids);
728 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
730 $sql = 'SELECT topic_id, mark_time
731 FROM ' . TOPICS_TRACK_TABLE
. '
732 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
733 AND ' . phpbb
::$db->sql_in_set('topic_id', $topic_ids);
734 $result = phpbb
::$db->sql_query($sql);
736 while ($row = phpbb
::$db->sql_fetchrow($result))
738 $last_read[$row['topic_id']] = $row['mark_time'];
740 phpbb
::$db->sql_freeresult($result);
742 $topic_ids = array_diff($topic_ids, array_keys($last_read));
744 if (sizeof($topic_ids))
746 $sql = 'SELECT forum_id, mark_time
747 FROM ' . FORUMS_TRACK_TABLE
. '
748 WHERE user_id = ' . phpbb
::$user->data
['user_id'] . '
750 (($global_announce_list && sizeof($global_announce_list)) ?
"IN (0, $forum_id)" : "= $forum_id");
751 $result = phpbb
::$db->sql_query($sql);
753 $mark_time = array();
754 while ($row = phpbb
::$db->sql_fetchrow($result))
756 $mark_time[$row['forum_id']] = $row['mark_time'];
758 phpbb
::$db->sql_freeresult($result);
760 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : phpbb
::$user->data
['user_lastmark'];
762 foreach ($topic_ids as $topic_id)
764 if ($global_announce_list && isset($global_announce_list[$topic_id]))
766 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
770 $last_read[$topic_id] = $user_lastmark;
775 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
777 global $tracking_topics;
779 if (!isset($tracking_topics) ||
!sizeof($tracking_topics))
781 $tracking_topics = phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
);
782 $tracking_topics = ($tracking_topics) ?
tracking_unserialize($tracking_topics) : array();
785 if (!phpbb
::$user->data
['is_registered'])
787 $user_lastmark = (isset($tracking_topics['l'])) ?
base_convert($tracking_topics['l'], 36, 10) + phpbb
::$config['board_startdate'] : 0;
791 $user_lastmark = phpbb
::$user->data
['user_lastmark'];
794 foreach ($topic_ids as $topic_id)
796 $topic_id36 = base_convert($topic_id, 10, 36);
798 if (isset($tracking_topics['t'][$topic_id36]))
800 $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + phpbb
::$config['board_startdate'];
804 $topic_ids = array_diff($topic_ids, array_keys($last_read));
806 if (sizeof($topic_ids))
808 $mark_time = array();
809 if ($global_announce_list && sizeof($global_announce_list))
811 if (isset($tracking_topics['f'][0]))
813 $mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) + phpbb
::$config['board_startdate'];
817 if (isset($tracking_topics['f'][$forum_id]))
819 $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) + phpbb
::$config['board_startdate'];
822 $user_lastmark = (isset($mark_time[$forum_id])) ?
$mark_time[$forum_id] : $user_lastmark;
824 foreach ($topic_ids as $topic_id)
826 if ($global_announce_list && isset($global_announce_list[$topic_id]))
828 $last_read[$topic_id] = (isset($mark_time[0])) ?
$mark_time[0] : $user_lastmark;
832 $last_read[$topic_id] = $user_lastmark;
842 * Check for read forums and update topic tracking info accordingly
844 * @param int $forum_id the forum id to check
845 * @param int $forum_last_post_time the forums last post time
846 * @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled
847 * @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time
849 * @return true if complete forum got marked read, else false.
851 function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
853 global $tracking_topics;
855 // Determine the users last forum mark time if not given.
856 if ($mark_time_forum === false)
858 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
860 $mark_time_forum = (!empty($f_mark_time)) ?
$f_mark_time : phpbb
::$user->data
['user_lastmark'];
862 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
864 $tracking_topics = phpbb_request
::variable(phpbb
::$config['cookie_name'] . '_track', '', false, phpbb_request
::COOKIE
);
865 $tracking_topics = ($tracking_topics) ?
tracking_unserialize($tracking_topics) : array();
867 if (!phpbb
::$user->data
['is_registered'])
869 phpbb
::$user->data
['user_lastmark'] = (isset($tracking_topics['l'])) ?
(int) (base_convert($tracking_topics['l'], 36, 10) + phpbb
::$config['board_startdate']) : 0;
872 $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ?
(int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + phpbb
::$config['board_startdate']) : phpbb
::$user->data
['user_lastmark'];
876 // Check the forum for any left unread topics.
877 // If there are none, we mark the forum as read.
878 if (phpbb
::$config['load_db_lastread'] && phpbb
::$user->data
['is_registered'])
880 if ($mark_time_forum >= $forum_last_post_time)
882 // We do not need to mark read, this happened before. Therefore setting this to true
887 $sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE
. ' t
888 LEFT JOIN ' . TOPICS_TRACK_TABLE
. ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . phpbb
::$user->data
['user_id'] . ')
889 WHERE t.forum_id = ' . $forum_id . '
890 AND t.topic_last_post_time > ' . $mark_time_forum . '
891 AND t.topic_moved_id = 0
892 AND (tt.topic_id IS NULL OR tt.mark_time < t.topic_last_post_time)
893 GROUP BY t.forum_id';
894 $result = phpbb
::$db->sql_query_limit($sql, 1);
895 $row = phpbb
::$db->sql_fetchrow($result);
896 phpbb
::$db->sql_freeresult($result);
899 else if (phpbb
::$config['load_anon_lastread'] || phpbb
::$user->data
['is_registered'])
901 // Get information from cookie
904 if (!isset($tracking_topics['tf'][$forum_id]))
906 // We do not need to mark read, this happened before. Therefore setting this to true
911 $sql = 'SELECT topic_id
912 FROM ' . TOPICS_TABLE
. '
913 WHERE forum_id = ' . $forum_id . '
914 AND topic_last_post_time > ' . $mark_time_forum . '
915 AND topic_moved_id = 0';
916 $result = phpbb
::$db->sql_query($sql);
918 $check_forum = $tracking_topics['tf'][$forum_id];
921 while ($row = phpbb
::$db->sql_fetchrow($result))
923 if (!isset($check_forum[base_convert($row['topic_id'], 10, 36)]))
929 phpbb
::$db->sql_freeresult($result);
941 markread('topics', $forum_id);
949 * Transform an array into a serialized format
951 function tracking_serialize($input)
954 foreach ($input as $key => $value)
956 if (is_array($value))
958 $out .= $key . ':(' . tracking_serialize($value) . ');';
962 $out .= $key . ':' . $value . ';';
969 * Transform a serialized array into an actual array
971 function tracking_unserialize($string, $max_depth = 3)
973 $n = strlen($string);
976 die('Invalid data supplied');
978 $data = $stack = array();
982 for ($i = 0; $i < $n; ++
$i)
995 $level = array_pop($stack);
1004 switch ($string[$i])
1007 if (sizeof($stack) >= $max_depth)
1009 die('Invalid data supplied');
1012 $level[$key] = array();
1013 $level = &$level[$key];
1018 $level[$key] = $string[$i];
1025 switch ($string[$i])
1029 $level = array_pop($stack);
1037 $level[$key] .= $string[$i];
1043 switch ($string[$i])
1047 $level = array_pop($stack);
1054 die('Invalid data supplied');
1061 if (sizeof($stack) != 0 ||
($mode != 0 && $mode != 3))
1063 die('Invalid data supplied');
1069 // Pagination functions
1072 * Pagination routine, generates page number sequence
1073 * tpl_prefix is for using different pagination blocks at one page
1075 function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '')
1079 // Make sure $per_page is a valid value
1080 $per_page = ($per_page <= 0) ?
1 : $per_page;
1082 $seperator = '<span class="page-sep">' . phpbb
::$user->lang
['COMMA_SEPARATOR'] . '</span>';
1083 $total_pages = ceil($num_items / $per_page);
1085 if ($total_pages == 1 ||
!$num_items)
1090 $on_page = floor($start_item / $per_page) +
1;
1091 $url_delim = (strpos($base_url, '?') === false) ?
'?' : '&';
1093 $page_string = ($on_page == 1) ?
'<strong>1</strong>' : '<a href="' . $base_url . '">1</a>';
1095 if ($total_pages > 5)
1097 $start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
1098 $end_cnt = max(min($total_pages, $on_page +
4), 6);
1100 $page_string .= ($start_cnt > 1) ?
' ... ' : $seperator;
1102 for ($i = $start_cnt +
1; $i < $end_cnt; $i++
)
1104 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1105 if ($i < $end_cnt - 1)
1107 $page_string .= $seperator;
1111 $page_string .= ($end_cnt < $total_pages) ?
' ... ' : $seperator;
1115 $page_string .= $seperator;
1117 for ($i = 2; $i < $total_pages; $i++
)
1119 $page_string .= ($i == $on_page) ?
'<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>';
1120 if ($i < $total_pages)
1122 $page_string .= $seperator;
1127 $page_string .= ($on_page == $total_pages) ?
'<strong>' . $total_pages . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($total_pages - 1) * $per_page) . '">' . $total_pages . '</a>';
1129 if ($add_prevnext_text)
1133 $page_string = '<a href="' . $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page) . '">' . phpbb
::$user->lang
['PREVIOUS'] . '</a> ' . $page_string;
1136 if ($on_page != $total_pages)
1138 $page_string .= ' <a href="' . $base_url . "{$url_delim}start=" . ($on_page * $per_page) . '">' . phpbb
::$user->lang
['NEXT'] . '</a>';
1142 $template->assign_vars(array(
1143 $tpl_prefix . 'BASE_URL' => $base_url,
1144 'A_' . $tpl_prefix . 'BASE_URL' => addslashes($base_url),
1145 $tpl_prefix . 'PER_PAGE' => $per_page,
1147 $tpl_prefix . 'PREVIOUS_PAGE' => ($on_page == 1) ?
'' : $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page),
1148 $tpl_prefix . 'NEXT_PAGE' => ($on_page == $total_pages) ?
'' : $base_url . "{$url_delim}start=" . ($on_page * $per_page),
1149 $tpl_prefix . 'TOTAL_PAGES' => $total_pages,
1152 return $page_string;
1156 * Return current page (pagination)
1158 function on_page($num_items, $per_page, $start)
1162 // Make sure $per_page is a valid value
1163 $per_page = ($per_page <= 0) ?
1 : $per_page;
1165 $on_page = floor($start / $per_page) +
1;
1167 $template->assign_vars(array(
1168 'ON_PAGE' => $on_page)
1171 return phpbb
::$user->lang('PAGE_OF', $on_page, max(ceil($num_items / $per_page), 1));
1180 * Add a secret token to the form (requires the S_FORM_TOKEN template variable)
1181 * @param string $form_name The name of the form; has to match the name used in check_form_key, otherwise no restrictions apply
1183 function add_form_key($form_name)
1188 $token_sid = (phpbb
::$user->data
['user_id'] == ANONYMOUS
&& !empty(phpbb
::$config['form_token_sid_guests'])) ? phpbb
::$user->session_id
: '';
1189 $token = sha1($now . phpbb
::$user->data
['user_form_salt'] . $form_name . $token_sid);
1191 $s_fields = build_hidden_fields(array(
1192 'creation_time' => $now,
1193 'form_token' => $token,
1196 $template->assign_vars(array(
1197 'S_FORM_TOKEN' => $s_fields,
1202 * Check the form key. Required for all altering actions not secured by confirm_box
1203 * @param string $form_name The name of the form; has to match the name used in add_form_key, otherwise no restrictions apply
1204 * @param int $timespan The maximum acceptable age for a submitted form in seconds. Defaults to the config setting.
1205 * @param string $return_page The address for the return link
1206 * @param bool $trigger If true, the function will triger an error when encountering an invalid form
1208 function check_form_key($form_name, $timespan = false, $return_page = '', $trigger = false)
1210 if ($timespan === false)
1212 // we enforce a minimum value of half a minute here.
1213 $timespan = (phpbb
::$config['form_token_lifetime'] == -1) ?
-1 : max(30, phpbb
::$config['form_token_lifetime']);
1216 if (phpbb_request
::is_set_post('creation_time') && phpbb_request
::is_set_post('form_token'))
1218 $creation_time = abs(request_var('creation_time', 0));
1219 $token = request_var('form_token', '');
1221 $diff = time() - $creation_time;
1223 // If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)...
1224 if ($diff && ($diff <= $timespan ||
$timespan === -1))
1226 $token_sid = (phpbb
::$user->data
['user_id'] == ANONYMOUS
&& !empty(phpbb
::$config['form_token_sid_guests'])) ? phpbb
::$user->session_id
: '';
1227 $key = sha1($creation_time . phpbb
::$user->data
['user_form_salt'] . $form_name . $token_sid);
1229 if ($key === $token)
1238 trigger_error(phpbb
::$user->lang
['FORM_INVALID'] . $return_page);
1244 // Message/Login boxes
1248 * @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
1249 * @param string $title Title/Message used for confirm box.
1250 * message text is _CONFIRM appended to title.
1251 * If title cannot be found in user->lang a default one is displayed
1252 * If title_CONFIRM cannot be found in user->lang the text given is used.
1253 * @param string $hidden Hidden variables
1254 * @param string $html_body Template used for confirm box
1255 * @param string $u_action Custom form action
1257 function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
1261 if (phpbb_request
::is_set_post('cancel'))
1267 if (phpbb_request
::is_set_post('confirm'))
1269 // language frontier
1270 if (request_var('confirm', '') === phpbb
::$user->lang
['YES'])
1276 if ($check && $confirm)
1278 $user_id = request_var('user_id', 0);
1279 $session_id = request_var('sess', '');
1280 $confirm_key = request_var('confirm_key', '');
1282 if ($user_id != phpbb
::$user->data
['user_id'] ||
$session_id != phpbb
::$user->session_id ||
!$confirm_key ||
!phpbb
::$user->data
['user_last_confirm_key'] ||
$confirm_key != phpbb
::$user->data
['user_last_confirm_key'])
1287 // Reset user_last_confirm_key
1288 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = ''
1289 WHERE user_id = " . phpbb
::$user->data
['user_id'];
1290 phpbb
::$db->sql_query($sql);
1299 $s_hidden_fields = build_hidden_fields(array(
1300 'user_id' => phpbb
::$user->data
['user_id'],
1301 'sess' => phpbb
::$user->session_id
,
1302 'sid' => phpbb
::$user->session_id
,
1305 // generate activation key
1306 $confirm_key = gen_rand_string(10);
1308 page_header((!isset(phpbb
::$user->lang
[$title])) ? phpbb
::$user->lang
['CONFIRM'] : phpbb
::$user->lang
[$title]);
1310 $template->set_filenames(array(
1311 'body' => $html_body)
1314 // If activation key already exist, we better do not re-use the key (something very strange is going on...)
1315 if (request_var('confirm_key', ''))
1317 // This should not occur, therefore we cancel the operation to safe the user
1321 // re-add sid / transform & to & for user->page (user->page is always using &)
1322 $use_page = ($u_action) ? PHPBB_ROOT_PATH
. $u_action : PHPBB_ROOT_PATH
. str_replace('&', '&', phpbb
::$user->page
['page']);
1323 $u_action = reapply_sid($use_page);
1324 $u_action .= ((strpos($u_action, '?') === false) ?
'?' : '&') . 'confirm_key=' . $confirm_key;
1326 $template->assign_vars(array(
1327 'MESSAGE_TITLE' => (!isset(phpbb
::$user->lang
[$title])) ? phpbb
::$user->lang
['CONFIRM'] : phpbb
::$user->lang
[$title],
1328 'MESSAGE_TEXT' => (!isset(phpbb
::$user->lang
[$title . '_CONFIRM'])) ?
$title : phpbb
::$user->lang
[$title . '_CONFIRM'],
1330 'YES_VALUE' => phpbb
::$user->lang
['YES'],
1331 'S_CONFIRM_ACTION' => $u_action,
1332 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
1335 $sql = 'UPDATE ' . USERS_TABLE
. " SET user_last_confirm_key = '" . phpbb
::$db->sql_escape($confirm_key) . "'
1336 WHERE user_id = " . phpbb
::$user->data
['user_id'];
1337 phpbb
::$db->sql_query($sql);
1343 * Generate login box or verify password
1345 function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
1349 // Make sure user->setup() has been called
1350 if (empty(phpbb
::$user->lang
))
1352 phpbb
::$user->setup();
1355 // Print out error if user tries to authenticate as an administrator without having the privileges...
1356 if ($admin && !phpbb
::$acl->acl_get('a_'))
1359 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1360 if (phpbb
::$user->is_registered
)
1362 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1368 if (phpbb_request
::is_set_post('login'))
1373 $credential = request_var('credential', '');
1375 if (strspn($credential, 'abcdef0123456789') !== strlen($credential) ||
strlen($credential) != 32)
1377 if (phpbb
::$user->is_registered
)
1379 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1382 trigger_error('NO_AUTH_ADMIN');
1385 $password = request_var('password_' . $credential, '', true);
1389 $password = request_var('password', '', true);
1392 $username = request_var('username', '', true);
1393 $autologin = phpbb_request
::variable('autologin', false, false, phpbb_request
::POST
);
1394 $viewonline = (phpbb_request
::variable('viewonline', false, false, phpbb_request
::POST
)) ?
0 : 1;
1395 $admin = ($admin) ?
1 : 0;
1396 $viewonline = ($admin) ? phpbb
::$user->data
['session_viewonline'] : $viewonline;
1398 // Check if the supplied username is equal to the one stored within the database if re-authenticating
1399 if ($admin && utf8_clean_string($username) != utf8_clean_string(phpbb
::$user->data
['username']))
1401 // We log the attempt to use a different username...
1402 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1403 trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
1406 // If authentication is successful we redirect user to previous page
1407 $result = phpbb
::$user->login($username, $password, $autologin, $viewonline, $admin);
1409 // If admin authentication and login, we will log if it was a success or not...
1410 // We also break the operation on the first non-success login - it could be argued that the user already knows
1413 if ($result['status'] == LOGIN_SUCCESS
)
1415 add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
1419 // Only log the failed attempt if a real user tried to.
1420 // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
1421 if (phpbb
::$user->is_registered
)
1423 add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
1428 // The result parameter is always an array, holding the relevant information...
1429 if ($result['status'] == LOGIN_SUCCESS
)
1431 $redirect = request_var('redirect', phpbb
::$user->page
['page']);
1433 $message = ($l_success) ?
$l_success : phpbb
::$user->lang
['LOGIN_REDIRECT'];
1434 $l_redirect = ($admin) ? phpbb
::$user->lang
['PROCEED_TO_ACP'] : (($redirect === PHPBB_ROOT_PATH
. 'index.' . PHP_EXT ||
$redirect === 'index.' . PHP_EXT
) ? phpbb
::$user->lang
['RETURN_INDEX'] : phpbb
::$user->lang
['RETURN_PAGE']);
1436 // append/replace SID (may change during the session for AOL users)
1437 $redirect = phpbb
::$url->reapply_sid($redirect);
1439 // Special case... the user is effectively banned, but we allow founders to login
1440 if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != phpbb
::USER_FOUNDER
)
1445 // $redirect = phpbb::$url->meta_refresh(3, $redirect);
1446 trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>'));
1449 // Something failed, determine what...
1450 if ($result['status'] == LOGIN_BREAK
)
1452 trigger_error($result['error_msg']);
1455 // Special cases... determine
1456 switch ($result['status'])
1458 case LOGIN_ERROR_ATTEMPTS
:
1460 $captcha = phpbb_captcha_factory
::get_instance(phpbb
::$config['captcha_plugin']);
1461 $captcha->init(CONFIRM_LOGIN
);
1464 $template->assign_vars(array(
1465 'S_CONFIRM_CODE' => true,
1466 'CONFIRM' => $captcha->get_template(''),
1469 $err = phpbb
::$user->lang
[$result['error_msg']];
1473 case LOGIN_ERROR_PASSWORD_CONVERT
:
1475 phpbb
::$user->lang
[$result['error_msg']],
1476 (phpbb
::$config['email_enable']) ?
'<a href="' . append_sid('ucp', 'mode=sendpassword') . '">' : '',
1477 (phpbb
::$config['email_enable']) ?
'</a>' : '',
1478 (phpbb
::$config['board_contact']) ?
'<a href="mailto:' . utf8_htmlspecialchars(phpbb
::$config['board_contact']) . '">' : '',
1479 (phpbb
::$config['board_contact']) ?
'</a>' : ''
1483 // Username, password, etc...
1485 $err = phpbb
::$user->lang
[$result['error_msg']];
1487 // Assign admin contact to some error messages
1488 if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' ||
$result['error_msg'] == 'LOGIN_ERROR_PASSWORD')
1490 $err = (!phpbb
::$config['board_contact']) ?
sprintf(phpbb
::$user->lang
[$result['error_msg']], '', '') : sprintf(phpbb
::$user->lang
[$result['error_msg']], '<a href="mailto:' . utf8_htmlspecialchars(phpbb
::$config['board_contact']) . '">', '</a>');
1499 // We just use what the session code determined...
1500 // If we are not within the admin directory we use the page dir...
1503 if (!$admin && !defined('ADMIN_START'))
1505 $redirect .= (phpbb
::$user->page
['page_dir']) ? phpbb
::$user->page
['page_dir'] . '/' : '';
1508 $redirect .= phpbb
::$user->page
['page_name'] . ((phpbb
::$user->page
['query_string']) ?
'?' . utf8_htmlspecialchars(phpbb
::$user->page
['query_string']) : '');
1511 // Assign credential for username/password pair
1512 $credential = ($admin) ?
md5(phpbb
::$security->unique_id()) : false;
1514 $s_hidden_fields = array(
1515 'redirect' => $redirect,
1516 'sid' => phpbb
::$user->session_id
,
1521 $s_hidden_fields['credential'] = $credential;
1524 $s_hidden_fields = build_hidden_fields($s_hidden_fields);
1526 phpbb
::$template->assign_vars(array(
1527 'LOGIN_ERROR' => $err,
1528 'LOGIN_EXPLAIN' => $l_explain,
1530 'U_SEND_PASSWORD' => (phpbb
::$config['email_enable']) ? phpbb
::$url->append_sid('ucp', 'mode=sendpassword') : '',
1531 'U_RESEND_ACTIVATION' => (phpbb
::$config['require_activation'] != USER_ACTIVATION_NONE
&& phpbb
::$config['email_enable']) ? phpbb
::$url->append_sid('ucp', 'mode=resend_act') : '',
1532 'U_TERMS_USE' => phpbb
::$url->append_sid('ucp', 'mode=terms'),
1533 'U_PRIVACY' => phpbb
::$url->append_sid('ucp', 'mode=privacy'),
1535 'S_DISPLAY_FULL_LOGIN' => ($s_display) ?
true : false,
1536 'S_LOGIN_ACTION' => (!$admin && !defined('ADMIN_START')) ? phpbb
::$url->append_sid('ucp', 'mode=login') : phpbb
::$url->append_sid(PHPBB_ADMIN_PATH
. 'index.' . PHP_EXT
, false, true, phpbb
::$user->session_id
),
1537 'S_HIDDEN_FIELDS' => $s_hidden_fields,
1539 'S_ADMIN_AUTH' => $admin,
1540 'S_ACP_LOGIN' => defined('ADMIN_START'),
1541 'USERNAME' => ($admin) ? phpbb
::$user->data
['username'] : '',
1543 'USERNAME_CREDENTIAL' => 'username',
1544 'PASSWORD_CREDENTIAL' => ($admin) ?
'password_' . $credential : 'password',
1547 phpbb
::$template->set_filenames(array(
1548 'body' => 'login_body.html')
1551 page_header(phpbb
::$user->lang
['LOGIN'], false);
1552 make_jumpbox('viewforum');
1558 * Generate forum login box
1560 function login_forum_box($forum_data)
1564 $password = request_var('password', '', true);
1566 $sql = 'SELECT forum_id
1567 FROM ' . FORUMS_ACCESS_TABLE
. '
1568 WHERE forum_id = ' . $forum_data['forum_id'] . '
1569 AND user_id = ' . phpbb
::$user->data
['user_id'] . "
1570 AND session_id = '" . phpbb
::$db->sql_escape(phpbb
::$user->session_id
) . "'";
1571 $result = phpbb
::$db->sql_query($sql);
1572 $row = phpbb
::$db->sql_fetchrow($result);
1573 phpbb
::$db->sql_freeresult($result);
1582 // Remove expired authorised sessions
1583 $sql = 'SELECT f.session_id
1584 FROM ' . FORUMS_ACCESS_TABLE
. ' f
1585 LEFT JOIN ' . SESSIONS_TABLE
. ' s ON (f.session_id = s.session_id)
1586 WHERE s.session_id IS NULL';
1587 $result = phpbb
::$db->sql_query($sql);
1589 if ($row = phpbb
::$db->sql_fetchrow($result))
1594 $sql_in[] = (string) $row['session_id'];
1596 while ($row = phpbb
::$db->sql_fetchrow($result));
1598 // Remove expired sessions
1599 $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE
. '
1600 WHERE ' . phpbb
::$db->sql_in_set('session_id', $sql_in);
1601 phpbb
::$db->sql_query($sql);
1603 phpbb
::$db->sql_freeresult($result);
1605 if (phpbb_check_hash($password, $forum_data['forum_password']))
1608 'forum_id' => (int) $forum_data['forum_id'],
1609 'user_id' => (int) phpbb
::$user->data
['user_id'],
1610 'session_id' => (string) phpbb
::$user->session_id
,
1613 phpbb
::$db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE
. ' ' . phpbb
::$db->sql_build_array('INSERT', $sql_ary));
1618 $template->assign_var('LOGIN_ERROR', phpbb
::$user->lang
['WRONG_PASSWORD']);
1621 page_header(phpbb
::$user->lang
['LOGIN']);
1623 $template->assign_vars(array(
1624 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id'])))
1627 $template->set_filenames(array(
1628 'body' => 'login_forum.html')
1637 * Little helper for the build_hidden_fields function
1639 function _build_hidden_fields($key, $value, $specialchar, $stripslashes)
1641 $hidden_fields = '';
1643 if (!is_array($value))
1645 $value = ($stripslashes) ?
stripslashes($value) : $value;
1646 $value = ($specialchar) ?
utf8_htmlspecialchars($value) : $value;
1648 $hidden_fields .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />' . "\n";
1652 foreach ($value as $_key => $_value)
1654 $_key = ($stripslashes) ?
stripslashes($_key) : $_key;
1655 $_key = ($specialchar) ?
utf8_htmlspecialchars($_key) : $_key;
1657 $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar, $stripslashes);
1661 return $hidden_fields;
1665 * Build simple hidden fields from array
1667 * @param array $field_ary an array of values to build the hidden field from
1668 * @param bool $specialchar if true, keys and values get specialchared
1669 * @param bool $stripslashes if true, keys and values get stripslashed
1671 * @return string the hidden fields
1673 function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false)
1675 $s_hidden_fields = '';
1677 foreach ($field_ary as $name => $vars)
1679 $name = ($stripslashes) ?
stripslashes($name) : $name;
1680 $name = ($specialchar) ?
utf8_htmlspecialchars($name) : $name;
1682 $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar, $stripslashes);
1685 return $s_hidden_fields;
1691 function parse_cfg_file($filename, $lines = false)
1693 $parsed_items = array();
1695 if ($lines === false)
1697 $lines = file($filename);
1700 foreach ($lines as $line)
1702 $line = trim($line);
1704 if (!$line ||
$line[0] == '#' ||
($delim_pos = strpos($line, '=')) === false)
1709 // Determine first occurrence, since in values the equal sign is allowed
1710 $key = strtolower(trim(substr($line, 0, $delim_pos)));
1711 $value = trim(substr($line, $delim_pos +
1));
1713 if (in_array($value, array('off', 'false', '0')))
1717 else if (in_array($value, array('on', 'true', '1')))
1721 else if (!trim($value))
1725 else if (($value[0] == "'" && $value[sizeof($value) - 1] == "'") ||
($value[0] == '"' && $value[sizeof($value) - 1] == '"'))
1727 $value = substr($value, 1, sizeof($value)-2);
1730 $parsed_items[$key] = $value;
1733 return $parsed_items;
1741 $args = func_get_args();
1743 $mode = array_shift($args);
1744 $reportee_id = ($mode == 'user') ?
intval(array_shift($args)) : '';
1745 $forum_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
1746 $topic_id = ($mode == 'mod') ?
intval(array_shift($args)) : '';
1747 $action = array_shift($args);
1748 $data = (!sizeof($args)) ?
'' : serialize($args);
1751 'user_id' => (empty(phpbb
::$user->data
)) ? ANONYMOUS
: phpbb
::$user->data
['user_id'],
1752 'log_ip' => phpbb
::$user->ip
,
1753 'log_time' => time(),
1754 'log_operation' => $action,
1755 'log_data' => $data,
1761 $sql_ary['log_type'] = LOG_ADMIN
;
1766 'log_type' => LOG_MOD
,
1767 'forum_id' => $forum_id,
1768 'topic_id' => $topic_id
1774 'log_type' => LOG_USERS
,
1775 'reportee_id' => $reportee_id
1780 $sql_ary['log_type'] = LOG_CRITICAL
;
1787 phpbb
::$db->sql_query('INSERT INTO ' . LOG_TABLE
. ' ' . phpbb
::$db->sql_build_array('INSERT', $sql_ary));
1789 return phpbb
::$db->sql_nextid();
1793 * Return a nicely formatted backtrace (parts from the php manual by diz at ysagoon dot com)
1795 function get_backtrace()
1797 $output = '<div style="font-family: monospace;">';
1798 $backtrace = debug_backtrace();
1799 $path = phpbb
::$url->realpath(PHPBB_ROOT_PATH
);
1801 foreach ($backtrace as $number => $trace)
1803 // We skip the first one, because it only shows this file/function
1809 if (empty($trace['file']) && empty($trace['line']))
1814 // Strip the current directory from path
1815 if (empty($trace['file']))
1817 $trace['file'] = '';
1821 $trace['file'] = str_replace(array($path, '\\'), array('', '/'), $trace['file']);
1822 $trace['file'] = substr($trace['file'], 1);
1826 // If include/require/include_once is not called, do not show arguments - they may contain sensible information
1827 if (!in_array($trace['function'], array('include', 'require', 'include_once')))
1829 unset($trace['args']);
1834 if (!empty($trace['args'][0]))
1836 $argument = htmlspecialchars($trace['args'][0]);
1837 $argument = str_replace(array($path, '\\'), array('', '/'), $argument);
1838 $argument = substr($argument, 1);
1839 $args[] = "'{$argument}'";
1843 $trace['class'] = (!isset($trace['class'])) ?
'' : $trace['class'];
1844 $trace['type'] = (!isset($trace['type'])) ?
'' : $trace['type'];
1846 $output .= '<br />';
1847 $output .= '<b>FILE:</b> ' . htmlspecialchars($trace['file']) . '<br />';
1848 $output .= '<b>LINE:</b> ' . ((!empty($trace['line'])) ?
$trace['line'] : '') . '<br />';
1850 $output .= '<b>CALL:</b> ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']) . '(' . ((sizeof($args)) ?
implode(', ', $args) : '') . ')<br />';
1852 $output .= '</div>';
1857 * This function returns a regular expression pattern for commonly used expressions
1858 * Use with / as delimiter for email mode and # for url modes
1859 * mode can be: email|bbcode_htm|url|url_inline|www_url|www_url_inline|relative_url|relative_url_inline|ipv4|ipv6
1861 function get_preg_expression($mode)
1866 return '(?:[a-z0-9\'\.\-_\+\|]++|&)+@[a-z0-9\-]+\.(?:[a-z0-9\-]+\.)*[a-z]+';
1871 '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
1872 '#<!\-\- l \-\-><a (?:class="[\w-]+" )?href="(.*?)(?:(&|\?)sid=[0-9a-f]{32})?">.*?</a><!\-\- l \-\->#',
1873 '#<!\-\- ([mw]) \-\-><a (?:class="[\w-]+" )?href="(.*?)">.*?</a><!\-\- \1 \-\->#',
1874 '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
1875 '#<!\-\- .*? \-\->#s',
1880 // Whoa these look impressive!
1881 // The code to generate the following two regular expressions which match valid IPv4/IPv6 addresses
1882 // can be found in the develop directory
1884 return '#^(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$#';
1888 return '#^(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){5}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:))$#i';
1893 $inline = ($mode == 'url') ?
')' : '';
1894 $scheme = ($mode == 'url') ?
'[a-z\d+\-.]' : '[a-z\d+]'; // avoid automatic parsing of "word" in "last word.http://..."
1895 // generated with regex generation file in the develop folder
1896 return "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
1900 case 'www_url_inline':
1901 $inline = ($mode == 'www_url') ?
')' : '';
1902 return "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
1905 case 'relative_url':
1906 case 'relative_url_inline':
1907 $inline = ($mode == 'relative_url') ?
')' : '';
1908 return "(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
1916 * Returns the first block of the specified IPv6 address and as many additional
1917 * ones as specified in the length paramater.
1918 * If length is zero, then an empty string is returned.
1919 * If length is greater than 3 the complete IP will be returned
1921 function short_ipv6($ip, $length)
1928 // extend IPv6 addresses
1929 $blocks = substr_count($ip, ':') +
1;
1932 $ip = str_replace('::', ':' . str_repeat('0000:', 9 - $blocks), $ip);
1940 $ip = implode(':', array_slice(explode(':', $ip), 0, 1 +
$length));
1947 * Wrapper for php's checkdnsrr function.
1949 * The windows failover is from the php manual
1950 * Please make sure to check the return value for === true and === false, since NULL could
1953 * @return true if entry found, false if not, NULL if this function is not supported by this environment
1955 function phpbb_checkdnsrr($host, $type = '')
1957 $type = (!$type) ?
'MX' : $type;
1959 if (DIRECTORY_SEPARATOR
== '\\')
1961 if (!function_exists('exec'))
1966 // @exec('nslookup -retry=1 -timout=1 -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output);
1967 @exec
('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host) . '.', $output);
1969 // If output is empty, the nslookup failed
1975 foreach ($output as $line)
1982 // Valid records begin with host name:
1983 if (strpos($line, $host) === 0)
1991 else if (function_exists('checkdnsrr'))
1993 // The dot indicates to search the DNS root (helps those having DNS prefixes on the same domain)
1994 return (checkdnsrr($host . '.', $type)) ?
true : false;
2000 // Handler, header and footer
2003 * Error and message handler, call with trigger_error if reqd
2005 function msg_handler($errno, $msg_text, $errfile, $errline)
2007 global $msg_title, $msg_long_text;
2009 // Message handler is stripping text. In case we need it, we are able to define long text...
2010 if (isset($msg_long_text) && $msg_long_text && !$msg_text)
2012 $msg_text = $msg_long_text;
2015 // Store information for later use
2016 phpbb
::$last_notice = array(
2019 'message' => $msg_text,
2020 'php_error' => (!empty($php_errormsg)) ?
$php_errormsg : '',
2024 // Do not display notices if we suppress them via @
2025 if (error_reporting() == 0)
2036 // Check the error reporting level and return if the error level does not match
2037 // If DEBUG is defined the default level is E_ALL
2038 if (($errno & ((phpbb
::$base_config['debug']) ? E_ALL | E_STRICT
: error_reporting())) == 0)
2043 // if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
2045 // flush the content, else we get a white page if output buffering is on
2046 if ((int) @ini_get
('output_buffering') === 1 ||
strtolower(@ini_get
('output_buffering')) === 'on')
2051 // Another quick fix for those having gzip compression enabled, but do not flush if the coder wants to catch "something". ;)
2052 if (!empty(phpbb
::$config['gzip_compress']))
2054 if (@extension_loaded
('zlib') && !headers_sent() && !ob_get_level())
2060 // remove complete path to installation, with the risk of changing backslashes meant to be there
2061 if (phpbb
::registered('url'))
2063 $errfile = str_replace(array(phpbb
::$url->realpath(PHPBB_ROOT_PATH
), '\\'), array('', '/'), $errfile);
2064 $msg_text = str_replace(array(phpbb
::$url->realpath(PHPBB_ROOT_PATH
), '\\'), array('', '/'), $msg_text);
2067 echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
2074 case E_RECOVERABLE_ERROR
:
2077 if (phpbb
::registered('user'))
2080 if (empty(phpbb
::$user->lang
))
2082 phpbb
::$user->setup();
2085 $msg_text = (!empty(phpbb
::$user->lang
[$msg_text])) ? phpbb
::$user->lang
[$msg_text] : $msg_text;
2086 $msg_title = (!isset($msg_title)) ? phpbb
::$user->lang
['GENERAL_ERROR'] : ((!empty(phpbb
::$user->lang
[$msg_title])) ? phpbb
::$user->lang
[$msg_title] : $msg_title);
2088 $l_return_index = phpbb
::$user->lang('RETURN_INDEX', '<a href="' . PHPBB_ROOT_PATH
. '">', '</a>');
2091 if (!empty(phpbb
::$config['board_contact']))
2093 $l_notify = '<p>' . phpbb
::$user->lang('NOTIFY_ADMIN_EMAIL', phpbb
::$config['board_contact']) . '</p>';
2098 $msg_title = 'General Error';
2099 $l_return_index = '<a href="' . PHPBB_ROOT_PATH
. '">Return to index page</a>';
2102 if (!empty(phpbb
::$config['board_contact']))
2104 $l_notify = '<p>Please notify the board administrator or webmaster: <a href="mailto:' . phpbb
::$config['board_contact'] . '">' . phpbb
::$config['board_contact'] . '</a></p>';
2108 garbage_collection();
2110 // Try to not call the adm page data...
2111 // @todo put into failover template file
2113 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
2114 echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
2116 echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
2117 echo '<title>' . $msg_title . '</title>';
2118 echo '<style type="text/css">' . "\n" . '/* <![CDATA[ */' . "\n";
2119 echo '* { margin: 0; padding: 0; } html { font-size: 100%; height: 100%; margin-bottom: 1px; background-color: #E4EDF0; } body { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; color: #536482; background: #E4EDF0; font-size: 62.5%; margin: 0; } ';
2120 echo 'a:link, a:active, a:visited { color: #006699; text-decoration: none; } a:hover { color: #DD6900; text-decoration: underline; } ';
2121 echo '#wrap { padding: 0 20px 15px 20px; min-width: 615px; } #page-header { text-align: right; height: 40px; } #page-footer { clear: both; font-size: 1em; text-align: center; } ';
2122 echo '.panel { margin: 4px 0; background-color: #FFFFFF; border: solid 1px #A9B8C2; } ';
2123 echo '#errorpage #page-header a { font-weight: bold; line-height: 6em; } #errorpage #content { padding: 10px; } #errorpage #content h1 { line-height: 1.2em; margin-bottom: 0; color: #DF075C; } ';
2124 echo '#errorpage #content div { margin-top: 20px; margin-bottom: 5px; border-bottom: 1px solid #CCCCCC; padding-bottom: 5px; color: #333333; font: bold 1.2em "Lucida Grande", Arial, Helvetica, sans-serif; text-decoration: none; line-height: 120%; text-align: left; } ';
2125 echo "\n" . '/* ]]> */' . "\n";
2128 echo '<body id="errorpage">';
2129 echo '<div id="wrap">';
2130 echo ' <div id="page-header">';
2131 echo ' ' . $l_return_index;
2133 echo ' <div id="acp">';
2134 echo ' <div class="panel">';
2135 echo ' <div id="content">';
2136 echo ' <h1>' . $msg_title . '</h1>';
2138 echo ' <div>' . $msg_text;
2140 if ((phpbb
::registered('acl') && phpbb
::$acl->acl_get('a_')) ||
defined('IN_INSTALL') || phpbb
::$base_config['debug_extra'])
2142 echo ($backtrace = get_backtrace()) ?
'<br /><br />BACKTRACE' . $backtrace : '';
2151 echo ' <div id="page-footer">';
2152 echo ' Powered by phpBB © 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>';
2160 // On a fatal error (and E_USER_ERROR *is* fatal) we never want other scripts to continue and force an exit here.
2164 case E_USER_WARNING
:
2167 define('IN_ERROR_HANDLER', true);
2169 if (empty(phpbb
::$user->data
))
2171 phpbb
::$user->session_begin();
2174 // We re-init the auth array to get correct results on login/logout
2175 phpbb
::$acl->init(phpbb
::$user->data
);
2177 if (empty(phpbb
::$user->lang
))
2179 phpbb
::$user->setup();
2182 $msg_text = (!empty(phpbb
::$user->lang
[$msg_text])) ? phpbb
::$user->lang
[$msg_text] : $msg_text;
2183 $msg_title = (!isset($msg_title)) ? phpbb
::$user->lang
['INFORMATION'] : ((!empty(phpbb
::$user->lang
[$msg_title])) ? phpbb
::$user->lang
[$msg_title] : $msg_title);
2185 if (!defined('HEADER_INC'))
2187 page_header($msg_title);
2190 phpbb
::$template->set_filenames(array(
2191 'body' => 'message_body.html')
2194 phpbb
::$template->assign_vars(array(
2195 'MESSAGE_TITLE' => $msg_title,
2196 'MESSAGE_TEXT' => $msg_text,
2197 'S_USER_WARNING' => ($errno == E_USER_WARNING
) ?
true : false,
2198 'S_USER_NOTICE' => ($errno == E_USER_NOTICE
) ?
true : false)
2201 // We do not want the cron script to be called on error messages
2202 define('IN_CRON', true);
2210 // If we notice an error not handled here we pass this back to PHP by returning false
2211 // This may not work for all php versions
2216 * Generate page header
2217 * @plugin-support override, default, return
2219 function page_header($page_title = '', $display_online_list = true)
2221 if (phpbb
::$plugins->function_override(__FUNCTION__
)) return phpbb
::$plugins->call_override(__FUNCTION__
, $page_title, $display_online_list);
2223 if (defined('HEADER_INC'))
2228 define('HEADER_INC', true);
2231 if (phpbb
::$config['gzip_compress'])
2233 if (@extension_loaded
('zlib') && !headers_sent())
2235 ob_start('ob_gzhandler');
2239 if (phpbb
::$plugins->function_inject(__FUNCTION__
)) phpbb
::$plugins->call_inject(__FUNCTION__
, array('default', &$page_title, &$display_online_list));
2241 // Generate logged in/logged out status
2242 if (phpbb
::$user->data
['user_id'] != ANONYMOUS
)
2244 $u_login_logout = phpbb
::$url->append_sid('ucp', 'mode=logout', true, phpbb
::$user->session_id
);
2245 $l_login_logout = sprintf(phpbb
::$user->lang
['LOGOUT_USER'], phpbb
::$user->data
['username']);
2249 $u_login_logout = phpbb
::$url->append_sid('ucp', 'mode=login');
2250 $l_login_logout = phpbb
::$user->lang
['LOGIN'];
2253 // Last visit date/time
2254 $s_last_visit = (phpbb
::$user->data
['user_id'] != ANONYMOUS
) ? phpbb
::$user->format_date(phpbb
::$user->data
['session_last_visit']) : '';
2256 // Get users online list ... if required
2257 $online_userlist = array();
2258 $l_online_users = $l_online_record = '';
2259 $forum = request_var('f', 0);
2261 if (phpbb
::$config['load_online'] && phpbb
::$config['load_online_time'] && $display_online_list)
2263 $logged_visible_online = $logged_hidden_online = $guests_online = $prev_user_id = 0;
2264 $prev_session_ip = $reading_sql = '';
2268 $reading_sql = ' AND s.session_forum_id = ' . $forum;
2271 // Get number of online guests
2272 if (!phpbb
::$config['load_online_guests'])
2274 if (phpbb
::$db->features
['count_distinct'])
2276 $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests
2277 FROM ' . SESSIONS_TABLE
. ' s
2278 WHERE s.session_user_id = ' . ANONYMOUS
. '
2279 AND s.session_time >= ' . (time() - (phpbb
::$config['load_online_time'] * 60)) .
2284 $sql = 'SELECT COUNT(session_ip) as num_guests
2286 SELECT DISTINCT s.session_ip
2287 FROM ' . SESSIONS_TABLE
. ' s
2288 WHERE s.session_user_id = ' . ANONYMOUS
. '
2289 AND s.session_time >= ' . (time() - (phpbb
::$config['load_online_time'] * 60)) .
2293 $result = phpbb
::$db->sql_query($sql);
2294 $guests_online = (int) phpbb
::$db->sql_fetchfield('num_guests');
2295 phpbb
::$db->sql_freeresult($result);
2298 $sql = 'SELECT u.username, u.username_clean, u.user_id, u.user_type, u.user_allow_viewonline, u.user_colour, s.session_ip, s.session_viewonline
2299 FROM ' . USERS_TABLE
. ' u, ' . SESSIONS_TABLE
. ' s
2300 WHERE s.session_time >= ' . (time() - (intval(phpbb
::$config['load_online_time']) * 60)) .
2302 ((!phpbb
::$config['load_online_guests']) ?
' AND s.session_user_id <> ' . ANONYMOUS
: '') . '
2303 AND u.user_id = s.session_user_id
2304 ORDER BY u.username_clean ASC, s.session_ip ASC';
2305 $result = phpbb
::$db->sql_query($sql);
2307 $prev_user_id = false;
2309 while ($row = phpbb
::$db->sql_fetchrow($result))
2311 // User is logged in and therefore not a guest
2312 if ($row['user_id'] != ANONYMOUS
)
2314 // Skip multiple sessions for one user
2315 if ($row['user_id'] != $prev_user_id)
2317 if ($row['session_viewonline'])
2319 $logged_visible_online++
;
2323 $row['username'] = '<em>' . $row['username'] . '</em>';
2324 $logged_hidden_online++
;
2327 if (($row['session_viewonline']) || phpbb
::$acl->acl_get('u_viewonline'))
2329 $user_online_link = get_username_string(($row['user_type'] <> phpbb
::USER_IGNORE
) ?
'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']);
2330 $online_userlist[] = $user_online_link;
2334 $prev_user_id = $row['user_id'];
2338 // Skip multiple sessions for one user
2339 if ($row['session_ip'] != $prev_session_ip)
2345 $prev_session_ip = $row['session_ip'];
2347 phpbb
::$db->sql_freeresult($result);
2349 if (!sizeof($online_userlist))
2351 $online_userlist = phpbb
::$user->lang
['NO_ONLINE_USERS'];
2355 $online_userlist = implode(', ', $online_userlist);
2360 $online_userlist = phpbb
::$user->lang
['REGISTERED_USERS'] . ' ' . $online_userlist;
2364 $online_userlist = phpbb
::$user->lang('BROWSING_FORUM_GUESTS', $online_userlist, $guests_online);
2367 $total_online_users = $logged_visible_online +
$logged_hidden_online +
$guests_online;
2369 if ($total_online_users > phpbb
::$config['record_online_users'])
2371 set_config('record_online_users', $total_online_users, true);
2372 set_config('record_online_date', time(), true);
2375 $l_online_users = phpbb
::$user->lang('ONLINE_USER_COUNT', $total_online_users);
2376 $l_online_users .= phpbb
::$user->lang('REG_USER_COUNT', $logged_visible_online);
2377 $l_online_users .= phpbb
::$user->lang('HIDDEN_USER_COUNT', $logged_hidden_online);
2378 $l_online_users .= phpbb
::$user->lang('GUEST_USER_COUNT', $guests_online);
2380 $l_online_record = phpbb
::$user->lang('RECORD_ONLINE_USERS', phpbb
::$config['record_online_users'], phpbb
::$user->format_date(phpbb
::$config['record_online_date']));
2381 $l_online_time = phpbb
::$user->lang('VIEW_ONLINE_TIME', phpbb
::$config['load_online_time']);
2385 $l_online_time = '';
2388 $l_privmsgs_text = $l_privmsgs_text_unread = '';
2389 $s_privmsg_new = false;
2391 // Obtain number of new private messages if user is logged in
2392 if (!empty(phpbb
::$user->data
['is_registered']))
2394 if (phpbb
::$user->data
['user_new_privmsg'])
2396 $l_privmsgs_text = phpbb
::$user->lang('NEW_PM', phpbb
::$user->data
['user_new_privmsg']);
2398 if (!phpbb
::$user->data
['user_last_privmsg'] || phpbb
::$user->data
['user_last_privmsg'] > phpbb
::$user->data
['session_last_visit'])
2400 $sql = 'UPDATE ' . USERS_TABLE
. '
2401 SET user_last_privmsg = ' . phpbb
::$user->data
['session_last_visit'] . '
2402 WHERE user_id = ' . phpbb
::$user->data
['user_id'];
2403 phpbb
::$db->sql_query($sql);
2405 $s_privmsg_new = true;
2409 $s_privmsg_new = false;
2414 $l_privmsgs_text = phpbb
::$user->lang
['NO_NEW_PM'];
2415 $s_privmsg_new = false;
2418 $l_privmsgs_text_unread = '';
2420 if (phpbb
::$user->data
['user_unread_privmsg'] && phpbb
::$user->data
['user_unread_privmsg'] != phpbb
::$user->data
['user_new_privmsg'])
2422 $l_privmsgs_text_unread = phpbb
::$user->lang('UNREAD_PM', phpbb
::$user->data
['user_unread_privmsg']);
2427 $tz = (phpbb
::$user->data
['user_id'] != ANONYMOUS
) ?
strval(doubleval(phpbb
::$user->data
['user_timezone'])) : strval(doubleval(phpbb
::$config['board_timezone']));
2429 // Send a proper content-language to the output
2430 $user_lang = phpbb
::$user->lang
['USER_LANG'];
2431 if (strpos($user_lang, '-x-') !== false)
2433 $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-'));
2436 // The following assigns all _common_ variables that may be used at any point in a template.
2437 phpbb
::$template->assign_vars(array(
2438 'SITENAME' => phpbb
::$config['sitename'],
2439 'SITE_DESCRIPTION' => phpbb
::$config['site_desc'],
2440 'PAGE_TITLE' => $page_title,
2441 'SCRIPT_NAME' => str_replace('.' . PHP_EXT
, '', phpbb
::$user->page
['page_name']),
2442 'LAST_VISIT_DATE' => phpbb
::$user->lang('YOU_LAST_VISIT', $s_last_visit),
2443 'LAST_VISIT_YOU' => $s_last_visit,
2444 'CURRENT_TIME' => phpbb
::$user->lang('CURRENT_TIME', phpbb
::$user->format_date(time(), false, true)),
2445 'TOTAL_USERS_ONLINE' => $l_online_users,
2446 'LOGGED_IN_USER_LIST' => $online_userlist,
2447 'RECORD_USERS' => $l_online_record,
2448 'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text,
2449 'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread,
2451 'S_USER_NEW_PRIVMSG' => phpbb
::$user->data
['user_new_privmsg'],
2452 'S_USER_UNREAD_PRIVMSG' => phpbb
::$user->data
['user_unread_privmsg'],
2454 'SESSION_ID' => phpbb
::$user->session_id
,
2455 'ROOT_PATH' => PHPBB_ROOT_PATH
,
2457 'L_LOGIN_LOGOUT' => $l_login_logout,
2458 'L_INDEX' => phpbb
::$user->lang
['FORUM_INDEX'],
2459 'L_ONLINE_EXPLAIN' => $l_online_time,
2461 'U_PRIVATEMSGS' => phpbb
::$url->append_sid('ucp', 'i=pm&folder=inbox'),
2462 'U_RETURN_INBOX' => phpbb
::$url->append_sid('ucp', 'i=pm&folder=inbox'),
2463 'U_POPUP_PM' => phpbb
::$url->append_sid('ucp', 'i=pm&mode=popup'),
2464 'UA_POPUP_PM' => addslashes(phpbb
::$url->append_sid('ucp', 'i=pm&mode=popup')),
2465 'U_MEMBERLIST' => phpbb
::$url->append_sid('memberlist'),
2466 'U_VIEWONLINE' => (phpbb
::$acl->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? phpbb
::$url->append_sid('viewonline') : '',
2467 'U_LOGIN_LOGOUT' => $u_login_logout,
2468 'U_INDEX' => phpbb
::$url->append_sid('index'),
2469 'U_SEARCH' => phpbb
::$url->append_sid('search'),
2470 'U_REGISTER' => phpbb
::$url->append_sid('ucp', 'mode=register'),
2471 'U_PROFILE' => phpbb
::$url->append_sid('ucp'),
2472 'U_MODCP' => phpbb
::$url->append_sid('mcp', false, true, phpbb
::$user->session_id
),
2473 'U_FAQ' => phpbb
::$url->append_sid('faq'),
2474 'U_SEARCH_SELF' => phpbb
::$url->append_sid('search', 'search_id=egosearch'),
2475 'U_SEARCH_NEW' => phpbb
::$url->append_sid('search', 'search_id=newposts'),
2476 'U_SEARCH_UNANSWERED' => phpbb
::$url->append_sid('search', 'search_id=unanswered'),
2477 'U_SEARCH_ACTIVE_TOPICS'=> phpbb
::$url->append_sid('search', 'search_id=active_topics'),
2478 'U_DELETE_COOKIES' => phpbb
::$url->append_sid('ucp', 'mode=delete_cookies'),
2479 'U_TEAM' => (phpbb
::$user->data
['user_id'] != ANONYMOUS
&& !phpbb
::$acl->acl_get('u_viewprofile')) ?
'' : phpbb
::$url->append_sid('memberlist', 'mode=leaders'),
2480 'U_RESTORE_PERMISSIONS' => (phpbb
::$user->data
['user_perm_from'] && phpbb
::$acl->acl_get('a_switchperm')) ? phpbb
::$url->append_sid('ucp', 'mode=restore_perm') : '',
2482 'S_USER_LOGGED_IN' => (phpbb
::$user->data
['user_id'] != ANONYMOUS
) ?
true : false,
2483 'S_AUTOLOGIN_ENABLED' => (phpbb
::$config['allow_autologin']) ?
true : false,
2484 'S_BOARD_DISABLED' => (phpbb
::$config['board_disable']) ?
true : false,
2485 'S_REGISTERED_USER' => (!empty(phpbb
::$user->is_registered
)) ?
true : false,
2486 'S_IS_BOT' => (!empty(phpbb
::$user->is_bot
)) ?
true : false,
2487 'S_USER_PM_POPUP' => phpbb
::$user->optionget('popuppm'),
2488 'S_USER_LANG' => $user_lang,
2489 'S_USER_BROWSER' => (isset(phpbb
::$user->data
['session_browser'])) ? phpbb
::$user->data
['session_browser'] : phpbb
::$user->lang
['UNKNOWN_BROWSER'],
2490 'S_USERNAME' => phpbb
::$user->data
['username'],
2491 'S_CONTENT_DIRECTION' => phpbb
::$user->lang
['DIRECTION'],
2492 'S_CONTENT_FLOW_BEGIN' => (phpbb
::$user->lang
['DIRECTION'] == 'ltr') ?
'left' : 'right',
2493 'S_CONTENT_FLOW_END' => (phpbb
::$user->lang
['DIRECTION'] == 'ltr') ?
'right' : 'left',
2494 'S_CONTENT_ENCODING' => 'UTF-8',
2495 'S_TIMEZONE' => (phpbb
::$user->data
['user_dst'] ||
(phpbb
::$user->data
['user_id'] == ANONYMOUS
&& phpbb
::$config['board_dst'])) ?
sprintf(phpbb
::$user->lang
['ALL_TIMES'], phpbb
::$user->lang
['tz'][$tz], phpbb
::$user->lang
['tz']['dst']) : sprintf(phpbb
::$user->lang
['ALL_TIMES'], phpbb
::$user->lang
['tz'][$tz], ''),
2496 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ?
1 : 0,
2497 'S_DISPLAY_SEARCH' => (!phpbb
::$config['load_search']) ?
0 : (phpbb
::$acl->acl_get('u_search') && phpbb
::$acl->acl_getf_global('f_search')),
2498 'S_DISPLAY_PM' => (phpbb
::$config['allow_privmsg'] && !empty(phpbb
::$user->data
['is_registered']) && (phpbb
::$acl->acl_get('u_readpm') || phpbb
::$acl->acl_get('u_sendpm'))) ?
true : false,
2499 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ? phpbb
::$acl->acl_get('u_viewprofile') : 0,
2500 'S_NEW_PM' => ($s_privmsg_new) ?
1 : 0,
2501 'S_REGISTER_ENABLED' => (phpbb
::$config['require_activation'] != USER_ACTIVATION_DISABLE
) ?
true : false,
2503 'T_THEME_PATH' => PHPBB_ROOT_PATH
. 'styles/' . phpbb
::$user->theme
['theme_path'] . '/theme',
2504 'T_TEMPLATE_PATH' => PHPBB_ROOT_PATH
. 'styles/' . phpbb
::$user->theme
['template_path'] . '/template',
2505 'T_IMAGESET_PATH' => PHPBB_ROOT_PATH
. 'styles/' . phpbb
::$user->theme
['imageset_path'] . '/imageset',
2506 'T_IMAGESET_LANG_PATH' => PHPBB_ROOT_PATH
. 'styles/' . phpbb
::$user->theme
['imageset_path'] . '/imageset/' . phpbb
::$user->data
['user_lang'],
2507 'T_IMAGES_PATH' => PHPBB_ROOT_PATH
. 'images/',
2508 'T_SMILIES_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['smilies_path'] . '/',
2509 'T_AVATAR_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['avatar_path'] . '/',
2510 'T_AVATAR_GALLERY_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['avatar_gallery_path'] . '/',
2511 'T_ICONS_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['icons_path'] . '/',
2512 'T_RANKS_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['ranks_path'] . '/',
2513 'T_UPLOAD_PATH' => PHPBB_ROOT_PATH
. phpbb
::$config['upload_path'] . '/',
2514 'T_STYLESHEET_LINK' => (!phpbb
::$user->theme
['theme_storedb']) ? PHPBB_ROOT_PATH
. 'styles/' . phpbb
::$user->theme
['theme_path'] . '/theme/stylesheet.css' : phpbb
::$url->get(PHPBB_ROOT_PATH
. 'style.' . PHP_EXT
. '?id=' . phpbb
::$user->theme
['style_id'] . '&lang=' . phpbb
::$user->data
['user_lang']), //PHPBB_ROOT_PATH . "store/{$user->theme['theme_id']}_{$user->theme['imageset_id']}_{$user->lang_name}.css"
2515 'T_STYLESHEET_NAME' => phpbb
::$user->theme
['theme_name'],
2517 'SITE_LOGO_IMG' => phpbb
::$user->img('site_logo'),
2519 'A_COOKIE_SETTINGS' => addslashes('; path=' . phpbb
::$config['cookie_path'] . ((!phpbb
::$config['cookie_domain'] || phpbb
::$config['cookie_domain'] == 'localhost' || phpbb
::$config['cookie_domain'] == '127.0.0.1') ?
'' : '; domain=' . phpbb
::$config['cookie_domain']) . ((!phpbb
::$config['cookie_secure']) ?
'' : '; secure')),
2522 // application/xhtml+xml not used because of IE
2523 header('Content-type: text/html; charset=UTF-8');
2525 header('Cache-Control: private, no-cache="set-cookie"');
2526 header('Expires: 0');
2527 header('Pragma: no-cache');
2529 if (phpbb
::$plugins->function_inject(__FUNCTION__
, 'return')) return phpbb
::$plugins->call_inject(__FUNCTION__
, 'return');
2533 * Generate page footer
2535 function page_footer($run_cron = true)
2539 // Output page creation time
2540 if (phpbb
::$base_config['debug'])
2542 $mtime = explode(' ', microtime());
2543 $totaltime = $mtime[0] +
$mtime[1] - $starttime;
2545 if (phpbb_request
::variable('explain', false) && /*phpbb::$acl->acl_get('a_') &&*/ phpbb
::$base_config['debug_extra'] && method_exists(phpbb
::$db, 'sql_report'))
2547 phpbb
::$db->sql_report('display');
2550 $debug_output = sprintf('Time : %.3fs | ' . phpbb
::$db->sql_num_queries() . ' Queries | GZIP : ' . ((phpbb
::$config['gzip_compress']) ?
'On' : 'Off') . ((phpbb
::$user->system
['load']) ?
' | Load : ' . phpbb
::$user->system
['load'] : ''), $totaltime);
2552 if (/*phpbb::$acl->acl_get('a_') &&*/ phpbb
::$base_config['debug_extra'])
2554 if (function_exists('memory_get_usage'))
2556 if ($memory_usage = memory_get_usage())
2558 $memory_usage -= phpbb
::$base_config['memory_usage'];
2559 $memory_usage = get_formatted_filesize($memory_usage);
2561 $debug_output .= ' | Memory Usage: ' . $memory_usage;
2565 $debug_output .= ' | <a href="' . phpbb
::$url->build_url() . '&explain=1">Explain</a>';
2569 phpbb
::$template->assign_vars(array(
2570 'DEBUG_OUTPUT' => (phpbb
::$base_config['debug']) ?
$debug_output : '',
2571 'TRANSLATION_INFO' => (!empty(phpbb
::$user->lang
['TRANSLATION_INFO'])) ? phpbb
::$user->lang
['TRANSLATION_INFO'] : '',
2573 'U_ACP' => (phpbb
::$acl->acl_get('a_') && !empty(phpbb
::$user->is_registered
)) ? phpbb
::$url->append_sid(phpbb
::$base_config['admin_folder'] . '/index', false, true, phpbb
::$user->session_id
) : '',
2576 // Call cron-type script
2577 if (!defined('IN_CRON') && $run_cron && !phpbb
::$config['board_disable'])
2581 if (time() - phpbb
::$config['queue_interval'] > phpbb
::$config['last_queue_run'] && !defined('IN_ADMIN') && file_exists(PHPBB_ROOT_PATH
. 'cache/queue.' . PHP_EXT
))
2583 // Process email queue
2584 $cron_type = 'queue';
2586 else if (method_exists(phpbb
::$acm, 'tidy') && time() - phpbb
::$config['cache_gc'] > phpbb
::$config['cache_last_gc'])
2589 $cron_type = 'tidy_cache';
2591 else if (time() - phpbb
::$config['warnings_gc'] > phpbb
::$config['warnings_last_gc'])
2593 $cron_type = 'tidy_warnings';
2595 else if (time() - phpbb
::$config['database_gc'] > phpbb
::$config['database_last_gc'])
2597 // Tidy the database
2598 $cron_type = 'tidy_database';
2600 else if (time() - phpbb
::$config['search_gc'] > phpbb
::$config['search_last_gc'])
2603 $cron_type = 'tidy_search';
2605 else if (time() - phpbb
::$config['session_gc'] > phpbb
::$config['session_last_gc'])
2607 $cron_type = 'tidy_sessions';
2612 phpbb
::$template->assign_var('RUN_CRON_TASK', '<img src="' . phpbb
::$url->append_sid('cron', 'cron_type=' . $cron_type) . '" width="1" height="1" alt="cron" />');
2616 phpbb
::$template->display('body');
2618 garbage_collection();
2623 * Closing the cache object and the database
2624 * Cool function name, eh? We might want to add operations to it later
2626 function garbage_collection()
2628 // Unload cache, must be done before the DB connection if closed
2629 if (phpbb
::registered('acm'))
2631 phpbb
::$acm->unload();
2634 // Close our DB connection.
2635 if (phpbb
::registered('db'))
2637 phpbb
::$db->sql_close();
2642 * Handler for exit calls in phpBB.
2643 * This function supports hooks.
2645 * Note: This function is called after the template has been outputted.
2647 function exit_handler()
2649 // needs to be run prior to the hook
2650 if (phpbb_request
::super_globals_disabled())
2652 phpbb_request
::enable_super_globals();
2655 // As a pre-caution... some setups display a blank page if the flush() is not there.
2656 (empty(phpbb
::$config['gzip_compress'])) ? @flush
() : @ob_flush
();