/** * Standard modular run function for realtime-rain hooks. * * @param TIME Start of time range. * @param TIME End of time range. * @return array A list of template parameter sets for rendering a 'drop'. */ function run($from, $to) { $drops = array(); if (has_actual_page_access(get_member(), 'admin_stats')) { require_lang('stats'); $rows = $GLOBALS['SITE_DB']->query('SELECT browser,referer,the_page,ip,the_user AS member_id,date_and_time AS timestamp FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE date_and_time BETWEEN ' . strval($from) . ' AND ' . strval($to)); foreach ($rows as $row) { $timestamp = $row['timestamp']; $member_id = $row['member_id']; $page_link = str_replace(':', ': ', page_path_to_pagelink($row['the_page'])); if ($row['the_page'] == '/access_denied') { $page_link = do_lang('ACCESS_DENIED_SCREEN'); } if ($row['the_page'] == '/closed') { $page_link = do_lang('CLOSED_SITE_SCREEN'); } if ($row['the_page'] == '/flood') { $page_link = do_lang('FLOOD_CONTROL_SCREEN'); } $title = rain_truncate_for_title(do_lang('HIT', $page_link)); // Show referer domain or Google search keyword $referer = @parse_url($row['referer']); $base_url = @parse_url(get_base_url()); if ($referer !== false) { if (!array_key_exists('host', $referer)) { $referer['host'] = do_lang('UNKNOWN'); } if ($referer['host'] != $base_url['host']) { $matches = array(); if (preg_match('#(&|\\?)q=([^&]*)#', $row['referer'], $matches) != 0) { $title = rain_truncate_for_title(do_lang('HIT', $page_link, $matches[2], $referer['host'])); } else { $title = rain_truncate_for_title(do_lang('HIT', $page_link, $referer['host'])); } } } $drops[] = rain_get_special_icons($row['ip'], $timestamp, $row['browser']) + array('TYPE' => 'stats', 'FROM_MEMBER_ID' => strval($member_id), 'TO_MEMBER_ID' => NULL, 'TITLE' => $title, 'IMAGE' => is_guest($member_id) ? rain_get_country_image($row['ip']) : $GLOBALS['FORUM_DRIVER']->get_member_avatar_url($member_id), 'TIMESTAMP' => strval($timestamp), 'RELATIVE_TIMESTAMP' => strval($timestamp - $from), 'TICKER_TEXT' => NULL, 'URL' => build_url(array('page' => 'admin_lookup', 'id' => $row['ip']), '_SEARCH'), 'IS_POSITIVE' => false, 'IS_NEGATIVE' => false, 'FROM_ID' => 'member_' . strval($member_id), 'TO_ID' => NULL, 'GROUP_ID' => 'page_' . $page_link); } } return $drops; }
/** * The UI to show page view statistics. * * @return tempcode The UI */ function page_stats() { //This will show a plain bar chart with all the pages listed // Handle time range if (get_param_integer('dated', 0) == 0) { $title = get_page_title('PAGES_STATISTICS'); return $this->get_between($title, true); } $time_start = get_input_date('time_start', true); $time_end = get_input_date('time_end', true); if (!is_null($time_end)) { $time_end += 60 * 60 * 24 - 1; } // So it is end of day not start if (is_null($time_start)) { $time_start = 0; } if (is_null($time_end)) { $time_end = time(); } $first_stat = $GLOBALS['SITE_DB']->query_value_null_ok('stats', 'MIN(date_and_time)'); if ($time_end < $first_stat) { warn_exit(do_lang_tempcode('NO_DATA_SPECIFIC')); } $start = get_param_integer('start', 0); $max = get_param_integer('max', 30); $csv = get_param_integer('csv', 0) == 1; if ($csv) { if (function_exists('set_time_limit')) { @set_time_limit(0); } $start = 0; $max = 10000; /*$time_start=0; Actually, this is annoying. We have legitimate reason to filter, and cannot re-filter the data in Excel retro-actively $time_end=time();*/ } $title = get_page_title('PAGES_STATISTICS_RANGE', true, array(escape_html(get_timezoned_date($time_start, false)), escape_html(get_timezoned_date($time_end, false)))); $rows = $GLOBALS['SITE_DB']->query_select('stats', array('the_page'), NULL, 'GROUP BY the_page ORDER BY COUNT(*) DESC', 3000); if (count($rows) < 1) { return warn_screen($title, do_lang_tempcode('NO_DATA')); } $views = array(do_lang('_ALL') => 0); $total = 0; foreach ($rows as $row) { $page = $row['the_page']; $matches = array(); if (preg_match('#^/?([^/]+)/pages/([^/]+)/(\\w\\w/)?([^/\\.]+)\\.(php|txt|htm)$#', $page, $matches) == 1 && $matches[4] == 'catalogues' && addon_installed('catalogues') && $GLOBALS['SITE_DB']->query_value('catalogue_categories', 'COUNT(*)', NULL, '', true) < 300) { require_lang('catalogues'); $categories = $GLOBALS['SITE_DB']->query_select('catalogue_categories', array('id', 'cc_title'), NULL, '', NULL, NULL, true); foreach ($categories as $cat) { $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 $count = $GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE (' . $where . ') AND s_get LIKE \'' . db_encode_like('<param>page=catalogues</param>\\n<param>type=category</param>\\n<param>id=' . strval($cat['id']) . '</param>%') . '\' AND date_and_time>' . strval((int) $time_start) . ' AND date_and_time<' . strval((int) $time_end)); $views[do_lang('CATALOGUE_CATEGORY') . ': ' . get_translated_text($cat['cc_title'])] = array($count, $page); $total += $count; } continue; } else { $page2 = page_path_to_pagelink($page); if ($page2 == '') { $page2 = $page; } } $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 $views[$page2] = array($GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE (' . $where . ') AND date_and_time>' . strval((int) $time_start) . ' AND date_and_time<' . strval((int) $time_end)), $page); $total += $views[$page2][0]; } $views[do_lang('_ALL')] = array($total, NULL); $sortables = array('views' => do_lang_tempcode('COUNT_VIEWS')); $test = explode(' ', get_param('sort', 'views DESC'), 2); if (count($test) == 1) { $test[1] = 'DESC'; } list($sortable, $sort_order) = $test; 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'; global $M_SORT_KEY; $M_SORT_KEY = 0; uasort($views, 'multi_sort'); if ($sort_order == 'DESC') { $views = array_reverse($views, true); } require_code('templates_results_table'); $fields_title = results_field_title(array(do_lang_tempcode('URL'), do_lang_tempcode('COUNT_VIEWS')), $sortables, 'sort', $sortable . ' ' . $sort_order); $fields = new ocp_tempcode(); $i = 0; $real_data = array(); foreach ($views as $url => $_value) { if ($i < $start) { $i++; continue; } elseif ($i >= $start + $max) { break; } list($value, $page) = $_value; $real_data[] = array('Page/URL' => is_null($page) ? $url : $page, 'Tally' => $value); $fields->attach(results_entry(array(is_null($page) ? make_string_tempcode(escape_html($url)) : hyperlink(build_url(array('page' => '_SELF', 'type' => '_page', 'iscreen' => $page), '_SELF'), escape_html($url)), escape_html(integer_format($value))))); $i++; } unset($views['(' . do_lang('ALL') . ')']); $list = results_table(do_lang_tempcode('PAGES_STATISTICS'), $start, 'start', $max, 'max', count($views), $fields_title, $fields, $sortables, $sortable, $sort_order, 'sort', new ocp_tempcode()); if ($csv) { make_csv($real_data, 'page_stats.csv'); } $output = create_bar_chart(array_slice($views, $start, $max), do_lang('PAGE'), do_lang('COUNT_VIEWS'), '', ''); $this->save_graph('Global-Views', $output); $graph = do_template('STATS_GRAPH', array('_GUID' => 'ea79fdc013046ef94992daeab961f2da', 'GRAPH' => get_custom_base_url() . '/data_custom/modules/admin_stats/Global-Views.xml', 'TITLE' => do_lang_tempcode('PAGES_STATISTICS'), 'TEXT' => do_lang_tempcode('DESCRIPTION_PAGES_STATISTICS'))); breadcrumb_set_parents(array(array('_SELF:_SELF:misc', do_lang_tempcode('SITE_STATISTICS')))); return do_template('STATS_SCREEN', array('_GUID' => 'cfe7d5aee8aa3c0d3a54bd3bf2d09e7f', 'TITLE' => $title, 'GRAPH' => $graph, 'STATS' => $list)); }