/** * Render a menu branch to tempcode. * * @param array The menu branch map * @param SHORT_TEXT An identifier for the menu (will be used as a unique id by menu javascript code) * @param MEMBER The member the menu is being built as * @param integer The depth into the menu that this branch resides at * @param ID_TEXT The menu type (determines what templates get used) * @param boolean Whether to generate Comcode with admin privilege * @param array Array of all other branches * @param integer The level * @return array A pair: array of parameters of the menu branch (or NULL if unrenderable, or Tempcode of something to attach), and whether it is expanded */ function render_menu_branch($branch, $codename, $source_member, $level, $type, $as_admin, $all_branches, $the_level = 1) { global $REDIRECTED_TO; $caption = mixed(); // Initialise type to mixed if (is_string($branch['caption']) && strpos($branch['caption'], '[') !== false) { $caption = comcode_to_tempcode($branch['caption'], $source_member, $as_admin); } else { $caption = $branch['caption']; } if (!is_null($branch['only_on_page']) && $branch['only_on_page'] != '') { if (strpos($branch['only_on_page'], '{') !== false) { require_code('tempcode_compiler'); $branch['only_on_page'] = static_evaluate_tempcode(template_to_tempcode($branch['only_on_page'])); } if ($branch['only_on_page'] != '' && !match_key_match($branch['only_on_page'])) { return array(NULL, false); } // We are not allowed to render this on this page } $current_zone = false; $current_page = false; $expand_this = false; $tooltip = array_key_exists('caption_long', $branch) ? $branch['caption_long'] : ''; if (is_null($tooltip)) { $tooltip = ''; } // Caused by corrupt in DB. translate table join failed due to corrupt lang string reference $dp = $GLOBALS['ZONE']['zone_default_page']; $url = mixed(); // Spacers if ($branch['type'] == 'blank') { return array(do_template('MENU_SPACER_' . filter_naughty_harsh($type), array('MENU' => $codename, 'TOP_LEVEL' => $the_level == 1, 'THE_LEVEL' => strval($the_level), 'CURRENT' => $current_page, 'CURRENT_ZONE' => $current_zone), NULL, false, 'MENU_SPACER_tree'), false); } // Normal branches... $users_current_zone = get_zone_name(); // Work out the final URL to use $url = $branch['special']; if (is_object($url)) { if (isset($url->seq_parts) && isset($url->seq_parts[0]) && $url->seq_parts[0][3] == 'PAGE_LINK') { $url = $url->seq_parts[0][1][0]; if (is_object($url)) { $url = $url->evaluate(); } } elseif (isset($url->bits) && isset($url->bits[0]) && $url->bits[0][2] == 'PAGE_LINK') { $url = $url->bits[0][3][0]; if (is_object($url)) { $url = $url->evaluate(); } } elseif (substr($url->evaluate(), 0, strlen(get_base_url())) == get_base_url()) { $page_link = url_to_pagelink($url->evaluate(), true, true); if ($page_link != '') { $url = $page_link; } } } if (!is_object($url)) { $parts = array(); if (preg_match('#([\\w-]*):([\\w-]+|[^/]|$)((:(.*))*)#', $url, $parts) != 0 && $parts[1] != 'mailto') { $page_link = $url; list($zone_name, $map, $hash) = page_link_decode($url); if ($zone_name == 'forum' && get_forum_type() != 'ocf') { return array(NULL, false); } if (!isset($map['page'])) { $map['page'] = get_zone_default_page($zone_name); } // If we need to check access if (array_key_exists('check_perms', $branch['modifiers'])) { if (!has_zone_access(get_member(), $zone_name)) { return array(NULL, false); } if (!has_page_access(get_member(), $map['page'], $zone_name)) { return array(NULL, false); } } // Scan for Tempcode symbols etc foreach ($map as $key => $val) { if (strpos($val, '{') !== false) { require_code('tempcode_compiler'); $map[$key] = template_to_tempcode($val); } } $url = build_url($map, $zone_name, NULL, false, false, false, $hash); // See if this is current page $somewhere_definite = false; $_parts = array(); foreach ($all_branches as $_branch) { if (!is_string($_branch['special'])) { continue; } if (preg_match('#([\\w-]*):([\\w-]+|[^/]|$)((:(.*))*)#', $_branch['special'], $_parts) != 0) { if ($_parts[1] == $users_current_zone) { $somewhere_definite = true; } } } $current_zone = $zone_name == $users_current_zone || !is_null($REDIRECTED_TO) && $zone_name == $REDIRECTED_TO['r_to_zone'] && !$somewhere_definite; // This code is a bit smart, as zone menus usually have a small number of zones on them - redirects will be counted into the zone redirected to, so long as there is no more suitable zone and so long as it is not a transparent redirect if ($zone_name == $users_current_zone || !is_null($REDIRECTED_TO) && $zone_name == $REDIRECTED_TO['r_to_zone'] && array_key_exists('page', $map) && $map['page'] == $REDIRECTED_TO['r_to_page']) { $current_page = true; foreach ($map as $k => $v) { if (is_integer($v)) { $v = strval($v); } if (is_object($v)) { $v = $v->evaluate(); } if ($v == '' && $k == 'page') { $v = 'start'; if ($zone_name == $users_current_zone) { global $ZONE; $v = $ZONE['zone_default_page']; } } $pv = get_param($k, $k == 'page' ? $dp : NULL, true); if ($pv !== $v && ($k != 'page' || is_null($REDIRECTED_TO) || !is_null($REDIRECTED_TO) && ($v !== $REDIRECTED_TO['r_to_page'] || $zone_name != $REDIRECTED_TO['r_to_zone'])) && ($k != 'type' || $v != 'misc') && ($v != $dp || $k != 'page' || get_param('page', '') != '') && substr($k, 0, 5) != 'keep_') { $current_page = false; break; } } } } else { $page_link = ''; $sym_pos = mixed(); $sym_pos = is_null($url) ? false : strpos($url, '{$'); if ($sym_pos !== false) { $_url = new ocp_tempcode(); $len = strlen($url); $prev = 0; do { $p_len = $sym_pos + 1; $balance = 1; while ($p_len < $len && $balance != 0) { if ($url[$p_len] == '{') { $balance++; } elseif ($url[$p_len] == '}') { $balance--; } $p_len++; } $_url->attach(substr($url, $prev, $sym_pos - $prev)); $_ret = new ocp_tempcode(); $_ret->parse_from($url, $sym_pos, $p_len); $_url->attach($_ret); $prev = $p_len; $sym_pos = strpos($url, '{$', $sym_pos + 1); } while ($sym_pos !== false); $_url->attach(substr($url, $prev)); $url = $_url; } } } else { $page_link = NULL; } // Children $children = new ocp_tempcode(); $display = 'block'; if ($branch['type'] == 'drawer') { $new_children = array(); foreach ($branch['children'] as $i => $child) { list($children2, $_expand_this) = render_menu_branch($child, $codename, $source_member, $level + 1, $type, $as_admin, $all_branches, $the_level + 1); if ($_expand_this) { $expand_this = true; } if ($children2 !== '' && !is_null($children2)) { $new_children[] = $children2; } } $num = count($new_children); foreach ($new_children as $i => $child) { if (is_object($child)) { $children->attach($child); } else { $children->attach(do_template('MENU_BRANCH_' . filter_naughty_harsh($type), $child + array('POSITION' => strval($i), 'LAST' => $i == $num - 1, 'BRETHREN_COUNT' => strval($num)), NULL, false, 'MENU_BRANCH_tree')); } } if ($children->is_empty()) { return array(NULL, false); } // Nothing here! if (!array_key_exists('expanded', $branch['modifiers']) && !$expand_this && !$current_page) { $display = has_js() ? 'none' : 'block'; // We remap to 'none' using JS. If no JS, it remains visible. Once we have learn't we have JS, we don't need to do it again } else { $display = 'block'; } } // Data cleanups $escape = is_string($caption) && !array_key_exists('comcode', $branch['modifiers']); if ($escape) { $caption = escape_html($caption); } // Access key if ($page_link === '_SEARCH:help') { $accesskey = '6'; } elseif ($page_link === '_SEARCH:rules') { $accesskey = '7'; } elseif ($page_link === '_SEARCH:staff:type=misc') { $accesskey = '5'; } else { $accesskey = ''; } // Other properties $popup = array_key_exists('popup', $branch['modifiers']); $popup_width = ''; $popup_height = ''; if ($popup) { $popup_width = strval($branch['width']); $popup_height = strval($branch['height']); } $new_window = array_key_exists('new_window', $branch['modifiers']); // Render! $rendered_branch = array('RANDOM' => substr(md5(uniqid('')), 0, 7), 'CAPTION' => $caption, 'IMG' => array_key_exists('img', $branch) ? $branch['img'] : '', 'URL' => $url, 'PAGE_LINK' => $page_link, 'ACCESSKEY' => $accesskey, 'POPUP' => $popup, 'POPUP_WIDTH' => $popup_width, 'POPUP_HEIGHT' => $popup_height, 'NEW_WINDOW' => $new_window, 'TOOLTIP' => $tooltip, 'CHILDREN' => $children, 'DISPLAY' => $display, 'MENU' => $codename, 'TOP_LEVEL' => $the_level == 1, 'THE_LEVEL' => strval($the_level), 'CURRENT' => $current_page, 'CURRENT_ZONE' => $current_zone); return array($rendered_branch, $current_page || $expand_this); }
/** * Take a page link and convert to attributes and zone. * * @param SHORT_TEXT The page link * @return array Triple: zone, attribute-array, hash part of a URL including the hash (or blank) */ function page_link_decode($param) { global $CHR_0; if (strpos($param, '#') === false) { $hash = ''; } else { $hash_pos = strpos($param, '#'); $hash = substr($param, $hash_pos); $param = substr($param, 0, $hash_pos); } if (strpos($param, $CHR_0) === false) { $bits = explode(':', $param); } else { $term_pos = strpos($param, $CHR_0); $bits = explode(':', substr($param, 0, $term_pos)); $bits[count($bits) - 1] .= substr($param, $term_pos); } $zone = $bits[0]; if ($zone == '_SEARCH') { if (isset($bits[1])) { $zone = get_page_zone($bits[1], false); if ($zone === NULL) { $zone = ''; } } else { $zone = ''; } } elseif ($zone == 'site' && get_option('collapse_user_zones') == '1') { $zone = ''; } elseif ($zone == '_SELF') { $zone = get_zone_name(); } if (isset($bits[1])) { if ($bits[1] != '') { if ($bits[1] == '_SELF') { $attributes = array('page' => get_page_name()); } else { $attributes = array('page' => $bits[1]); } } else { $attributes = array(); } unset($bits[1]); } else { $attributes = array('page' => get_zone_default_page($zone)); } unset($bits[0]); $i = 0; foreach ($bits as $bit) { if ($bit != '' || $i == 1) { if ($i == 0 && strpos($bit, '=') === false) { $_bit = array('type', $bit); } elseif ($i == 1 && strpos($bit, '=') === false) { $_bit = array('id', $bit); } else { $_bit = explode('=', $bit, 2); } } else { $_bit = array($bit, ''); } if (isset($_bit[1])) { $decoded = urldecode($_bit[1]); if ($decoded != '' && $decoded[0] == '{' && strlen($decoded) > 2 && intval($decoded[1]) > 51) { require_code('tempcode_compiler'); $decoded = template_to_tempcode($decoded); $decoded = $decoded->evaluate(); } if ($decoded == '<null>') { $attributes[$_bit[0]] = NULL; } else { $attributes[$_bit[0]] = $decoded; } } $i++; } return array($zone, $attributes, $hash); }
/** * The UI to show page view statistics for the front page. * * @return tempcode The UI */ function overview() { $page_request = _request_page(get_zone_default_page(''), ''); $page = $page_request[count($page_request) - 1]; $title = get_page_title('OVERVIEW_STATISTICS'); list($graph_views_monthly, $list_views_monthly) = array_values($this->views_per_x($page, 'views_hourly', 'VIEWS_PER_MONTH', 'DESCRIPTION_VIEWS_PER_MONTH', 730, 8766)); //************************************************************************************************ // Views //************************************************************************************************ $start = get_param_integer('start_views', 0); $max = get_param_integer('max_views', 30); $sortables = array('date_and_time' => do_lang_tempcode('DATE_TIME')); list($sortable, $sort_order) = explode(' ', get_param('sort_views', 'date_and_time DESC')); if (strtoupper($sort_order) != 'ASC' && strtoupper($sort_order) != 'DESC' || !array_key_exists($sortable, $sortables)) { log_hack_attack_and_exit('ORDERBY_HACK'); } global $NON_CANONICAL_PARAMS; $NON_CANONICAL_PARAMS[] = 'sort_views'; // NB: not used in default templates $where = db_string_equal_to('the_page', $page); if (substr($page, 0, 6) == 'pages/') { $where .= ' OR ' . db_string_equal_to('the_page', '/' . $page); } // Legacy compatibility $rows = $GLOBALS['SITE_DB']->query('SELECT date_and_time FROM ' . get_table_prefix() . 'stats WHERE (' . $where . ') ORDER BY ' . $sortable . ' ' . $sort_order); if (count($rows) < 1) { $list_views = new ocp_tempcode(); } else { require_code('templates_results_table'); $fields_title = results_field_title(array(do_lang_tempcode('DATE_TIME'), do_lang_tempcode('COUNT_VIEWS')), $sortables, 'sort', $sortable . ' ' . $sort_order); $fields = new ocp_tempcode(); $i = 0; while (array_key_exists($i, $rows)) { $row = $rows[$i]; $date = get_timezoned_date($row['date_and_time'], false); $week = round($row['date_and_time'] / (60 * 60 * 24 * 7)); $views = 0; while (array_key_exists($i + $views, $rows)) { $_week = round($row['date_and_time'] / (60 * 60 * 24 * 7)); if ($_week != $week) { break; } $views++; } $i += $views; if ($i < $start) { continue; } elseif ($i >= $start + $max) { break; } $fields->attach(results_entry(array($date, integer_format($views)), true)); } $list_views = results_table(do_lang_tempcode('PAGES_STATISTICS', escape_html($page)), $start, 'start_views', $max, 'max_views', $i, $fields_title, $fields, $sortables, $sortable, $sort_order, 'sort_views'); } breadcrumb_set_parents(array(array('_SELF:_SELF:misc', do_lang_tempcode('SITE_STATISTICS')))); return do_template('STATS_OVERVIEW_SCREEN', array('_GUID' => '71be91ba0d83368e1e1ceaf39e506610', 'TITLE' => $title, 'STATS_VIEWS' => $list_views, 'GRAPH_VIEWS_MONTHLY' => $graph_views_monthly, 'STATS_VIEWS_MONTHLY' => $list_views_monthly)); }
/** * Get an array of all the pages of the specified type (module, etc) and extension (for small sites everything will be returned, for larger ones it depends on the show method). * * @param ID_TEXT The zone name * @param ID_TEXT The type (including language, if appropriate) * @set modules modules_custom comcode/EN comcode_custom/EN html/EN html_custom/EN * @param string The file extension to limit us to (without a dot) * @param boolean Whether to leave file extensions on the page name * @param ?TIME Only show pages newer than (NULL: no restriction) * @param integer Selection algorithm constant * @set 0 1 2 * @param ?boolean Whether to search under the custom-file-base (NULL: auto-decide) * @return array A map of page name to type (modules_custom, etc) */ function _find_all_pages($zone, $type, $ext = 'php', $keep_ext_on = false, $cutoff_time = NULL, $show_method = 0, $custom = NULL) { $out = array(); $module_path = $zone == '' ? 'pages/' . filter_naughty($type) : filter_naughty($zone) . '/pages/' . filter_naughty($type); if (is_null($custom)) { $custom = strpos($type, 'comcode_custom') !== false || strpos($type, 'html_custom') !== false; if ($custom && get_custom_file_base() != get_file_base()) { $out = _find_all_pages($zone, $type, $ext, false, NULL, $show_method, false); } } $stub = $custom ? get_custom_file_base() : get_file_base(); $dh = @opendir($stub . '/' . $module_path); if ($dh !== false) { while (($file = readdir($dh)) !== false) { if (substr($file, -4) == '.' . $ext && file_exists($stub . '/' . $module_path . '/' . $file) && preg_match('#^[\\w\\-\\.]*$#', substr($file, 0, strlen($file) - 4)) != 0) { if (!is_null($cutoff_time)) { if (filectime($stub . '/' . $module_path . '/' . $file) < $cutoff_time) { continue; } } if ($ext == 'txt') { switch ($show_method) { case FIND_ALL_PAGES__NEWEST: // Only gets newest if it's a large site if (count($out) > 300) { $out = array(); $records = $GLOBALS['SITE_DB']->query_select('comcode_pages', array('the_page'), array('the_zone' => $zone), 'ORDER BY p_add_date DESC', 300); foreach ($records as $record) { $file = $record['the_page'] . '.txt'; if (!file_exists($stub . '/' . $module_path . '/' . $file)) { continue; } if (!is_null($cutoff_time)) { if (filectime($stub . '/' . $module_path . '/' . $file) < $cutoff_time) { continue; } } $out[$keep_ext_on ? $file : substr($file, 0, strlen($file) - 4)] = $type; } } else { break; } //break; Actually, no, let it roll on to the next one to get key files too //break; Actually, no, let it roll on to the next one to get key files too case FIND_ALL_PAGES__PERFORMANT: // Default, chooses selection carefully based on site size if ($show_method == FIND_ALL_PAGES__NEWEST || count($out) > 300) { if ($show_method != FIND_ALL_PAGES__NEWEST) { $out = array(); } $records = $GLOBALS['SITE_DB']->query('SELECT the_page FROM ' . get_table_prefix() . 'comcode_pages WHERE ' . db_string_equal_to('the_zone', $zone) . ' AND (' . db_string_equal_to('the_page', get_zone_default_page($zone)) . ' OR the_page LIKE \'' . db_encode_like('panel\\_%') . '\') ORDER BY p_add_date DESC'); foreach ($records as $record) { $file = $record['the_page'] . '.txt'; if (!file_exists($stub . '/' . $module_path . '/' . $file)) { continue; } if (!is_null($cutoff_time)) { if (filectime($stub . '/' . $module_path . '/' . $file) < $cutoff_time) { continue; } } $out[$keep_ext_on ? $file : substr($file, 0, strlen($file) - 4)] = $type; } break 2; } break; case FIND_ALL_PAGES__ALL: // Nothing special break; } } $out[$keep_ext_on ? $file : substr($file, 0, strlen($file) - 4)] = $type; } } closedir($dh); } if ($zone == '' && get_option('collapse_user_zones', true) === '1') { $out += _find_all_pages('site', $type, $ext, $keep_ext_on); } ksort($out); return $out; }