annotate forum/Sources/Stats.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
rev   line source
Chris@76 1 <?php
Chris@76 2
Chris@76 3 /**
Chris@76 4 * Simple Machines Forum (SMF)
Chris@76 5 *
Chris@76 6 * @package SMF
Chris@76 7 * @author Simple Machines http://www.simplemachines.org
Chris@76 8 * @copyright 2011 Simple Machines
Chris@76 9 * @license http://www.simplemachines.org/about/smf/license.php BSD
Chris@76 10 *
Chris@76 11 * @version 2.0
Chris@76 12 */
Chris@76 13
Chris@76 14 if (!defined('SMF'))
Chris@76 15 die('Hacking attempt...');
Chris@76 16
Chris@76 17 /* This function has only one job: providing a display for forum statistics.
Chris@76 18 As such, it has only one function:
Chris@76 19
Chris@76 20 void DisplayStats()
Chris@76 21 - gets all the statistics in order and puts them in.
Chris@76 22 - uses the Stats template and language file. (and main sub template.)
Chris@76 23 - requires the view_stats permission.
Chris@76 24 - accessed from ?action=stats.
Chris@76 25
Chris@76 26 void getDailyStats(string $condition)
Chris@76 27 - called by DisplayStats().
Chris@76 28 - loads the statistics on a daily basis in $context.
Chris@76 29
Chris@76 30 void SMStats()
Chris@76 31 - called by simplemachines.org.
Chris@76 32 - only returns anything if stats was enabled during installation.
Chris@76 33 - can also be accessed by the admin, to show what stats sm.org collects.
Chris@76 34 - does not return any data directly to sm.org, instead starts a new request for security.
Chris@76 35
Chris@76 36 */
Chris@76 37
Chris@76 38 // Display some useful/interesting board statistics.
Chris@76 39 function DisplayStats()
Chris@76 40 {
Chris@76 41 global $txt, $scripturl, $modSettings, $user_info, $context, $smcFunc;
Chris@76 42
Chris@76 43 isAllowedTo('view_stats');
Chris@76 44
Chris@76 45 if (!empty($_REQUEST['expand']))
Chris@76 46 {
Chris@76 47 $context['robot_no_index'] = true;
Chris@76 48
Chris@76 49 $month = (int) substr($_REQUEST['expand'], 4);
Chris@76 50 $year = (int) substr($_REQUEST['expand'], 0, 4);
Chris@76 51 if ($year > 1900 && $year < 2200 && $month >= 1 && $month <= 12)
Chris@76 52 $_SESSION['expanded_stats'][$year][] = $month;
Chris@76 53 }
Chris@76 54 elseif (!empty($_REQUEST['collapse']))
Chris@76 55 {
Chris@76 56 $context['robot_no_index'] = true;
Chris@76 57
Chris@76 58 $month = (int) substr($_REQUEST['collapse'], 4);
Chris@76 59 $year = (int) substr($_REQUEST['collapse'], 0, 4);
Chris@76 60 if (!empty($_SESSION['expanded_stats'][$year]))
Chris@76 61 $_SESSION['expanded_stats'][$year] = array_diff($_SESSION['expanded_stats'][$year], array($month));
Chris@76 62 }
Chris@76 63
Chris@76 64 // Handle the XMLHttpRequest.
Chris@76 65 if (isset($_REQUEST['xml']))
Chris@76 66 {
Chris@76 67 // Collapsing stats only needs adjustments of the session variables.
Chris@76 68 if (!empty($_REQUEST['collapse']))
Chris@76 69 obExit(false);
Chris@76 70
Chris@76 71 $context['sub_template'] = 'stats';
Chris@76 72 getDailyStats('YEAR(date) = {int:year} AND MONTH(date) = {int:month}', array('year' => $year, 'month' => $month));
Chris@76 73 $context['yearly'][$year]['months'][$month]['date'] = array(
Chris@76 74 'month' => sprintf('%02d', $month),
Chris@76 75 'year' => $year,
Chris@76 76 );
Chris@76 77 return;
Chris@76 78 }
Chris@76 79
Chris@76 80 loadLanguage('Stats');
Chris@76 81 loadTemplate('Stats');
Chris@76 82
Chris@76 83 // Build the link tree......
Chris@76 84 $context['linktree'][] = array(
Chris@76 85 'url' => $scripturl . '?action=stats',
Chris@76 86 'name' => $txt['stats_center']
Chris@76 87 );
Chris@76 88 $context['page_title'] = $context['forum_name'] . ' - ' . $txt['stats_center'];
Chris@76 89
Chris@76 90 $context['show_member_list'] = allowedTo('view_mlist');
Chris@76 91
Chris@76 92 // Get averages...
Chris@76 93 $result = $smcFunc['db_query']('', '
Chris@76 94 SELECT
Chris@76 95 SUM(posts) AS posts, SUM(topics) AS topics, SUM(registers) AS registers,
Chris@76 96 SUM(most_on) AS most_on, MIN(date) AS date, SUM(hits) AS hits
Chris@76 97 FROM {db_prefix}log_activity',
Chris@76 98 array(
Chris@76 99 )
Chris@76 100 );
Chris@76 101 $row = $smcFunc['db_fetch_assoc']($result);
Chris@76 102 $smcFunc['db_free_result']($result);
Chris@76 103
Chris@76 104 // This would be the amount of time the forum has been up... in days...
Chris@76 105 $total_days_up = ceil((time() - strtotime($row['date'])) / (60 * 60 * 24));
Chris@76 106
Chris@76 107 $context['average_posts'] = comma_format(round($row['posts'] / $total_days_up, 2));
Chris@76 108 $context['average_topics'] = comma_format(round($row['topics'] / $total_days_up, 2));
Chris@76 109 $context['average_members'] = comma_format(round($row['registers'] / $total_days_up, 2));
Chris@76 110 $context['average_online'] = comma_format(round($row['most_on'] / $total_days_up, 2));
Chris@76 111 $context['average_hits'] = comma_format(round($row['hits'] / $total_days_up, 2));
Chris@76 112
Chris@76 113 $context['num_hits'] = comma_format($row['hits'], 0);
Chris@76 114
Chris@76 115 // How many users are online now.
Chris@76 116 $result = $smcFunc['db_query']('', '
Chris@76 117 SELECT COUNT(*)
Chris@76 118 FROM {db_prefix}log_online',
Chris@76 119 array(
Chris@76 120 )
Chris@76 121 );
Chris@76 122 list ($context['users_online']) = $smcFunc['db_fetch_row']($result);
Chris@76 123 $smcFunc['db_free_result']($result);
Chris@76 124
Chris@76 125 // Statistics such as number of boards, categories, etc.
Chris@76 126 $result = $smcFunc['db_query']('', '
Chris@76 127 SELECT COUNT(*)
Chris@76 128 FROM {db_prefix}boards AS b
Chris@76 129 WHERE b.redirect = {string:blank_redirect}',
Chris@76 130 array(
Chris@76 131 'blank_redirect' => '',
Chris@76 132 )
Chris@76 133 );
Chris@76 134 list ($context['num_boards']) = $smcFunc['db_fetch_row']($result);
Chris@76 135 $smcFunc['db_free_result']($result);
Chris@76 136
Chris@76 137 $result = $smcFunc['db_query']('', '
Chris@76 138 SELECT COUNT(*)
Chris@76 139 FROM {db_prefix}categories AS c',
Chris@76 140 array(
Chris@76 141 )
Chris@76 142 );
Chris@76 143 list ($context['num_categories']) = $smcFunc['db_fetch_row']($result);
Chris@76 144 $smcFunc['db_free_result']($result);
Chris@76 145
Chris@76 146 // Format the numbers nicely.
Chris@76 147 $context['users_online'] = comma_format($context['users_online']);
Chris@76 148 $context['num_boards'] = comma_format($context['num_boards']);
Chris@76 149 $context['num_categories'] = comma_format($context['num_categories']);
Chris@76 150
Chris@76 151 $context['num_members'] = comma_format($modSettings['totalMembers']);
Chris@76 152 $context['num_posts'] = comma_format($modSettings['totalMessages']);
Chris@76 153 $context['num_topics'] = comma_format($modSettings['totalTopics']);
Chris@76 154 $context['most_members_online'] = array(
Chris@76 155 'number' => comma_format($modSettings['mostOnline']),
Chris@76 156 'date' => timeformat($modSettings['mostDate'])
Chris@76 157 );
Chris@76 158 $context['latest_member'] = &$context['common_stats']['latest_member'];
Chris@76 159
Chris@76 160 // Male vs. female ratio - let's calculate this only every four minutes.
Chris@76 161 if (($context['gender'] = cache_get_data('stats_gender', 240)) == null)
Chris@76 162 {
Chris@76 163 $result = $smcFunc['db_query']('', '
Chris@76 164 SELECT COUNT(*) AS total_members, gender
Chris@76 165 FROM {db_prefix}members
Chris@76 166 GROUP BY gender',
Chris@76 167 array(
Chris@76 168 )
Chris@76 169 );
Chris@76 170 $context['gender'] = array();
Chris@76 171 while ($row = $smcFunc['db_fetch_assoc']($result))
Chris@76 172 {
Chris@76 173 // Assuming we're telling... male or female?
Chris@76 174 if (!empty($row['gender']))
Chris@76 175 $context['gender'][$row['gender'] == 2 ? 'females' : 'males'] = $row['total_members'];
Chris@76 176 }
Chris@76 177 $smcFunc['db_free_result']($result);
Chris@76 178
Chris@76 179 // Set these two zero if the didn't get set at all.
Chris@76 180 if (empty($context['gender']['males']))
Chris@76 181 $context['gender']['males'] = 0;
Chris@76 182 if (empty($context['gender']['females']))
Chris@76 183 $context['gender']['females'] = 0;
Chris@76 184
Chris@76 185 // Try and come up with some "sensible" default states in case of a non-mixed board.
Chris@76 186 if ($context['gender']['males'] == $context['gender']['females'])
Chris@76 187 $context['gender']['ratio'] = '1:1';
Chris@76 188 elseif ($context['gender']['males'] == 0)
Chris@76 189 $context['gender']['ratio'] = '0:1';
Chris@76 190 elseif ($context['gender']['females'] == 0)
Chris@76 191 $context['gender']['ratio'] = '1:0';
Chris@76 192 elseif ($context['gender']['males'] > $context['gender']['females'])
Chris@76 193 $context['gender']['ratio'] = round($context['gender']['males'] / $context['gender']['females'], 1) . ':1';
Chris@76 194 elseif ($context['gender']['females'] > $context['gender']['males'])
Chris@76 195 $context['gender']['ratio'] = '1:' . round($context['gender']['females'] / $context['gender']['males'], 1);
Chris@76 196
Chris@76 197 cache_put_data('stats_gender', $context['gender'], 240);
Chris@76 198 }
Chris@76 199
Chris@76 200 $date = strftime('%Y-%m-%d', forum_time(false));
Chris@76 201
Chris@76 202 // Members online so far today.
Chris@76 203 $result = $smcFunc['db_query']('', '
Chris@76 204 SELECT most_on
Chris@76 205 FROM {db_prefix}log_activity
Chris@76 206 WHERE date = {date:today_date}
Chris@76 207 LIMIT 1',
Chris@76 208 array(
Chris@76 209 'today_date' => $date,
Chris@76 210 )
Chris@76 211 );
Chris@76 212 list ($context['online_today']) = $smcFunc['db_fetch_row']($result);
Chris@76 213 $smcFunc['db_free_result']($result);
Chris@76 214
Chris@76 215 $context['online_today'] = comma_format((int) $context['online_today']);
Chris@76 216
Chris@76 217 // Poster top 10.
Chris@76 218 $members_result = $smcFunc['db_query']('', '
Chris@76 219 SELECT id_member, real_name, posts
Chris@76 220 FROM {db_prefix}members
Chris@76 221 WHERE posts > {int:no_posts}
Chris@76 222 ORDER BY posts DESC
Chris@76 223 LIMIT 10',
Chris@76 224 array(
Chris@76 225 'no_posts' => 0,
Chris@76 226 )
Chris@76 227 );
Chris@76 228 $context['top_posters'] = array();
Chris@76 229 $max_num_posts = 1;
Chris@76 230 while ($row_members = $smcFunc['db_fetch_assoc']($members_result))
Chris@76 231 {
Chris@76 232 $context['top_posters'][] = array(
Chris@76 233 'name' => $row_members['real_name'],
Chris@76 234 'id' => $row_members['id_member'],
Chris@76 235 'num_posts' => $row_members['posts'],
Chris@76 236 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'],
Chris@76 237 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>'
Chris@76 238 );
Chris@76 239
Chris@76 240 if ($max_num_posts < $row_members['posts'])
Chris@76 241 $max_num_posts = $row_members['posts'];
Chris@76 242 }
Chris@76 243 $smcFunc['db_free_result']($members_result);
Chris@76 244
Chris@76 245 foreach ($context['top_posters'] as $i => $poster)
Chris@76 246 {
Chris@76 247 $context['top_posters'][$i]['post_percent'] = round(($poster['num_posts'] * 100) / $max_num_posts);
Chris@76 248 $context['top_posters'][$i]['num_posts'] = comma_format($context['top_posters'][$i]['num_posts']);
Chris@76 249 }
Chris@76 250
Chris@76 251 // Board top 10.
Chris@76 252 $boards_result = $smcFunc['db_query']('', '
Chris@76 253 SELECT id_board, name, num_posts
Chris@76 254 FROM {db_prefix}boards AS b
Chris@76 255 WHERE {query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
Chris@76 256 AND b.id_board != {int:recycle_board}' : '') . '
Chris@76 257 AND b.redirect = {string:blank_redirect}
Chris@76 258 ORDER BY num_posts DESC
Chris@76 259 LIMIT 10',
Chris@76 260 array(
Chris@76 261 'recycle_board' => $modSettings['recycle_board'],
Chris@76 262 'blank_redirect' => '',
Chris@76 263 )
Chris@76 264 );
Chris@76 265 $context['top_boards'] = array();
Chris@76 266 $max_num_posts = 1;
Chris@76 267 while ($row_board = $smcFunc['db_fetch_assoc']($boards_result))
Chris@76 268 {
Chris@76 269 $context['top_boards'][] = array(
Chris@76 270 'id' => $row_board['id_board'],
Chris@76 271 'name' => $row_board['name'],
Chris@76 272 'num_posts' => $row_board['num_posts'],
Chris@76 273 'href' => $scripturl . '?board=' . $row_board['id_board'] . '.0',
Chris@76 274 'link' => '<a href="' . $scripturl . '?board=' . $row_board['id_board'] . '.0">' . $row_board['name'] . '</a>'
Chris@76 275 );
Chris@76 276
Chris@76 277 if ($max_num_posts < $row_board['num_posts'])
Chris@76 278 $max_num_posts = $row_board['num_posts'];
Chris@76 279 }
Chris@76 280 $smcFunc['db_free_result']($boards_result);
Chris@76 281
Chris@76 282 foreach ($context['top_boards'] as $i => $board)
Chris@76 283 {
Chris@76 284 $context['top_boards'][$i]['post_percent'] = round(($board['num_posts'] * 100) / $max_num_posts);
Chris@76 285 $context['top_boards'][$i]['num_posts'] = comma_format($context['top_boards'][$i]['num_posts']);
Chris@76 286 }
Chris@76 287
Chris@76 288 // Are you on a larger forum? If so, let's try to limit the number of topics we search through.
Chris@76 289 if ($modSettings['totalMessages'] > 100000)
Chris@76 290 {
Chris@76 291 $request = $smcFunc['db_query']('', '
Chris@76 292 SELECT id_topic
Chris@76 293 FROM {db_prefix}topics
Chris@76 294 WHERE num_replies != {int:no_replies}' . ($modSettings['postmod_active'] ? '
Chris@76 295 AND approved = {int:is_approved}' : '') . '
Chris@76 296 ORDER BY num_replies DESC
Chris@76 297 LIMIT 100',
Chris@76 298 array(
Chris@76 299 'no_replies' => 0,
Chris@76 300 'is_approved' => 1,
Chris@76 301 )
Chris@76 302 );
Chris@76 303 $topic_ids = array();
Chris@76 304 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 305 $topic_ids[] = $row['id_topic'];
Chris@76 306 $smcFunc['db_free_result']($request);
Chris@76 307 }
Chris@76 308 else
Chris@76 309 $topic_ids = array();
Chris@76 310
Chris@76 311 // Topic replies top 10.
Chris@76 312 $topic_reply_result = $smcFunc['db_query']('', '
Chris@76 313 SELECT m.subject, t.num_replies, t.id_board, t.id_topic, b.name
Chris@76 314 FROM {db_prefix}topics AS t
Chris@76 315 INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
Chris@76 316 INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
Chris@76 317 AND b.id_board != {int:recycle_board}' : '') . ')
Chris@76 318 WHERE {query_see_board}' . (!empty($topic_ids) ? '
Chris@76 319 AND t.id_topic IN ({array_int:topic_list})' : ($modSettings['postmod_active'] ? '
Chris@76 320 AND t.approved = {int:is_approved}' : '')) . '
Chris@76 321 ORDER BY t.num_replies DESC
Chris@76 322 LIMIT 10',
Chris@76 323 array(
Chris@76 324 'topic_list' => $topic_ids,
Chris@76 325 'recycle_board' => $modSettings['recycle_board'],
Chris@76 326 'is_approved' => 1,
Chris@76 327 )
Chris@76 328 );
Chris@76 329 $context['top_topics_replies'] = array();
Chris@76 330 $max_num_replies = 1;
Chris@76 331 while ($row_topic_reply = $smcFunc['db_fetch_assoc']($topic_reply_result))
Chris@76 332 {
Chris@76 333 censorText($row_topic_reply['subject']);
Chris@76 334
Chris@76 335 $context['top_topics_replies'][] = array(
Chris@76 336 'id' => $row_topic_reply['id_topic'],
Chris@76 337 'board' => array(
Chris@76 338 'id' => $row_topic_reply['id_board'],
Chris@76 339 'name' => $row_topic_reply['name'],
Chris@76 340 'href' => $scripturl . '?board=' . $row_topic_reply['id_board'] . '.0',
Chris@76 341 'link' => '<a href="' . $scripturl . '?board=' . $row_topic_reply['id_board'] . '.0">' . $row_topic_reply['name'] . '</a>'
Chris@76 342 ),
Chris@76 343 'subject' => $row_topic_reply['subject'],
Chris@76 344 'num_replies' => $row_topic_reply['num_replies'],
Chris@76 345 'href' => $scripturl . '?topic=' . $row_topic_reply['id_topic'] . '.0',
Chris@76 346 'link' => '<a href="' . $scripturl . '?topic=' . $row_topic_reply['id_topic'] . '.0">' . $row_topic_reply['subject'] . '</a>'
Chris@76 347 );
Chris@76 348
Chris@76 349 if ($max_num_replies < $row_topic_reply['num_replies'])
Chris@76 350 $max_num_replies = $row_topic_reply['num_replies'];
Chris@76 351 }
Chris@76 352 $smcFunc['db_free_result']($topic_reply_result);
Chris@76 353
Chris@76 354 foreach ($context['top_topics_replies'] as $i => $topic)
Chris@76 355 {
Chris@76 356 $context['top_topics_replies'][$i]['post_percent'] = round(($topic['num_replies'] * 100) / $max_num_replies);
Chris@76 357 $context['top_topics_replies'][$i]['num_replies'] = comma_format($context['top_topics_replies'][$i]['num_replies']);
Chris@76 358 }
Chris@76 359
Chris@76 360 // Large forums may need a bit more prodding...
Chris@76 361 if ($modSettings['totalMessages'] > 100000)
Chris@76 362 {
Chris@76 363 $request = $smcFunc['db_query']('', '
Chris@76 364 SELECT id_topic
Chris@76 365 FROM {db_prefix}topics
Chris@76 366 WHERE num_views != {int:no_views}
Chris@76 367 ORDER BY num_views DESC
Chris@76 368 LIMIT 100',
Chris@76 369 array(
Chris@76 370 'no_views' => 0,
Chris@76 371 )
Chris@76 372 );
Chris@76 373 $topic_ids = array();
Chris@76 374 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 375 $topic_ids[] = $row['id_topic'];
Chris@76 376 $smcFunc['db_free_result']($request);
Chris@76 377 }
Chris@76 378 else
Chris@76 379 $topic_ids = array();
Chris@76 380
Chris@76 381 // Topic views top 10.
Chris@76 382 $topic_view_result = $smcFunc['db_query']('', '
Chris@76 383 SELECT m.subject, t.num_views, t.id_board, t.id_topic, b.name
Chris@76 384 FROM {db_prefix}topics AS t
Chris@76 385 INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
Chris@76 386 INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
Chris@76 387 AND b.id_board != {int:recycle_board}' : '') . ')
Chris@76 388 WHERE {query_see_board}' . (!empty($topic_ids) ? '
Chris@76 389 AND t.id_topic IN ({array_int:topic_list})' : ($modSettings['postmod_active'] ? '
Chris@76 390 AND t.approved = {int:is_approved}' : '')) . '
Chris@76 391 ORDER BY t.num_views DESC
Chris@76 392 LIMIT 10',
Chris@76 393 array(
Chris@76 394 'topic_list' => $topic_ids,
Chris@76 395 'recycle_board' => $modSettings['recycle_board'],
Chris@76 396 'is_approved' => 1,
Chris@76 397 )
Chris@76 398 );
Chris@76 399 $context['top_topics_views'] = array();
Chris@76 400 $max_num_views = 1;
Chris@76 401 while ($row_topic_views = $smcFunc['db_fetch_assoc']($topic_view_result))
Chris@76 402 {
Chris@76 403 censorText($row_topic_views['subject']);
Chris@76 404
Chris@76 405 $context['top_topics_views'][] = array(
Chris@76 406 'id' => $row_topic_views['id_topic'],
Chris@76 407 'board' => array(
Chris@76 408 'id' => $row_topic_views['id_board'],
Chris@76 409 'name' => $row_topic_views['name'],
Chris@76 410 'href' => $scripturl . '?board=' . $row_topic_views['id_board'] . '.0',
Chris@76 411 'link' => '<a href="' . $scripturl . '?board=' . $row_topic_views['id_board'] . '.0">' . $row_topic_views['name'] . '</a>'
Chris@76 412 ),
Chris@76 413 'subject' => $row_topic_views['subject'],
Chris@76 414 'num_views' => $row_topic_views['num_views'],
Chris@76 415 'href' => $scripturl . '?topic=' . $row_topic_views['id_topic'] . '.0',
Chris@76 416 'link' => '<a href="' . $scripturl . '?topic=' . $row_topic_views['id_topic'] . '.0">' . $row_topic_views['subject'] . '</a>'
Chris@76 417 );
Chris@76 418
Chris@76 419 if ($max_num_views < $row_topic_views['num_views'])
Chris@76 420 $max_num_views = $row_topic_views['num_views'];
Chris@76 421 }
Chris@76 422 $smcFunc['db_free_result']($topic_view_result);
Chris@76 423
Chris@76 424 foreach ($context['top_topics_views'] as $i => $topic)
Chris@76 425 {
Chris@76 426 $context['top_topics_views'][$i]['post_percent'] = round(($topic['num_views'] * 100) / $max_num_views);
Chris@76 427 $context['top_topics_views'][$i]['num_views'] = comma_format($context['top_topics_views'][$i]['num_views']);
Chris@76 428 }
Chris@76 429
Chris@76 430 // Try to cache this when possible, because it's a little unavoidably slow.
Chris@76 431 if (($members = cache_get_data('stats_top_starters', 360)) == null)
Chris@76 432 {
Chris@76 433 $request = $smcFunc['db_query']('', '
Chris@76 434 SELECT id_member_started, COUNT(*) AS hits
Chris@76 435 FROM {db_prefix}topics' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
Chris@76 436 WHERE id_board != {int:recycle_board}' : '') . '
Chris@76 437 GROUP BY id_member_started
Chris@76 438 ORDER BY hits DESC
Chris@76 439 LIMIT 20',
Chris@76 440 array(
Chris@76 441 'recycle_board' => $modSettings['recycle_board'],
Chris@76 442 )
Chris@76 443 );
Chris@76 444 $members = array();
Chris@76 445 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 446 $members[$row['id_member_started']] = $row['hits'];
Chris@76 447 $smcFunc['db_free_result']($request);
Chris@76 448
Chris@76 449 cache_put_data('stats_top_starters', $members, 360);
Chris@76 450 }
Chris@76 451
Chris@76 452 if (empty($members))
Chris@76 453 $members = array(0 => 0);
Chris@76 454
Chris@76 455 // Topic poster top 10.
Chris@76 456 $members_result = $smcFunc['db_query']('top_topic_starters', '
Chris@76 457 SELECT id_member, real_name
Chris@76 458 FROM {db_prefix}members
Chris@76 459 WHERE id_member IN ({array_int:member_list})
Chris@76 460 ORDER BY FIND_IN_SET(id_member, {string:top_topic_posters})
Chris@76 461 LIMIT 10',
Chris@76 462 array(
Chris@76 463 'member_list' => array_keys($members),
Chris@76 464 'top_topic_posters' => implode(',', array_keys($members)),
Chris@76 465 )
Chris@76 466 );
Chris@76 467 $context['top_starters'] = array();
Chris@76 468 $max_num_topics = 1;
Chris@76 469 while ($row_members = $smcFunc['db_fetch_assoc']($members_result))
Chris@76 470 {
Chris@76 471 $context['top_starters'][] = array(
Chris@76 472 'name' => $row_members['real_name'],
Chris@76 473 'id' => $row_members['id_member'],
Chris@76 474 'num_topics' => $members[$row_members['id_member']],
Chris@76 475 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'],
Chris@76 476 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>'
Chris@76 477 );
Chris@76 478
Chris@76 479 if ($max_num_topics < $members[$row_members['id_member']])
Chris@76 480 $max_num_topics = $members[$row_members['id_member']];
Chris@76 481 }
Chris@76 482 $smcFunc['db_free_result']($members_result);
Chris@76 483
Chris@76 484 foreach ($context['top_starters'] as $i => $topic)
Chris@76 485 {
Chris@76 486 $context['top_starters'][$i]['post_percent'] = round(($topic['num_topics'] * 100) / $max_num_topics);
Chris@76 487 $context['top_starters'][$i]['num_topics'] = comma_format($context['top_starters'][$i]['num_topics']);
Chris@76 488 }
Chris@76 489
Chris@76 490 // Time online top 10.
Chris@76 491 $temp = cache_get_data('stats_total_time_members', 600);
Chris@76 492 $members_result = $smcFunc['db_query']('', '
Chris@76 493 SELECT id_member, real_name, total_time_logged_in
Chris@76 494 FROM {db_prefix}members' . (!empty($temp) ? '
Chris@76 495 WHERE id_member IN ({array_int:member_list_cached})' : '') . '
Chris@76 496 ORDER BY total_time_logged_in DESC
Chris@76 497 LIMIT 20',
Chris@76 498 array(
Chris@76 499 'member_list_cached' => $temp,
Chris@76 500 )
Chris@76 501 );
Chris@76 502 $context['top_time_online'] = array();
Chris@76 503 $temp2 = array();
Chris@76 504 $max_time_online = 1;
Chris@76 505 while ($row_members = $smcFunc['db_fetch_assoc']($members_result))
Chris@76 506 {
Chris@76 507 $temp2[] = (int) $row_members['id_member'];
Chris@76 508 if (count($context['top_time_online']) >= 10)
Chris@76 509 continue;
Chris@76 510
Chris@76 511 // Figure out the days, hours and minutes.
Chris@76 512 $timeDays = floor($row_members['total_time_logged_in'] / 86400);
Chris@76 513 $timeHours = floor(($row_members['total_time_logged_in'] % 86400) / 3600);
Chris@76 514
Chris@76 515 // Figure out which things to show... (days, hours, minutes, etc.)
Chris@76 516 $timelogged = '';
Chris@76 517 if ($timeDays > 0)
Chris@76 518 $timelogged .= $timeDays . $txt['totalTimeLogged5'];
Chris@76 519 if ($timeHours > 0)
Chris@76 520 $timelogged .= $timeHours . $txt['totalTimeLogged6'];
Chris@76 521 $timelogged .= floor(($row_members['total_time_logged_in'] % 3600) / 60) . $txt['totalTimeLogged7'];
Chris@76 522
Chris@76 523 $context['top_time_online'][] = array(
Chris@76 524 'id' => $row_members['id_member'],
Chris@76 525 'name' => $row_members['real_name'],
Chris@76 526 'time_online' => $timelogged,
Chris@76 527 'seconds_online' => $row_members['total_time_logged_in'],
Chris@76 528 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'],
Chris@76 529 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>'
Chris@76 530 );
Chris@76 531
Chris@76 532 if ($max_time_online < $row_members['total_time_logged_in'])
Chris@76 533 $max_time_online = $row_members['total_time_logged_in'];
Chris@76 534 }
Chris@76 535 $smcFunc['db_free_result']($members_result);
Chris@76 536
Chris@76 537 foreach ($context['top_time_online'] as $i => $member)
Chris@76 538 $context['top_time_online'][$i]['time_percent'] = round(($member['seconds_online'] * 100) / $max_time_online);
Chris@76 539
Chris@76 540 // Cache the ones we found for a bit, just so we don't have to look again.
Chris@76 541 if ($temp !== $temp2)
Chris@76 542 cache_put_data('stats_total_time_members', $temp2, 480);
Chris@76 543
Chris@76 544 // Activity by month.
Chris@76 545 $months_result = $smcFunc['db_query']('', '
Chris@76 546 SELECT
Chris@76 547 YEAR(date) AS stats_year, MONTH(date) AS stats_month, SUM(hits) AS hits, SUM(registers) AS registers, SUM(topics) AS topics, SUM(posts) AS posts, MAX(most_on) AS most_on, COUNT(*) AS num_days
Chris@76 548 FROM {db_prefix}log_activity
Chris@76 549 GROUP BY stats_year, stats_month',
Chris@76 550 array()
Chris@76 551 );
Chris@76 552
Chris@76 553 $context['yearly'] = array();
Chris@76 554 while ($row_months = $smcFunc['db_fetch_assoc']($months_result))
Chris@76 555 {
Chris@76 556 $ID_MONTH = $row_months['stats_year'] . sprintf('%02d', $row_months['stats_month']);
Chris@76 557 $expanded = !empty($_SESSION['expanded_stats'][$row_months['stats_year']]) && in_array($row_months['stats_month'], $_SESSION['expanded_stats'][$row_months['stats_year']]);
Chris@76 558
Chris@76 559 if (!isset($context['yearly'][$row_months['stats_year']]))
Chris@76 560 $context['yearly'][$row_months['stats_year']] = array(
Chris@76 561 'year' => $row_months['stats_year'],
Chris@76 562 'new_topics' => 0,
Chris@76 563 'new_posts' => 0,
Chris@76 564 'new_members' => 0,
Chris@76 565 'most_members_online' => 0,
Chris@76 566 'hits' => 0,
Chris@76 567 'num_months' => 0,
Chris@76 568 'months' => array(),
Chris@76 569 'expanded' => false,
Chris@76 570 'current_year' => $row_months['stats_year'] == date('Y'),
Chris@76 571 );
Chris@76 572
Chris@76 573 $context['yearly'][$row_months['stats_year']]['months'][(int) $row_months['stats_month']] = array(
Chris@76 574 'id' => $ID_MONTH,
Chris@76 575 'date' => array(
Chris@76 576 'month' => sprintf('%02d', $row_months['stats_month']),
Chris@76 577 'year' => $row_months['stats_year']
Chris@76 578 ),
Chris@76 579 'href' => $scripturl . '?action=stats;' . ($expanded ? 'collapse' : 'expand') . '=' . $ID_MONTH . '#m' . $ID_MONTH,
Chris@76 580 'link' => '<a href="' . $scripturl . '?action=stats;' . ($expanded ? 'collapse' : 'expand') . '=' . $ID_MONTH . '#m' . $ID_MONTH . '">' . $txt['months'][(int) $row_months['stats_month']] . ' ' . $row_months['stats_year'] . '</a>',
Chris@76 581 'month' => $txt['months'][(int) $row_months['stats_month']],
Chris@76 582 'year' => $row_months['stats_year'],
Chris@76 583 'new_topics' => comma_format($row_months['topics']),
Chris@76 584 'new_posts' => comma_format($row_months['posts']),
Chris@76 585 'new_members' => comma_format($row_months['registers']),
Chris@76 586 'most_members_online' => comma_format($row_months['most_on']),
Chris@76 587 'hits' => comma_format($row_months['hits']),
Chris@76 588 'num_days' => $row_months['num_days'],
Chris@76 589 'days' => array(),
Chris@76 590 'expanded' => $expanded
Chris@76 591 );
Chris@76 592
Chris@76 593 $context['yearly'][$row_months['stats_year']]['new_topics'] += $row_months['topics'];
Chris@76 594 $context['yearly'][$row_months['stats_year']]['new_posts'] += $row_months['posts'];
Chris@76 595 $context['yearly'][$row_months['stats_year']]['new_members'] += $row_months['registers'];
Chris@76 596 $context['yearly'][$row_months['stats_year']]['hits'] += $row_months['hits'];
Chris@76 597 $context['yearly'][$row_months['stats_year']]['num_months']++;
Chris@76 598 $context['yearly'][$row_months['stats_year']]['expanded'] |= $expanded;
Chris@76 599 $context['yearly'][$row_months['stats_year']]['most_members_online'] = max($context['yearly'][$row_months['stats_year']]['most_members_online'], $row_months['most_on']);
Chris@76 600 }
Chris@76 601
Chris@76 602 krsort($context['yearly']);
Chris@76 603
Chris@76 604 $context['collapsed_years'] = array();
Chris@76 605 foreach ($context['yearly'] as $year => $data)
Chris@76 606 {
Chris@76 607 // This gets rid of the filesort on the query ;).
Chris@76 608 krsort($context['yearly'][$year]['months']);
Chris@76 609
Chris@76 610 $context['yearly'][$year]['new_topics'] = comma_format($data['new_topics']);
Chris@76 611 $context['yearly'][$year]['new_posts'] = comma_format($data['new_posts']);
Chris@76 612 $context['yearly'][$year]['new_members'] = comma_format($data['new_members']);
Chris@76 613 $context['yearly'][$year]['most_members_online'] = comma_format($data['most_members_online']);
Chris@76 614 $context['yearly'][$year]['hits'] = comma_format($data['hits']);
Chris@76 615
Chris@76 616 // Keep a list of collapsed years.
Chris@76 617 if (!$data['expanded'] && !$data['current_year'])
Chris@76 618 $context['collapsed_years'][] = $year;
Chris@76 619 }
Chris@76 620
Chris@76 621 if (empty($_SESSION['expanded_stats']))
Chris@76 622 return;
Chris@76 623
Chris@76 624 $condition_text = array();
Chris@76 625 $condition_params = array();
Chris@76 626 foreach ($_SESSION['expanded_stats'] as $year => $months)
Chris@76 627 if (!empty($months))
Chris@76 628 {
Chris@76 629 $condition_text[] = 'YEAR(date) = {int:year_' . $year . '} AND MONTH(date) IN ({array_int:months_' . $year . '})';
Chris@76 630 $condition_params['year_' . $year] = $year;
Chris@76 631 $condition_params['months_' . $year] = $months;
Chris@76 632 }
Chris@76 633
Chris@76 634 // No daily stats to even look at?
Chris@76 635 if (empty($condition_text))
Chris@76 636 return;
Chris@76 637
Chris@76 638 getDailyStats(implode(' OR ', $condition_text), $condition_params);
Chris@76 639 }
Chris@76 640
Chris@76 641 function getDailyStats($condition_string, $condition_parameters = array())
Chris@76 642 {
Chris@76 643 global $context, $smcFunc;
Chris@76 644
Chris@76 645 // Activity by day.
Chris@76 646 $days_result = $smcFunc['db_query']('', '
Chris@76 647 SELECT YEAR(date) AS stats_year, MONTH(date) AS stats_month, DAYOFMONTH(date) AS stats_day, topics, posts, registers, most_on, hits
Chris@76 648 FROM {db_prefix}log_activity
Chris@76 649 WHERE ' . $condition_string . '
Chris@76 650 ORDER BY stats_day ASC',
Chris@76 651 $condition_parameters
Chris@76 652 );
Chris@76 653 while ($row_days = $smcFunc['db_fetch_assoc']($days_result))
Chris@76 654 $context['yearly'][$row_days['stats_year']]['months'][(int) $row_days['stats_month']]['days'][] = array(
Chris@76 655 'day' => sprintf('%02d', $row_days['stats_day']),
Chris@76 656 'month' => sprintf('%02d', $row_days['stats_month']),
Chris@76 657 'year' => $row_days['stats_year'],
Chris@76 658 'new_topics' => comma_format($row_days['topics']),
Chris@76 659 'new_posts' => comma_format($row_days['posts']),
Chris@76 660 'new_members' => comma_format($row_days['registers']),
Chris@76 661 'most_members_online' => comma_format($row_days['most_on']),
Chris@76 662 'hits' => comma_format($row_days['hits'])
Chris@76 663 );
Chris@76 664 $smcFunc['db_free_result']($days_result);
Chris@76 665 }
Chris@76 666
Chris@76 667 // This is the function which returns stats to simplemachines.org IF enabled!
Chris@76 668 // See http://www.simplemachines.org/about/stats.php for more info.
Chris@76 669 function SMStats()
Chris@76 670 {
Chris@76 671 global $modSettings, $user_info, $forum_version, $sourcedir;
Chris@76 672
Chris@76 673 // First, is it disabled?
Chris@76 674 if (empty($modSettings['allow_sm_stats']))
Chris@76 675 die();
Chris@76 676
Chris@76 677 // Are we saying who we are, and are we right? (OR an admin)
Chris@76 678 if (!$user_info['is_admin'] && (!isset($_GET['sid']) || $_GET['sid'] != $modSettings['allow_sm_stats']))
Chris@76 679 die();
Chris@76 680
Chris@76 681 // Verify the referer...
Chris@76 682 if (!$user_info['is_admin'] && (!isset($_SERVER['HTTP_REFERER']) || md5($_SERVER['HTTP_REFERER']) != '746cb59a1a0d5cf4bd240e5a67c73085'))
Chris@76 683 die();
Chris@76 684
Chris@76 685 // Get some server versions.
Chris@76 686 require_once($sourcedir . '/Subs-Admin.php');
Chris@76 687 $checkFor = array(
Chris@76 688 'php',
Chris@76 689 'db_server',
Chris@76 690 );
Chris@76 691 $serverVersions = getServerVersions($checkFor);
Chris@76 692
Chris@76 693 // Get the actual stats.
Chris@76 694 $stats_to_send = array(
Chris@76 695 'UID' => $modSettings['allow_sm_stats'],
Chris@76 696 'time_added' => time(),
Chris@76 697 'members' => $modSettings['totalMembers'],
Chris@76 698 'messages' => $modSettings['totalMessages'],
Chris@76 699 'topics' => $modSettings['totalTopics'],
Chris@76 700 'boards' => 0,
Chris@76 701 'php_version' => $serverVersions['php']['version'],
Chris@76 702 'database_type' => strtolower($serverVersions['db_server']['title']),
Chris@76 703 'database_version' => $serverVersions['db_server']['version'],
Chris@76 704 'smf_version' => $forum_version,
Chris@76 705 'smfd_version' => $modSettings['smfVersion'],
Chris@76 706 );
Chris@76 707
Chris@76 708 // Encode all the data, for security.
Chris@76 709 foreach ($stats_to_send as $k => $v)
Chris@76 710 $stats_to_send[$k] = urlencode($k) . '=' . urlencode($v);
Chris@76 711
Chris@76 712 // Turn this into the query string!
Chris@76 713 $stats_to_send = implode('&', $stats_to_send);
Chris@76 714
Chris@76 715 // If we're an admin, just plonk them out.
Chris@76 716 if ($user_info['is_admin'])
Chris@76 717 echo $stats_to_send;
Chris@76 718 else
Chris@76 719 {
Chris@76 720 // Connect to the collection script.
Chris@76 721 $fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
Chris@76 722 if ($fp)
Chris@76 723 {
Chris@76 724 $length = strlen($stats_to_send);
Chris@76 725
Chris@76 726 $out = 'POST /smf/stats/collect_stats.php HTTP/1.1' . "\r\n";
Chris@76 727 $out .= 'Host: www.simplemachines.org' . "\r\n";
Chris@76 728 $out .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
Chris@76 729 $out .= 'Content-Length: ' . $length . "\r\n\r\n";
Chris@76 730 $out .= $stats_to_send . "\r\n";
Chris@76 731 $out .= 'Connection: Close' . "\r\n\r\n";
Chris@76 732 fwrite($fp, $out);
Chris@76 733 fclose($fp);
Chris@76 734 }
Chris@76 735 }
Chris@76 736
Chris@76 737 // Die.
Chris@76 738 die('OK');
Chris@76 739 }
Chris@76 740
Chris@76 741 ?>