Modlog.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0
  11. */
  12. if (!defined('SMF'))
  13. die('Hacking attempt...');
  14. /* The moderation log is this file's only job. It views it, and that's about
  15. all it does.
  16. void ViewModlog()
  17. - prepares the information from the moderation log for viewing.
  18. - disallows the deletion of events within twenty-four hours of now.
  19. - requires the admin_forum permission.
  20. - uses the Modlog template, main sub template.
  21. - is accessed via ?action=moderate;area=modlog.
  22. int list_getModLogEntries()
  23. //!!!
  24. array list_getModLogEntries($start, $items_per_page, $sort, $query_string = '', $query_params = array(), $log_type = 1)
  25. - Gets the moderation log entries that match the specified paramaters
  26. - limit can be an array with two values
  27. - search_param and order should be proper SQL strings or blank. If blank they are not used.
  28. */
  29. // Show the moderation log
  30. function ViewModlog()
  31. {
  32. global $txt, $modSettings, $context, $scripturl, $sourcedir, $user_info, $smcFunc, $settings;
  33. // Are we looking at the moderation log or the administration log.
  34. $context['log_type'] = isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'adminlog' ? 3 : 1;
  35. if ($context['log_type'] == 3)
  36. isAllowedTo('admin_forum');
  37. // These change dependant on whether we are viewing the moderation or admin log.
  38. if ($context['log_type'] == 3 || $_REQUEST['action'] == 'admin')
  39. $context['url_start'] = '?action=admin;area=logs;sa=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . ';type=' . $context['log_type'];
  40. else
  41. $context['url_start'] = '?action=moderate;area=modlog;type=' . $context['log_type'];
  42. $context['can_delete'] = allowedTo('admin_forum');
  43. loadLanguage('Modlog');
  44. $context['page_title'] = $context['log_type'] == 3 ? $txt['modlog_admin_log'] : $txt['modlog_view'];
  45. // The number of entries to show per page of log file.
  46. $context['displaypage'] = 30;
  47. // Amount of hours that must pass before allowed to delete file.
  48. $context['hoursdisable'] = 24;
  49. // Handle deletion...
  50. if (isset($_POST['removeall']) && $context['can_delete'])
  51. {
  52. checkSession();
  53. $smcFunc['db_query']('', '
  54. DELETE FROM {db_prefix}log_actions
  55. WHERE id_log = {int:moderate_log}
  56. AND log_time < {int:twenty_four_hours_wait}',
  57. array(
  58. 'twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600,
  59. 'moderate_log' => $context['log_type'],
  60. )
  61. );
  62. }
  63. elseif (!empty($_POST['remove']) && isset($_POST['delete']) && $context['can_delete'])
  64. {
  65. checkSession();
  66. $smcFunc['db_query']('', '
  67. DELETE FROM {db_prefix}log_actions
  68. WHERE id_log = {int:moderate_log}
  69. AND id_action IN ({array_string:delete_actions})
  70. AND log_time < {int:twenty_four_hours_wait}',
  71. array(
  72. 'twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600,
  73. 'delete_actions' => array_unique($_POST['delete']),
  74. 'moderate_log' => $context['log_type'],
  75. )
  76. );
  77. }
  78. // Do the column stuff!
  79. $sort_types = array(
  80. 'action' =>'lm.action',
  81. 'time' => 'lm.log_time',
  82. 'member' => 'mem.real_name',
  83. 'group' => 'mg.group_name',
  84. 'ip' => 'lm.ip',
  85. );
  86. // Setup the direction stuff...
  87. $context['order'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $_REQUEST['sort'] : 'time';
  88. // If we're coming from a search, get the variables.
  89. if (!empty($_REQUEST['params']) && empty($_REQUEST['is_search']))
  90. {
  91. $search_params = base64_decode(strtr($_REQUEST['params'], array(' ' => '+')));
  92. $search_params = @unserialize($search_params);
  93. }
  94. // This array houses all the valid search types.
  95. $searchTypes = array(
  96. 'action' => array('sql' => 'lm.action', 'label' => $txt['modlog_action']),
  97. 'member' => array('sql' => 'mem.real_name', 'label' => $txt['modlog_member']),
  98. 'group' => array('sql' => 'mg.group_name', 'label' => $txt['modlog_position']),
  99. 'ip' => array('sql' => 'lm.ip', 'label' => $txt['modlog_ip'])
  100. );
  101. if (!isset($search_params['string']) || (!empty($_REQUEST['search']) && $search_params['string'] != $_REQUEST['search']))
  102. $search_params_string = empty($_REQUEST['search']) ? '' : $_REQUEST['search'];
  103. else
  104. $search_params_string = $search_params['string'];
  105. if (isset($_REQUEST['search_type']) || empty($search_params['type']) || !isset($searchTypes[$search_params['type']]))
  106. $search_params_type = isset($_REQUEST['search_type']) && isset($searchTypes[$_REQUEST['search_type']]) ? $_REQUEST['search_type'] : (isset($searchTypes[$context['order']]) ? $context['order'] : 'member');
  107. else
  108. $search_params_type = $search_params['type'];
  109. $search_params_column = $searchTypes[$search_params_type]['sql'];
  110. $search_params = array(
  111. 'string' => $search_params_string,
  112. 'type' => $search_params_type,
  113. );
  114. // Setup the search context.
  115. $context['search_params'] = empty($search_params['string']) ? '' : base64_encode(serialize($search_params));
  116. $context['search'] = array(
  117. 'string' => $search_params['string'],
  118. 'type' => $search_params['type'],
  119. 'label' => $searchTypes[$search_params_type]['label'],
  120. );
  121. // If they are searching by action, then we must do some manual intervention to search in their language!
  122. if ($search_params['type'] == 'action' && !empty($search_params['string']))
  123. {
  124. // For the moment they can only search for ONE action!
  125. foreach ($txt as $key => $text)
  126. {
  127. if (substr($key, 0, 10) == 'modlog_ac_' && strpos($text, $search_params['string']) !== false)
  128. {
  129. $search_params['string'] = substr($key, 10);
  130. break;
  131. }
  132. }
  133. }
  134. require_once($sourcedir . '/Subs-List.php');
  135. // This is all the information required for a watched user listing.
  136. $listOptions = array(
  137. 'id' => 'moderation_log_list',
  138. 'title' => '<a href="' . $scripturl . '?action=helpadmin;help=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . '" onclick="return reqWin(this.href);" class="help"><img src="' . $settings['images_url'] . '/helptopics.gif" alt="' . $txt['help'] . '" align="top" /></a> ' . $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log'],
  139. 'width' => '100%',
  140. 'items_per_page' => $context['displaypage'],
  141. 'no_items_label' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin_log_' : '') . 'no_entries_found'],
  142. 'base_href' => $scripturl . $context['url_start'] . (!empty($context['search_params']) ? ';params=' . $context['search_params'] : ''),
  143. 'default_sort_col' => 'time',
  144. 'get_items' => array(
  145. 'function' => 'list_getModLogEntries',
  146. 'params' => array(
  147. (!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''),
  148. array('sql_type' => $search_params_column, 'search_string' => $search_params['string']),
  149. $context['log_type'],
  150. ),
  151. ),
  152. 'get_count' => array(
  153. 'function' => 'list_getModLogEntryCount',
  154. 'params' => array(
  155. (!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''),
  156. array('sql_type' => $search_params_column, 'search_string' => $search_params['string']),
  157. $context['log_type'],
  158. ),
  159. ),
  160. // This assumes we are viewing by user.
  161. 'columns' => array(
  162. 'action' => array(
  163. 'header' => array(
  164. 'value' => $txt['modlog_action'],
  165. 'class' => 'lefttext first_th',
  166. ),
  167. 'data' => array(
  168. 'db' => 'action_text',
  169. 'class' => 'smalltext',
  170. ),
  171. 'sort' => array(
  172. 'default' => 'lm.action',
  173. 'reverse' => 'lm.action DESC',
  174. ),
  175. ),
  176. 'time' => array(
  177. 'header' => array(
  178. 'value' => $txt['modlog_date'],
  179. 'class' => 'lefttext',
  180. ),
  181. 'data' => array(
  182. 'db' => 'time',
  183. 'class' => 'smalltext',
  184. ),
  185. 'sort' => array(
  186. 'default' => 'lm.log_time DESC',
  187. 'reverse' => 'lm.log_time',
  188. ),
  189. ),
  190. 'moderator' => array(
  191. 'header' => array(
  192. 'value' => $txt['modlog_member'],
  193. 'class' => 'lefttext',
  194. ),
  195. 'data' => array(
  196. 'db' => 'moderator_link',
  197. 'class' => 'smalltext',
  198. ),
  199. 'sort' => array(
  200. 'default' => 'mem.real_name',
  201. 'reverse' => 'mem.real_name DESC',
  202. ),
  203. ),
  204. 'position' => array(
  205. 'header' => array(
  206. 'value' => $txt['modlog_position'],
  207. 'class' => 'lefttext',
  208. ),
  209. 'data' => array(
  210. 'db' => 'position',
  211. 'class' => 'smalltext',
  212. ),
  213. 'sort' => array(
  214. 'default' => 'mg.group_name',
  215. 'reverse' => 'mg.group_name DESC',
  216. ),
  217. ),
  218. 'ip' => array(
  219. 'header' => array(
  220. 'value' => $txt['modlog_ip'],
  221. 'class' => 'lefttext',
  222. ),
  223. 'data' => array(
  224. 'db' => 'ip',
  225. 'class' => 'smalltext',
  226. ),
  227. 'sort' => array(
  228. 'default' => 'lm.ip',
  229. 'reverse' => 'lm.ip DESC',
  230. ),
  231. ),
  232. 'delete' => array(
  233. 'header' => array(
  234. 'value' => '<input type="checkbox" name="all" class="input_check" onclick="invertAll(this, this.form);" />',
  235. ),
  236. 'data' => array(
  237. 'function' => create_function('$entry', '
  238. return \'<input type="checkbox" class="input_check" name="delete[]" value="\' . $entry[\'id\'] . \'"\' . ($entry[\'editable\'] ? \'\' : \' disabled="disabled"\') . \' />\';
  239. '),
  240. 'style' => 'text-align: center;',
  241. ),
  242. ),
  243. ),
  244. 'form' => array(
  245. 'href' => $scripturl . $context['url_start'],
  246. 'include_sort' => true,
  247. 'include_start' => true,
  248. 'hidden_fields' => array(
  249. $context['session_var'] => $context['session_id'],
  250. 'params' => $context['search_params']
  251. ),
  252. ),
  253. 'additional_rows' => array(
  254. array(
  255. 'position' => 'after_title',
  256. 'value' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log_desc'],
  257. 'class' => 'smalltext',
  258. 'style' => 'padding: 2ex;',
  259. ),
  260. array(
  261. 'position' => 'below_table_data',
  262. 'value' => '
  263. ' . $txt['modlog_search'] . ' (' . $txt['modlog_by'] . ': ' . $context['search']['label'] . '):
  264. <input type="text" name="search" size="18" value="' . $context['search']['string'] . '" class="input_text" /> <input type="submit" name="is_search" value="' . $txt['modlog_go'] . '" class="button_submit" />
  265. ' . ($context['can_delete'] ? ' |
  266. <input type="submit" name="remove" value="' . $txt['modlog_remove'] . '" class="button_submit" />
  267. <input type="submit" name="removeall" value="' . $txt['modlog_removeall'] . '" class="button_submit" />' : ''),
  268. ),
  269. ),
  270. );
  271. // Create the watched user list.
  272. createList($listOptions);
  273. $context['sub_template'] = 'show_list';
  274. $context['default_list'] = 'moderation_log_list';
  275. }
  276. // Get the number of mod log entries.
  277. function list_getModLogEntryCount($query_string = '', $query_params = array(), $log_type = 1)
  278. {
  279. global $smcFunc, $user_info;
  280. $modlog_query = allowedTo('admin_forum') || $user_info['mod_cache']['bq'] == '1=1' ? '1=1' : ($user_info['mod_cache']['bq'] == '0=1' ? 'lm.id_board = 0 AND lm.id_topic = 0' : (strtr($user_info['mod_cache']['bq'], array('id_board' => 'b.id_board')) . ' AND ' . strtr($user_info['mod_cache']['bq'], array('id_board' => 't.id_board'))));
  281. $result = $smcFunc['db_query']('', '
  282. SELECT COUNT(*)
  283. FROM {db_prefix}log_actions AS lm
  284. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lm.id_member)
  285. LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END)
  286. LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lm.id_board)
  287. LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lm.id_topic)
  288. WHERE id_log = {int:log_type}
  289. AND {raw:modlog_query}'
  290. . (!empty($query_string) ? '
  291. AND ' . $query_string : ''),
  292. array_merge($query_params, array(
  293. 'reg_group_id' => 0,
  294. 'log_type' => $log_type,
  295. 'modlog_query' => $modlog_query,
  296. ))
  297. );
  298. list ($entry_count) = $smcFunc['db_fetch_row']($result);
  299. $smcFunc['db_free_result']($result);
  300. return $entry_count;
  301. }
  302. function list_getModLogEntries($start, $items_per_page, $sort, $query_string = '', $query_params = array(), $log_type = 1)
  303. {
  304. global $context, $scripturl, $txt, $smcFunc, $user_info;
  305. $modlog_query = allowedTo('admin_forum') || $user_info['mod_cache']['bq'] == '1=1' ? '1=1' : ($user_info['mod_cache']['bq'] == '0=1' ? 'lm.id_board = 0 AND lm.id_topic = 0' : (strtr($user_info['mod_cache']['bq'], array('id_board' => 'b.id_board')) . ' AND ' . strtr($user_info['mod_cache']['bq'], array('id_board' => 't.id_board'))));
  306. // Do a little bit of self protection.
  307. if (!isset($context['hoursdisable']))
  308. $context['hoursdisable'] = 24;
  309. // Can they see the IP address?
  310. $seeIP = allowedTo('moderate_forum');
  311. // Here we have the query getting the log details.
  312. $result = $smcFunc['db_query']('', '
  313. SELECT
  314. lm.id_action, lm.id_member, lm.ip, lm.log_time, lm.action, lm.id_board, lm.id_topic, lm.id_msg, lm.extra,
  315. mem.real_name, mg.group_name
  316. FROM {db_prefix}log_actions AS lm
  317. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lm.id_member)
  318. LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END)
  319. LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lm.id_board)
  320. LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lm.id_topic)
  321. WHERE id_log = {int:log_type}
  322. AND {raw:modlog_query}'
  323. . (!empty($query_string) ? '
  324. AND ' . $query_string : '') . '
  325. ORDER BY ' . $sort . '
  326. LIMIT ' . $start . ', ' . $items_per_page,
  327. array_merge($query_params, array(
  328. 'reg_group_id' => 0,
  329. 'log_type' => $log_type,
  330. 'modlog_query' => $modlog_query,
  331. ))
  332. );
  333. // Arrays for decoding objects into.
  334. $topics = array();
  335. $boards = array();
  336. $members = array();
  337. $messages = array();
  338. $entries = array();
  339. while ($row = $smcFunc['db_fetch_assoc']($result))
  340. {
  341. $row['extra'] = @unserialize($row['extra']);
  342. // Corrupt?
  343. $row['extra'] = is_array($row['extra']) ? $row['extra'] : array();
  344. // Add on some of the column stuff info
  345. if (!empty($row['id_board']))
  346. {
  347. if ($row['action'] == 'move')
  348. $row['extra']['board_to'] = $row['id_board'];
  349. else
  350. $row['extra']['board'] = $row['id_board'];
  351. }
  352. if (!empty($row['id_topic']))
  353. $row['extra']['topic'] = $row['id_topic'];
  354. if (!empty($row['id_msg']))
  355. $row['extra']['message'] = $row['id_msg'];
  356. // Is this associated with a topic?
  357. if (isset($row['extra']['topic']))
  358. $topics[(int) $row['extra']['topic']][] = $row['id_action'];
  359. if (isset($row['extra']['new_topic']))
  360. $topics[(int) $row['extra']['new_topic']][] = $row['id_action'];
  361. // How about a member?
  362. if (isset($row['extra']['member']))
  363. {
  364. // Guests don't have names!
  365. if (empty($row['extra']['member']))
  366. $row['extra']['member'] = $txt['modlog_parameter_guest'];
  367. else
  368. {
  369. // Try to find it...
  370. $members[(int) $row['extra']['member']][] = $row['id_action'];
  371. }
  372. }
  373. // Associated with a board?
  374. if (isset($row['extra']['board_to']))
  375. $boards[(int) $row['extra']['board_to']][] = $row['id_action'];
  376. if (isset($row['extra']['board_from']))
  377. $boards[(int) $row['extra']['board_from']][] = $row['id_action'];
  378. if (isset($row['extra']['board']))
  379. $boards[(int) $row['extra']['board']][] = $row['id_action'];
  380. // A message?
  381. if (isset($row['extra']['message']))
  382. $messages[(int) $row['extra']['message']][] = $row['id_action'];
  383. // IP Info?
  384. if (isset($row['extra']['ip_range']))
  385. if ($seeIP)
  386. $row['extra']['ip_range'] = '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['extra']['ip_range'] . '">' . $row['extra']['ip_range'] . '</a>';
  387. else
  388. $row['extra']['ip_range'] = $txt['logged'];
  389. // Email?
  390. if (isset($row['extra']['email']))
  391. $row['extra']['email'] = '<a href="mailto:' . $row['extra']['email'] . '">' . $row['extra']['email'] . '</a>';
  392. // Bans are complex.
  393. if ($row['action'] == 'ban')
  394. {
  395. $row['action_text'] = $txt['modlog_ac_ban'];
  396. foreach (array('member', 'email', 'ip_range', 'hostname') as $type)
  397. if (isset($row['extra'][$type]))
  398. $row['action_text'] .= $txt['modlog_ac_ban_trigger_' . $type];
  399. }
  400. // The array to go to the template. Note here that action is set to a "default" value of the action doesn't match anything in the descriptions. Allows easy adding of logging events with basic details.
  401. $entries[$row['id_action']] = array(
  402. 'id' => $row['id_action'],
  403. 'ip' => $seeIP ? $row['ip'] : $txt['logged'],
  404. 'position' => empty($row['real_name']) && empty($row['group_name']) ? $txt['guest'] : $row['group_name'],
  405. 'moderator_link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' : (empty($row['real_name']) ? ($txt['guest'] . (!empty($row['extra']['member_acted']) ? ' (' . $row['extra']['member_acted'] . ')' : '')) : $row['real_name']),
  406. 'time' => timeformat($row['log_time']),
  407. 'timestamp' => forum_time(true, $row['log_time']),
  408. 'editable' => time() > $row['log_time'] + $context['hoursdisable'] * 3600,
  409. 'extra' => $row['extra'],
  410. 'action' => $row['action'],
  411. 'action_text' => isset($row['action_text']) ? $row['action_text'] : '',
  412. );
  413. }
  414. $smcFunc['db_free_result']($result);
  415. if (!empty($boards))
  416. {
  417. $request = $smcFunc['db_query']('', '
  418. SELECT id_board, name
  419. FROM {db_prefix}boards
  420. WHERE id_board IN ({array_int:board_list})
  421. LIMIT ' . count(array_keys($boards)),
  422. array(
  423. 'board_list' => array_keys($boards),
  424. )
  425. );
  426. while ($row = $smcFunc['db_fetch_assoc']($request))
  427. {
  428. foreach ($boards[$row['id_board']] as $action)
  429. {
  430. // Make the board number into a link - dealing with moving too.
  431. if (isset($entries[$action]['extra']['board_to']) && $entries[$action]['extra']['board_to'] == $row['id_board'])
  432. $entries[$action]['extra']['board_to'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
  433. elseif (isset($entries[$action]['extra']['board_from']) && $entries[$action]['extra']['board_from'] == $row['id_board'])
  434. $entries[$action]['extra']['board_from'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
  435. elseif (isset($entries[$action]['extra']['board']) && $entries[$action]['extra']['board'] == $row['id_board'])
  436. $entries[$action]['extra']['board'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>';
  437. }
  438. }
  439. $smcFunc['db_free_result']($request);
  440. }
  441. if (!empty($topics))
  442. {
  443. $request = $smcFunc['db_query']('', '
  444. SELECT ms.subject, t.id_topic
  445. FROM {db_prefix}topics AS t
  446. INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)
  447. WHERE t.id_topic IN ({array_int:topic_list})
  448. LIMIT ' . count(array_keys($topics)),
  449. array(
  450. 'topic_list' => array_keys($topics),
  451. )
  452. );
  453. while ($row = $smcFunc['db_fetch_assoc']($request))
  454. {
  455. foreach ($topics[$row['id_topic']] as $action)
  456. {
  457. $this_action = &$entries[$action];
  458. // This isn't used in the current theme.
  459. $this_action['topic'] = array(
  460. 'id' => $row['id_topic'],
  461. 'subject' => $row['subject'],
  462. 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  463. 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>'
  464. );
  465. // Make the topic number into a link - dealing with splitting too.
  466. if (isset($this_action['extra']['topic']) && $this_action['extra']['topic'] == $row['id_topic'])
  467. $this_action['extra']['topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>';
  468. elseif (isset($this_action['extra']['new_topic']) && $this_action['extra']['new_topic'] == $row['id_topic'])
  469. $this_action['extra']['new_topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>';
  470. }
  471. }
  472. $smcFunc['db_free_result']($request);
  473. }
  474. if (!empty($messages))
  475. {
  476. $request = $smcFunc['db_query']('', '
  477. SELECT id_msg, subject
  478. FROM {db_prefix}messages
  479. WHERE id_msg IN ({array_int:message_list})
  480. LIMIT ' . count(array_keys($messages)),
  481. array(
  482. 'message_list' => array_keys($messages),
  483. )
  484. );
  485. while ($row = $smcFunc['db_fetch_assoc']($request))
  486. {
  487. foreach ($messages[$row['id_msg']] as $action)
  488. {
  489. $this_action = &$entries[$action];
  490. // This isn't used in the current theme.
  491. $this_action['message'] = array(
  492. 'id' => $row['id_msg'],
  493. 'subject' => $row['subject'],
  494. 'href' => $scripturl . '?msg=' . $row['id_msg'],
  495. 'link' => '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>',
  496. );
  497. // Make the message number into a link.
  498. if (isset($this_action['extra']['message']) && $this_action['extra']['message'] == $row['id_msg'])
  499. $this_action['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>';
  500. }
  501. }
  502. $smcFunc['db_free_result']($request);
  503. }
  504. if (!empty($members))
  505. {
  506. $request = $smcFunc['db_query']('', '
  507. SELECT real_name, id_member
  508. FROM {db_prefix}members
  509. WHERE id_member IN ({array_int:member_list})
  510. LIMIT ' . count(array_keys($members)),
  511. array(
  512. 'member_list' => array_keys($members),
  513. )
  514. );
  515. while ($row = $smcFunc['db_fetch_assoc']($request))
  516. {
  517. foreach ($members[$row['id_member']] as $action)
  518. {
  519. // Not used currently.
  520. $entries[$action]['member'] = array(
  521. 'id' => $row['id_member'],
  522. 'name' => $row['real_name'],
  523. 'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
  524. 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'
  525. );
  526. // Make the member number into a name.
  527. $entries[$action]['extra']['member'] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
  528. }
  529. }
  530. $smcFunc['db_free_result']($request);
  531. }
  532. // Do some formatting of the action string.
  533. foreach ($entries as $k => $entry)
  534. {
  535. // Make any message info links so its easier to go find that message.
  536. if (isset($entry['extra']['message']) && (empty($entry['message']) || empty($entry['message']['id'])))
  537. $entries[$k]['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $entry['extra']['message'] . '">' . $entry['extra']['message'] . '</a>';
  538. // Mark up any deleted members, topics and boards.
  539. foreach (array('board', 'board_from', 'board_to', 'member', 'topic', 'new_topic') as $type)
  540. if (!empty($entry['extra'][$type]) && is_numeric($entry['extra'][$type]))
  541. $entries[$k]['extra'][$type] = sprintf($txt['modlog_id'], $entry['extra'][$type]);
  542. if (empty($entries[$k]['action_text']))
  543. $entries[$k]['action_text'] = isset($txt['modlog_ac_' . $entry['action']]) ? $txt['modlog_ac_' . $entry['action']] : $entry['action'];
  544. $entries[$k]['action_text'] = preg_replace('~\{([A-Za-z\d_]+)\}~ie', 'isset($entries[$k][\'extra\'][\'$1\']) ? $entries[$k][\'extra\'][\'$1\'] : \'\'', $entries[$k]['action_text']);
  545. }
  546. // Back we go!
  547. return $entries;
  548. }
  549. ?>