ManageBans.php 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790
  1. <?php
  2. /**
  3. * This file contains all the functions used for the ban center.
  4. * @todo refactor as controller-model
  5. *
  6. * Simple Machines Forum (SMF)
  7. *
  8. * @package SMF
  9. * @author Simple Machines http://www.simplemachines.org
  10. * @copyright 2011 Simple Machines
  11. * @license http://www.simplemachines.org/about/smf/license.php BSD
  12. *
  13. * @version 2.0
  14. */
  15. if (!defined('SMF'))
  16. die('Hacking attempt...');
  17. /**
  18. * Ban center. The main entrance point for all ban center functions.
  19. * It is accesssed by ?action=admin;area=ban.
  20. * It choses a function based on the 'sa' parameter, like many others.
  21. * The default sub-action is BanList().
  22. * It requires the ban_members permission.
  23. * It initializes the admin tabs.
  24. *
  25. * @uses ManageBans template.
  26. */
  27. function Ban()
  28. {
  29. global $context, $txt, $scripturl;
  30. isAllowedTo('manage_bans');
  31. loadTemplate('ManageBans');
  32. $subActions = array(
  33. 'add' => 'BanEdit',
  34. 'browse' => 'BanBrowseTriggers',
  35. 'edittrigger' => 'BanEditTrigger',
  36. 'edit' => 'BanEdit',
  37. 'list' => 'BanList',
  38. 'log' => 'BanLog',
  39. );
  40. // Default the sub-action to 'view ban list'.
  41. $_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'list';
  42. $context['page_title'] = $txt['ban_title'];
  43. $context['sub_action'] = $_REQUEST['sa'];
  44. // Tabs for browsing the different ban functions.
  45. $context[$context['admin_menu_name']]['tab_data'] = array(
  46. 'title' => $txt['ban_title'],
  47. 'help' => 'ban_members',
  48. 'description' => $txt['ban_description'],
  49. 'tabs' => array(
  50. 'list' => array(
  51. 'description' => $txt['ban_description'],
  52. 'href' => $scripturl . '?action=admin;area=ban;sa=list',
  53. 'is_selected' => $_REQUEST['sa'] == 'list' || $_REQUEST['sa'] == 'edit' || $_REQUEST['sa'] == 'edittrigger',
  54. ),
  55. 'add' => array(
  56. 'description' => $txt['ban_description'],
  57. 'href' => $scripturl . '?action=admin;area=ban;sa=add',
  58. 'is_selected' => $_REQUEST['sa'] == 'add',
  59. ),
  60. 'browse' => array(
  61. 'description' => $txt['ban_trigger_browse_description'],
  62. 'href' => $scripturl . '?action=admin;area=ban;sa=browse',
  63. 'is_selected' => $_REQUEST['sa'] == 'browse',
  64. ),
  65. 'log' => array(
  66. 'description' => $txt['ban_log_description'],
  67. 'href' => $scripturl . '?action=admin;area=ban;sa=log',
  68. 'is_selected' => $_REQUEST['sa'] == 'log',
  69. 'is_last' => true,
  70. ),
  71. ),
  72. );
  73. // Call the right function for this sub-acton.
  74. $subActions[$_REQUEST['sa']]();
  75. }
  76. /**
  77. * Shows a list of bans currently set.
  78. * It is accesssed by ?action=admin;area=ban;sa=list.
  79. * It removes expired bans.
  80. * It allows sorting on different criteria.
  81. * It also handles removal of selected ban items.
  82. *
  83. * @uses the main ManageBans template.
  84. */
  85. function BanList()
  86. {
  87. global $txt, $context, $ban_request, $ban_counts, $scripturl;
  88. global $user_info, $smcFunc, $sourcedir;
  89. // User pressed the 'remove selection button'.
  90. if (!empty($_POST['removeBans']) && !empty($_POST['remove']) && is_array($_POST['remove']))
  91. {
  92. checkSession();
  93. // Make sure every entry is a proper integer.
  94. foreach ($_POST['remove'] as $index => $ban_id)
  95. $_POST['remove'][(int) $index] = (int) $ban_id;
  96. // Unban them all!
  97. $smcFunc['db_query']('', '
  98. DELETE FROM {db_prefix}ban_groups
  99. WHERE id_ban_group IN ({array_int:ban_list})',
  100. array(
  101. 'ban_list' => $_POST['remove'],
  102. )
  103. );
  104. $smcFunc['db_query']('', '
  105. DELETE FROM {db_prefix}ban_items
  106. WHERE id_ban_group IN ({array_int:ban_list})',
  107. array(
  108. 'ban_list' => $_POST['remove'],
  109. )
  110. );
  111. // No more caching this ban!
  112. updateSettings(array('banLastUpdated' => time()));
  113. // Some members might be unbanned now. Update the members table.
  114. updateBanMembers();
  115. }
  116. // Create a date string so we don't overload them with date info.
  117. if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
  118. $context['ban_time_format'] = $user_info['time_format'];
  119. else
  120. $context['ban_time_format'] = $matches[0];
  121. $listOptions = array(
  122. 'id' => 'ban_list',
  123. 'items_per_page' => 20,
  124. 'base_href' => $scripturl . '?action=admin;area=ban;sa=list',
  125. 'default_sort_col' => 'added',
  126. 'default_sort_dir' => 'desc',
  127. 'get_items' => array(
  128. 'function' => 'list_getBans',
  129. ),
  130. 'get_count' => array(
  131. 'function' => 'list_getNumBans',
  132. ),
  133. 'no_items_label' => $txt['ban_no_entries'],
  134. 'columns' => array(
  135. 'name' => array(
  136. 'header' => array(
  137. 'value' => $txt['ban_name'],
  138. ),
  139. 'data' => array(
  140. 'db' => 'name',
  141. ),
  142. 'sort' => array(
  143. 'default' => 'bg.name',
  144. 'reverse' => 'bg.name DESC',
  145. ),
  146. ),
  147. 'notes' => array(
  148. 'header' => array(
  149. 'value' => $txt['ban_notes'],
  150. ),
  151. 'data' => array(
  152. 'db' => 'notes',
  153. 'class' => 'smalltext',
  154. ),
  155. 'sort' => array(
  156. 'default' => 'LENGTH(bg.notes) > 0 DESC, bg.notes',
  157. 'reverse' => 'LENGTH(bg.notes) > 0, bg.notes DESC',
  158. ),
  159. ),
  160. 'reason' => array(
  161. 'header' => array(
  162. 'value' => $txt['ban_reason'],
  163. ),
  164. 'data' => array(
  165. 'db' => 'reason',
  166. 'class' => 'smalltext',
  167. ),
  168. 'sort' => array(
  169. 'default' => 'LENGTH(bg.reason) > 0 DESC, bg.reason',
  170. 'reverse' => 'LENGTH(bg.reason) > 0, bg.reason DESC',
  171. ),
  172. ),
  173. 'added' => array(
  174. 'header' => array(
  175. 'value' => $txt['ban_added'],
  176. ),
  177. 'data' => array(
  178. 'function' => create_function('$rowData', '
  179. global $context;
  180. return timeformat($rowData[\'ban_time\'], empty($context[\'ban_time_format\']) ? true : $context[\'ban_time_format\']);
  181. '),
  182. ),
  183. 'sort' => array(
  184. 'default' => 'bg.ban_time',
  185. 'reverse' => 'bg.ban_time DESC',
  186. ),
  187. ),
  188. 'expires' => array(
  189. 'header' => array(
  190. 'value' => $txt['ban_expires'],
  191. ),
  192. 'data' => array(
  193. 'function' => create_function('$rowData', '
  194. global $txt;
  195. // This ban never expires...whahaha.
  196. if ($rowData[\'expire_time\'] === null)
  197. return $txt[\'never\'];
  198. // This ban has already expired.
  199. elseif ($rowData[\'expire_time\'] < time())
  200. return sprintf(\'<span style="color: red">%1$s</span>\', $txt[\'ban_expired\']);
  201. // Still need to wait a few days for this ban to expire.
  202. else
  203. return sprintf(\'%1$d&nbsp;%2$s\', ceil(($rowData[\'expire_time\'] - time()) / (60 * 60 * 24)), $txt[\'ban_days\']);
  204. '),
  205. ),
  206. 'sort' => array(
  207. 'default' => 'IFNULL(bg.expire_time, 1=1) DESC, bg.expire_time DESC',
  208. 'reverse' => 'IFNULL(bg.expire_time, 1=1), bg.expire_time',
  209. ),
  210. ),
  211. 'num_triggers' => array(
  212. 'header' => array(
  213. 'value' => $txt['ban_triggers'],
  214. ),
  215. 'data' => array(
  216. 'db' => 'num_triggers',
  217. 'style' => 'text-align: center;',
  218. ),
  219. 'sort' => array(
  220. 'default' => 'num_triggers DESC',
  221. 'reverse' => 'num_triggers',
  222. ),
  223. ),
  224. 'actions' => array(
  225. 'header' => array(
  226. 'value' => $txt['ban_actions'],
  227. ),
  228. 'data' => array(
  229. 'sprintf' => array(
  230. 'format' => '<a href="' . $scripturl . '?action=admin;area=ban;sa=edit;bg=%1$d">' . $txt['modify'] . '</a>',
  231. 'params' => array(
  232. 'id_ban_group' => false,
  233. ),
  234. ),
  235. 'style' => 'text-align: center;',
  236. ),
  237. ),
  238. 'check' => array(
  239. 'header' => array(
  240. 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
  241. ),
  242. 'data' => array(
  243. 'sprintf' => array(
  244. 'format' => '<input type="checkbox" name="remove[]" value="%1$d" class="input_check" />',
  245. 'params' => array(
  246. 'id_ban_group' => false,
  247. ),
  248. ),
  249. 'style' => 'text-align: center',
  250. ),
  251. ),
  252. ),
  253. 'form' => array(
  254. 'href' => $scripturl . '?action=admin;area=ban;sa=list',
  255. ),
  256. 'additional_rows' => array(
  257. array(
  258. 'position' => 'below_table_data',
  259. 'value' => '<input type="submit" name="removeBans" value="' . $txt['ban_remove_selected'] . '" onclick="return confirm(\'' . $txt['ban_remove_selected_confirm'] . '\');" class="button_submit" />',
  260. 'style' => 'text-align: right;',
  261. ),
  262. ),
  263. );
  264. require_once($sourcedir . '/Subs-List.php');
  265. createList($listOptions);
  266. $context['sub_template'] = 'show_list';
  267. $context['default_list'] = 'ban_list';
  268. }
  269. /**
  270. * Get bans, what else? For the given options.
  271. *
  272. * @param int $start
  273. * @param int $items_per_page
  274. * @param string $sort
  275. * @return array
  276. */
  277. function list_getBans($start, $items_per_page, $sort)
  278. {
  279. global $smcFunc;
  280. $request = $smcFunc['db_query']('', '
  281. SELECT bg.id_ban_group, bg.name, bg.ban_time, bg.expire_time, bg.reason, bg.notes, COUNT(bi.id_ban) AS num_triggers
  282. FROM {db_prefix}ban_groups AS bg
  283. LEFT JOIN {db_prefix}ban_items AS bi ON (bi.id_ban_group = bg.id_ban_group)
  284. GROUP BY bg.id_ban_group, bg.name, bg.ban_time, bg.expire_time, bg.reason, bg.notes
  285. ORDER BY {raw:sort}
  286. LIMIT {int:offset}, {int:limit}',
  287. array(
  288. 'sort' => $sort,
  289. 'offset' => $start,
  290. 'limit' => $items_per_page,
  291. )
  292. );
  293. $bans = array();
  294. while ($row = $smcFunc['db_fetch_assoc']($request))
  295. $bans[] = $row;
  296. $smcFunc['db_free_result']($request);
  297. return $bans;
  298. }
  299. function list_getNumBans()
  300. {
  301. global $smcFunc;
  302. $request = $smcFunc['db_query']('', '
  303. SELECT COUNT(*) AS num_bans
  304. FROM {db_prefix}ban_groups',
  305. array(
  306. )
  307. );
  308. list ($numBans) = $smcFunc['db_fetch_row']($request);
  309. $smcFunc['db_free_result']($request);
  310. return $numBans;
  311. }
  312. /**
  313. * This function is behind the screen for adding new bans and modifying existing ones.
  314. * Adding new bans:
  315. * - is accesssed by ?action=admin;area=ban;sa=add.
  316. * - uses the ban_edit sub template of the ManageBans template.
  317. * Modifying existing bans:
  318. * - is accesssed by ?action=admin;area=ban;sa=edit;bg=x
  319. * - uses the ban_edit sub template of the ManageBans template.
  320. * - shows a list of ban triggers for the specified ban.
  321. * - handles submitted forms that add, modify or remove ban triggers.
  322. *
  323. * @todo insane number of writing to superglobals here...
  324. */
  325. function BanEdit()
  326. {
  327. global $txt, $modSettings, $context, $ban_request, $scripturl, $smcFunc;
  328. $_REQUEST['bg'] = empty($_REQUEST['bg']) ? 0 : (int) $_REQUEST['bg'];
  329. // Adding or editing a ban trigger?
  330. if (!empty($_POST['add_new_trigger']) || !empty($_POST['edit_trigger']))
  331. {
  332. checkSession();
  333. validateToken('admin-bet');
  334. $newBan = !empty($_POST['add_new_trigger']);
  335. $values = array(
  336. 'id_ban_group' => $_REQUEST['bg'],
  337. 'hostname' => '',
  338. 'email_address' => '',
  339. 'id_member' => 0,
  340. 'ip_low1' => 0,
  341. 'ip_high1' => 0,
  342. 'ip_low2' => 0,
  343. 'ip_high2' => 0,
  344. 'ip_low3' => 0,
  345. 'ip_high3' => 0,
  346. 'ip_low4' => 0,
  347. 'ip_high4' => 0,
  348. );
  349. // Preset all values that are required.
  350. if ($newBan)
  351. {
  352. $insertKeys = array(
  353. 'id_ban_group' => 'int',
  354. 'hostname' => 'string',
  355. 'email_address' => 'string',
  356. 'id_member' => 'int',
  357. 'ip_low1' => 'int',
  358. 'ip_high1' => 'int',
  359. 'ip_low2' => 'int',
  360. 'ip_high2' => 'int',
  361. 'ip_low3' => 'int',
  362. 'ip_high3' => 'int',
  363. 'ip_low4' => 'int',
  364. 'ip_high4' => 'int',
  365. );
  366. }
  367. else
  368. $updateString = '
  369. hostname = {string:hostname}, email_address = {string:email_address}, id_member = {int:id_member},
  370. ip_low1 = {int:ip_low1}, ip_high1 = {int:ip_high1},
  371. ip_low2 = {int:ip_low2}, ip_high2 = {int:ip_high2},
  372. ip_low3 = {int:ip_low3}, ip_high3 = {int:ip_high3},
  373. ip_low4 = {int:ip_low4}, ip_high4 = {int:ip_high4}';
  374. if ($_POST['bantype'] == 'ip_ban')
  375. {
  376. $ip = trim($_POST['ip']);
  377. $ip_parts = ip2range($ip);
  378. $ip_check = checkExistingTriggerIP($ip_parts, $ip);
  379. if (!$ip_check)
  380. fatal_lang_error('invalid_ip', false);
  381. $values = array_merge($values, $ip_check);
  382. $modlogInfo['ip_range'] = $_POST['ip'];
  383. }
  384. elseif ($_POST['bantype'] == 'hostname_ban')
  385. {
  386. if (preg_match('/[^\w.\-*]/', $_POST['hostname']) == 1)
  387. fatal_lang_error('invalid_hostname', false);
  388. // Replace the * wildcard by a MySQL compatible wildcard %.
  389. $_POST['hostname'] = str_replace('*', '%', $_POST['hostname']);
  390. $values['hostname'] = $_POST['hostname'];
  391. $modlogInfo['hostname'] = $_POST['hostname'];
  392. }
  393. elseif ($_POST['bantype'] == 'email_ban')
  394. {
  395. if (preg_match('/[^\w.\-\+*@]/', $_POST['email']) == 1)
  396. fatal_lang_error('invalid_email', false);
  397. $_POST['email'] = strtolower(str_replace('*', '%', $_POST['email']));
  398. // Check the user is not banning an admin.
  399. $request = $smcFunc['db_query']('', '
  400. SELECT id_member
  401. FROM {db_prefix}members
  402. WHERE (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0)
  403. AND email_address LIKE {string:email}
  404. LIMIT 1',
  405. array(
  406. 'admin_group' => 1,
  407. 'email' => $_POST['email'],
  408. )
  409. );
  410. if ($smcFunc['db_num_rows']($request) != 0)
  411. fatal_lang_error('no_ban_admin', 'critical');
  412. $smcFunc['db_free_result']($request);
  413. $values['email_address'] = $_POST['email'];
  414. $modlogInfo['email'] = $_POST['email'];
  415. }
  416. elseif ($_POST['bantype'] == 'user_ban')
  417. {
  418. $_POST['user'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $smcFunc['htmlspecialchars']($_POST['user'], ENT_QUOTES));
  419. $request = $smcFunc['db_query']('', '
  420. SELECT id_member, (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0) AS isAdmin
  421. FROM {db_prefix}members
  422. WHERE member_name = {string:user_name} OR real_name = {string:user_name}
  423. LIMIT 1',
  424. array(
  425. 'admin_group' => 1,
  426. 'user_name' => $_POST['user'],
  427. )
  428. );
  429. if ($smcFunc['db_num_rows']($request) == 0)
  430. fatal_lang_error('invalid_username', false);
  431. list ($memberid, $isAdmin) = $smcFunc['db_fetch_row']($request);
  432. $smcFunc['db_free_result']($request);
  433. if ($isAdmin && $isAdmin != 'f')
  434. fatal_lang_error('no_ban_admin', 'critical');
  435. $values['id_member'] = $memberid;
  436. $modlogInfo['member'] = $memberid;
  437. }
  438. else
  439. fatal_lang_error('no_bantype_selected', false);
  440. if ($newBan)
  441. $smcFunc['db_insert']('',
  442. '{db_prefix}ban_items',
  443. $insertKeys,
  444. $values,
  445. array('id_ban')
  446. );
  447. else
  448. $smcFunc['db_query']('', '
  449. UPDATE {db_prefix}ban_items
  450. SET ' . $updateString . '
  451. WHERE id_ban = {int:ban_item}
  452. AND id_ban_group = {int:id_ban_group}',
  453. array_merge($values, array(
  454. 'ban_item' => (int) $_REQUEST['bi'],
  455. ))
  456. );
  457. // Log the addion of the ban entry into the moderation log.
  458. logAction('ban', $modlogInfo + array(
  459. 'new' => $newBan,
  460. 'type' => $_POST['bantype'],
  461. ));
  462. // Register the last modified date.
  463. updateSettings(array('banLastUpdated' => time()));
  464. // Update the member table to represent the new ban situation.
  465. updateBanMembers();
  466. }
  467. // The user pressed 'Remove selected ban entries'.
  468. elseif (!empty($_POST['remove_selection']) && !empty($_POST['ban_items']) && is_array($_POST['ban_items']))
  469. {
  470. checkSession();
  471. validateToken('admin-bet');
  472. // Making sure every deleted ban item is an integer.
  473. foreach ($_POST['ban_items'] as $key => $value)
  474. $_POST['ban_items'][$key] = (int) $value;
  475. $smcFunc['db_query']('', '
  476. DELETE FROM {db_prefix}ban_items
  477. WHERE id_ban IN ({array_int:ban_list})
  478. AND id_ban_group = {int:ban_group}',
  479. array(
  480. 'ban_list' => $_POST['ban_items'],
  481. 'ban_group' => $_REQUEST['bg'],
  482. )
  483. );
  484. // It changed, let the settings and the member table know.
  485. updateSettings(array('banLastUpdated' => time()));
  486. updateBanMembers();
  487. }
  488. // Modify OR add a ban.
  489. elseif (!empty($_POST['modify_ban']) || !empty($_POST['add_ban']))
  490. {
  491. checkSession();
  492. validateToken('admin-bet');
  493. $addBan = !empty($_POST['add_ban']);
  494. if (empty($_POST['ban_name']))
  495. fatal_lang_error('ban_name_empty', false);
  496. // Let's not allow HTML in ban names, it's more evil than beneficial.
  497. $_POST['ban_name'] = $smcFunc['htmlspecialchars']($_POST['ban_name'], ENT_QUOTES);
  498. // Check whether a ban with this name already exists.
  499. $request = $smcFunc['db_query']('', '
  500. SELECT id_ban_group
  501. FROM {db_prefix}ban_groups
  502. WHERE name = {string:new_ban_name}' . ($addBan ? '' : '
  503. AND id_ban_group != {int:ban_group}') . '
  504. LIMIT 1',
  505. array(
  506. 'ban_group' => $_REQUEST['bg'],
  507. 'new_ban_name' => $_POST['ban_name'],
  508. )
  509. );
  510. if ($smcFunc['db_num_rows']($request) == 1)
  511. fatal_lang_error('ban_name_exists', false, array($_POST['ban_name']));
  512. $smcFunc['db_free_result']($request);
  513. $_POST['reason'] = $smcFunc['htmlspecialchars']($_POST['reason'], ENT_QUOTES);
  514. $_POST['notes'] = $smcFunc['htmlspecialchars']($_POST['notes'], ENT_QUOTES);
  515. $_POST['notes'] = str_replace(array("\r", "\n", ' '), array('', '<br />', '&nbsp; '), $_POST['notes']);
  516. $_POST['expiration'] = $_POST['expiration'] == 'never' ? 'NULL' : ($_POST['expiration'] == 'expired' ? '0' : ($_POST['expire_date'] != $_POST['old_expire'] ? time() + 24 * 60 * 60 * (int) $_POST['expire_date'] : 'expire_time'));
  517. $_POST['full_ban'] = empty($_POST['full_ban']) ? '0' : '1';
  518. $_POST['cannot_post'] = !empty($_POST['full_ban']) || empty($_POST['cannot_post']) ? '0' : '1';
  519. $_POST['cannot_register'] = !empty($_POST['full_ban']) || empty($_POST['cannot_register']) ? '0' : '1';
  520. $_POST['cannot_login'] = !empty($_POST['full_ban']) || empty($_POST['cannot_login']) ? '0' : '1';
  521. if ($addBan)
  522. {
  523. // Adding some ban triggers?
  524. if ($addBan && !empty($_POST['ban_suggestion']) && is_array($_POST['ban_suggestion']))
  525. {
  526. $ban_triggers = array();
  527. $ban_logs = array();
  528. if (in_array('main_ip', $_POST['ban_suggestion']) && !empty($_POST['main_ip']))
  529. {
  530. $ip = trim($_POST['main_ip']);
  531. $ip_parts = ip2range($ip);
  532. if (!checkExistingTriggerIP($ip_parts, $ip))
  533. fatal_lang_error('invalid_ip', false);
  534. $ban_triggers[] = array(
  535. $ip_parts[0]['low'],
  536. $ip_parts[0]['high'],
  537. $ip_parts[1]['low'],
  538. $ip_parts[1]['high'],
  539. $ip_parts[2]['low'],
  540. $ip_parts[2]['high'],
  541. $ip_parts[3]['low'],
  542. $ip_parts[3]['high'],
  543. '',
  544. '',
  545. 0,
  546. );
  547. $ban_logs[] = array(
  548. 'ip_range' => $_POST['main_ip'],
  549. );
  550. }
  551. if (in_array('hostname', $_POST['ban_suggestion']) && !empty($_POST['hostname']))
  552. {
  553. if (preg_match('/[^\w.\-*]/', $_POST['hostname']) == 1)
  554. fatal_lang_error('invalid_hostname', false);
  555. // Replace the * wildcard by a MySQL wildcard %.
  556. $_POST['hostname'] = str_replace('*', '%', $_POST['hostname']);
  557. $ban_triggers[] = array(
  558. 0, 0, 0, 0, 0, 0, 0, 0,
  559. substr($_POST['hostname'], 0, 255),
  560. '',
  561. 0,
  562. );
  563. $ban_logs[] = array(
  564. 'hostname' => $_POST['hostname'],
  565. );
  566. }
  567. if (in_array('email', $_POST['ban_suggestion']) && !empty($_POST['email']))
  568. {
  569. if (preg_match('/[^\w.\-\+*@]/', $_POST['email']) == 1)
  570. fatal_lang_error('invalid_email', false);
  571. $_POST['email'] = strtolower(str_replace('*', '%', $_POST['email']));
  572. $ban_triggers[] = array(
  573. 0, 0, 0, 0, 0, 0, 0, 0,
  574. '',
  575. substr($_POST['email'], 0, 255),
  576. 0,
  577. );
  578. $ban_logs[] = array(
  579. 'email' => $_POST['email'],
  580. );
  581. }
  582. if (in_array('user', $_POST['ban_suggestion']) && (!empty($_POST['bannedUser']) || !empty($_POST['user'])))
  583. {
  584. // We got a username, let's find its ID.
  585. if (empty($_POST['bannedUser']))
  586. {
  587. $_POST['user'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $smcFunc['htmlspecialchars']($_POST['user'], ENT_QUOTES));
  588. $request = $smcFunc['db_query']('', '
  589. SELECT id_member, (id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0) AS isAdmin
  590. FROM {db_prefix}members
  591. WHERE member_name = {string:username} OR real_name = {string:username}
  592. LIMIT 1',
  593. array(
  594. 'admin_group' => 1,
  595. 'username' => $_POST['user'],
  596. )
  597. );
  598. if ($smcFunc['db_num_rows']($request) == 0)
  599. fatal_lang_error('invalid_username', false);
  600. list ($_POST['bannedUser'], $isAdmin) = $smcFunc['db_fetch_row']($request);
  601. $smcFunc['db_free_result']($request);
  602. if ($isAdmin && $isAdmin != 'f')
  603. fatal_lang_error('no_ban_admin', 'critical');
  604. }
  605. $ban_triggers[] = array(
  606. 0, 0, 0, 0, 0, 0, 0, 0,
  607. '',
  608. '',
  609. (int) $_POST['bannedUser'],
  610. );
  611. $ban_logs[] = array(
  612. 'member' => $_POST['bannedUser'],
  613. );
  614. }
  615. if (!empty($_POST['ban_suggestion']['ips']) && is_array($_POST['ban_suggestion']['ips']))
  616. {
  617. $_POST['ban_suggestion']['ips'] = array_unique($_POST['ban_suggestion']['ips']);
  618. // Don't add the main IP again.
  619. if (in_array('main_ip', $_POST['ban_suggestion']))
  620. $_POST['ban_suggestion']['ips'] = array_diff($_POST['ban_suggestion']['ips'], array($_POST['main_ip']));
  621. foreach ($_POST['ban_suggestion']['ips'] as $ip)
  622. {
  623. $ip_parts = ip2range($ip);
  624. // They should be alright, but just to be sure...
  625. if (count($ip_parts) != 4)
  626. fatal_lang_error('invalid_ip', false);
  627. $ban_triggers[] = array(
  628. $ip_parts[0]['low'],
  629. $ip_parts[0]['high'],
  630. $ip_parts[1]['low'],
  631. $ip_parts[1]['high'],
  632. $ip_parts[2]['low'],
  633. $ip_parts[2]['high'],
  634. $ip_parts[3]['low'],
  635. $ip_parts[3]['high'],
  636. '',
  637. '',
  638. 0,
  639. );
  640. $ban_logs[] = array(
  641. 'ip_range' => $ip,
  642. );
  643. }
  644. }
  645. }
  646. // Yes yes, we're ready to add now.
  647. $smcFunc['db_insert']('',
  648. '{db_prefix}ban_groups',
  649. array(
  650. 'name' => 'string-20', 'ban_time' => 'int', 'expire_time' => 'raw', 'cannot_access' => 'int', 'cannot_register' => 'int',
  651. 'cannot_post' => 'int', 'cannot_login' => 'int', 'reason' => 'string-255', 'notes' => 'string-65534',
  652. ),
  653. array(
  654. $_POST['ban_name'], time(), $_POST['expiration'], $_POST['full_ban'], $_POST['cannot_register'],
  655. $_POST['cannot_post'], $_POST['cannot_login'], $_POST['reason'], $_POST['notes'],
  656. ),
  657. array('id_ban_group')
  658. );
  659. $_REQUEST['bg'] = $smcFunc['db_insert_id']('{db_prefix}ban_groups', 'id_ban_group');
  660. // Now that the ban group is added, add some triggers as well.
  661. if (!empty($ban_triggers) && !empty($_REQUEST['bg']))
  662. {
  663. // Put in the ban group ID.
  664. foreach ($ban_triggers as $k => $trigger)
  665. array_unshift($ban_triggers[$k], $_REQUEST['bg']);
  666. // Log what we are doing!
  667. foreach ($ban_logs as $log_details)
  668. logAction('ban', $log_details + array('new' => 1));
  669. $smcFunc['db_insert']('',
  670. '{db_prefix}ban_items',
  671. array(
  672. 'id_ban_group' => 'int', 'ip_low1' => 'int', 'ip_high1' => 'int', 'ip_low2' => 'int', 'ip_high2' => 'int',
  673. 'ip_low3' => 'int', 'ip_high3' => 'int', 'ip_low4' => 'int', 'ip_high4' => 'int', 'hostname' => 'string-255',
  674. 'email_address' => 'string-255', 'id_member' => 'int',
  675. ),
  676. $ban_triggers,
  677. array('id_ban')
  678. );
  679. }
  680. }
  681. else
  682. $smcFunc['db_query']('', '
  683. UPDATE {db_prefix}ban_groups
  684. SET
  685. name = {string:ban_name},
  686. reason = {string:reason},
  687. notes = {string:notes},
  688. expire_time = {raw:expiration},
  689. cannot_access = {int:cannot_access},
  690. cannot_post = {int:cannot_post},
  691. cannot_register = {int:cannot_register},
  692. cannot_login = {int:cannot_login}
  693. WHERE id_ban_group = {int:id_ban_group}',
  694. array(
  695. 'expiration' => $_POST['expiration'],
  696. 'cannot_access' => $_POST['full_ban'],
  697. 'cannot_post' => $_POST['cannot_post'],
  698. 'cannot_register' => $_POST['cannot_register'],
  699. 'cannot_login' => $_POST['cannot_login'],
  700. 'id_ban_group' => $_REQUEST['bg'],
  701. 'ban_name' => $_POST['ban_name'],
  702. 'reason' => $_POST['reason'],
  703. 'notes' => $_POST['notes'],
  704. )
  705. );
  706. // No more caching, we have something new here.
  707. updateSettings(array('banLastUpdated' => time()));
  708. updateBanMembers();
  709. }
  710. // If we're editing an existing ban, get it from the database.
  711. if (!empty($_REQUEST['bg']))
  712. {
  713. $context['ban_items'] = array();
  714. $request = $smcFunc['db_query']('', '
  715. SELECT
  716. bi.id_ban, bi.hostname, bi.email_address, bi.id_member, bi.hits,
  717. bi.ip_low1, bi.ip_high1, bi.ip_low2, bi.ip_high2, bi.ip_low3, bi.ip_high3, bi.ip_low4, bi.ip_high4,
  718. bg.id_ban_group, bg.name, bg.ban_time, bg.expire_time, bg.reason, bg.notes, bg.cannot_access, bg.cannot_register, bg.cannot_login, bg.cannot_post,
  719. IFNULL(mem.id_member, 0) AS id_member, mem.member_name, mem.real_name
  720. FROM {db_prefix}ban_groups AS bg
  721. LEFT JOIN {db_prefix}ban_items AS bi ON (bi.id_ban_group = bg.id_ban_group)
  722. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = bi.id_member)
  723. WHERE bg.id_ban_group = {int:current_ban}',
  724. array(
  725. 'current_ban' => $_REQUEST['bg'],
  726. )
  727. );
  728. if ($smcFunc['db_num_rows']($request) == 0)
  729. fatal_lang_error('ban_not_found', false);
  730. while ($row = $smcFunc['db_fetch_assoc']($request))
  731. {
  732. if (!isset($context['ban']))
  733. {
  734. $context['ban'] = array(
  735. 'id' => $row['id_ban_group'],
  736. 'name' => $row['name'],
  737. 'expiration' => array(
  738. 'status' => $row['expire_time'] === null ? 'never' : ($row['expire_time'] < time() ? 'expired' : 'still_active_but_we_re_counting_the_days'),
  739. 'days' => $row['expire_time'] > time() ? floor(($row['expire_time'] - time()) / 86400) : 0
  740. ),
  741. 'reason' => $row['reason'],
  742. 'notes' => $row['notes'],
  743. 'cannot' => array(
  744. 'access' => !empty($row['cannot_access']),
  745. 'post' => !empty($row['cannot_post']),
  746. 'register' => !empty($row['cannot_register']),
  747. 'login' => !empty($row['cannot_login']),
  748. ),
  749. 'is_new' => false,
  750. );
  751. }
  752. if (!empty($row['id_ban']))
  753. {
  754. $context['ban_items'][$row['id_ban']] = array(
  755. 'id' => $row['id_ban'],
  756. 'hits' => $row['hits'],
  757. );
  758. if (!empty($row['ip_high1']))
  759. {
  760. $context['ban_items'][$row['id_ban']]['type'] = 'ip';
  761. $context['ban_items'][$row['id_ban']]['ip'] = range2ip(array($row['ip_low1'], $row['ip_low2'], $row['ip_low3'], $row['ip_low4']), array($row['ip_high1'], $row['ip_high2'], $row['ip_high3'], $row['ip_high4']));
  762. }
  763. elseif (!empty($row['hostname']))
  764. {
  765. $context['ban_items'][$row['id_ban']]['type'] = 'hostname';
  766. $context['ban_items'][$row['id_ban']]['hostname'] = str_replace('%', '*', $row['hostname']);
  767. }
  768. elseif (!empty($row['email_address']))
  769. {
  770. $context['ban_items'][$row['id_ban']]['type'] = 'email';
  771. $context['ban_items'][$row['id_ban']]['email'] = str_replace('%', '*', $row['email_address']);
  772. }
  773. elseif (!empty($row['id_member']))
  774. {
  775. $context['ban_items'][$row['id_ban']]['type'] = 'user';
  776. $context['ban_items'][$row['id_ban']]['user'] = array(
  777. 'id' => $row['id_member'],
  778. 'name' => $row['real_name'],
  779. 'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
  780. 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>',
  781. );
  782. }
  783. // Invalid ban (member probably doesn't exist anymore).
  784. else
  785. {
  786. unset($context['ban_items'][$row['id_ban']]);
  787. $smcFunc['db_query']('', '
  788. DELETE FROM {db_prefix}ban_items
  789. WHERE id_ban = {int:current_ban}',
  790. array(
  791. 'current_ban' => $row['id_ban'],
  792. )
  793. );
  794. }
  795. }
  796. }
  797. $smcFunc['db_free_result']($request);
  798. }
  799. // Not an existing one, then it's probably a new one.
  800. else
  801. {
  802. $context['ban'] = array(
  803. 'id' => 0,
  804. 'name' => '',
  805. 'expiration' => array(
  806. 'status' => 'never',
  807. 'days' => 0
  808. ),
  809. 'reason' => '',
  810. 'notes' => '',
  811. 'ban_days' => 0,
  812. 'cannot' => array(
  813. 'access' => true,
  814. 'post' => false,
  815. 'register' => false,
  816. 'login' => false,
  817. ),
  818. 'is_new' => true,
  819. );
  820. $context['ban_suggestions'] = array(
  821. 'main_ip' => '',
  822. 'hostname' => '',
  823. 'email' => '',
  824. 'member' => array(
  825. 'id' => 0,
  826. ),
  827. );
  828. // Overwrite some of the default form values if a user ID was given.
  829. if (!empty($_REQUEST['u']))
  830. {
  831. $request = $smcFunc['db_query']('', '
  832. SELECT id_member, real_name, member_ip, email_address
  833. FROM {db_prefix}members
  834. WHERE id_member = {int:current_user}
  835. LIMIT 1',
  836. array(
  837. 'current_user' => (int) $_REQUEST['u'],
  838. )
  839. );
  840. if ($smcFunc['db_num_rows']($request) > 0)
  841. list ($context['ban_suggestions']['member']['id'], $context['ban_suggestions']['member']['name'], $context['ban_suggestions']['main_ip'], $context['ban_suggestions']['email']) = $smcFunc['db_fetch_row']($request);
  842. $smcFunc['db_free_result']($request);
  843. if (!empty($context['ban_suggestions']['member']['id']))
  844. {
  845. $context['ban_suggestions']['href'] = $scripturl . '?action=profile;u=' . $context['ban_suggestions']['member']['id'];
  846. $context['ban_suggestions']['member']['link'] = '<a href="' . $context['ban_suggestions']['href'] . '">' . $context['ban_suggestions']['member']['name'] . '</a>';
  847. // Default the ban name to the name of the banned member.
  848. $context['ban']['name'] = $context['ban_suggestions']['member']['name'];
  849. // Would be nice if we could also ban the hostname.
  850. if (preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $context['ban_suggestions']['main_ip']) == 1 && empty($modSettings['disableHostnameLookup']))
  851. $context['ban_suggestions']['hostname'] = host_from_ip($context['ban_suggestions']['main_ip']);
  852. // Find some additional IP's used by this member.
  853. $context['ban_suggestions']['message_ips'] = array();
  854. $request = $smcFunc['db_query']('ban_suggest_message_ips', '
  855. SELECT DISTINCT poster_ip
  856. FROM {db_prefix}messages
  857. WHERE id_member = {int:current_user}
  858. AND poster_ip RLIKE {string:poster_ip_regex}
  859. ORDER BY poster_ip',
  860. array(
  861. 'current_user' => (int) $_REQUEST['u'],
  862. 'poster_ip_regex' => '^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$',
  863. )
  864. );
  865. while ($row = $smcFunc['db_fetch_assoc']($request))
  866. $context['ban_suggestions']['message_ips'][] = $row['poster_ip'];
  867. $smcFunc['db_free_result']($request);
  868. $context['ban_suggestions']['error_ips'] = array();
  869. $request = $smcFunc['db_query']('ban_suggest_error_ips', '
  870. SELECT DISTINCT ip
  871. FROM {db_prefix}log_errors
  872. WHERE id_member = {int:current_user}
  873. AND ip RLIKE {string:poster_ip_regex}
  874. ORDER BY ip',
  875. array(
  876. 'current_user' => (int) $_REQUEST['u'],
  877. 'poster_ip_regex' => '^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$',
  878. )
  879. );
  880. while ($row = $smcFunc['db_fetch_assoc']($request))
  881. $context['ban_suggestions']['error_ips'][] = $row['ip'];
  882. $smcFunc['db_free_result']($request);
  883. // Borrowing a few language strings from profile.
  884. loadLanguage('Profile');
  885. }
  886. }
  887. }
  888. // Template needs this to show errors using javascript
  889. loadLanguage('Errors');
  890. // If we're in wireless mode remove the admin template layer and use a special template.
  891. if (WIRELESS && WIRELESS_PROTOCOL != 'wap')
  892. {
  893. $context['sub_template'] = WIRELESS_PROTOCOL . '_ban_edit';
  894. foreach ($context['template_layers'] as $k => $v)
  895. if (strpos($v, 'generic_menu') === 0)
  896. unset($context['template_layers'][$k]);
  897. }
  898. else
  899. $context['sub_template'] = 'ban_edit';
  900. createToken('admin-bet');
  901. }
  902. /**
  903. * This function handles the ins and outs of the screen for adding new ban
  904. * triggers or modifying existing ones.
  905. * Adding new ban triggers:
  906. * - is accessed by ?action=admin;area=ban;sa=edittrigger;bg=x
  907. * - uses the ban_edit_trigger sub template of ManageBans.
  908. * Editing existing ban triggers:
  909. * - is accessed by ?action=admin;area=ban;sa=edittrigger;bg=x;bi=y
  910. * - uses the ban_edit_trigger sub template of ManageBans.
  911. */
  912. function BanEditTrigger()
  913. {
  914. global $context, $smcFunc;
  915. $context['sub_template'] = 'ban_edit_trigger';
  916. if (empty($_REQUEST['bg']))
  917. fatal_lang_error('ban_not_found', false);
  918. if (empty($_REQUEST['bi']))
  919. {
  920. $context['ban_trigger'] = array(
  921. 'id' => 0,
  922. 'group' => (int) $_REQUEST['bg'],
  923. 'ip' => array(
  924. 'value' => '',
  925. 'selected' => true,
  926. ),
  927. 'hostname' => array(
  928. 'selected' => false,
  929. 'value' => '',
  930. ),
  931. 'email' => array(
  932. 'value' => '',
  933. 'selected' => false,
  934. ),
  935. 'banneduser' => array(
  936. 'value' => '',
  937. 'selected' => false,
  938. ),
  939. 'is_new' => true,
  940. );
  941. }
  942. else
  943. {
  944. $request = $smcFunc['db_query']('', '
  945. SELECT
  946. bi.id_ban, bi.id_ban_group, bi.hostname, bi.email_address, bi.id_member,
  947. bi.ip_low1, bi.ip_high1, bi.ip_low2, bi.ip_high2, bi.ip_low3, bi.ip_high3, bi.ip_low4, bi.ip_high4,
  948. mem.member_name, mem.real_name
  949. FROM {db_prefix}ban_items AS bi
  950. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = bi.id_member)
  951. WHERE bi.id_ban = {int:ban_item}
  952. AND bi.id_ban_group = {int:ban_group}
  953. LIMIT 1',
  954. array(
  955. 'ban_item' => (int) $_REQUEST['bi'],
  956. 'ban_group' => (int) $_REQUEST['bg'],
  957. )
  958. );
  959. if ($smcFunc['db_num_rows']($request) == 0)
  960. fatal_lang_error('ban_not_found', false);
  961. $row = $smcFunc['db_fetch_assoc']($request);
  962. $smcFunc['db_free_result']($request);
  963. $context['ban_trigger'] = array(
  964. 'id' => $row['id_ban'],
  965. 'group' => $row['id_ban_group'],
  966. 'ip' => array(
  967. 'value' => empty($row['ip_low1']) ? '' : range2ip(array($row['ip_low1'], $row['ip_low2'], $row['ip_low3'], $row['ip_low4']), array($row['ip_high1'], $row['ip_high2'], $row['ip_high3'], $row['ip_high4'])),
  968. 'selected' => !empty($row['ip_low1']),
  969. ),
  970. 'hostname' => array(
  971. 'value' => str_replace('%', '*', $row['hostname']),
  972. 'selected' => !empty($row['hostname']),
  973. ),
  974. 'email' => array(
  975. 'value' => str_replace('%', '*', $row['email_address']),
  976. 'selected' => !empty($row['email_address'])
  977. ),
  978. 'banneduser' => array(
  979. 'value' => $row['member_name'],
  980. 'selected' => !empty($row['member_name'])
  981. ),
  982. 'is_new' => false,
  983. );
  984. }
  985. createToken('admin-bet');
  986. }
  987. /**
  988. * This handles the screen for showing the banned entities
  989. * It is accessed by ?action=admin;area=ban;sa=browse
  990. * It uses sub-tabs for browsing by IP, hostname, email or username.
  991. *
  992. * @uses ManageBans template, browse_triggers sub template.
  993. */
  994. function BanBrowseTriggers()
  995. {
  996. global $modSettings, $context, $scripturl, $smcFunc, $txt;
  997. global $sourcedir, $settings;
  998. if (!empty($_POST['remove_triggers']) && !empty($_POST['remove']) && is_array($_POST['remove']))
  999. {
  1000. checkSession();
  1001. // Clean the integers.
  1002. foreach ($_POST['remove'] as $key => $value)
  1003. $_POST['remove'][$key] = $value;
  1004. $smcFunc['db_query']('', '
  1005. DELETE FROM {db_prefix}ban_items
  1006. WHERE id_ban IN ({array_int:ban_list})',
  1007. array(
  1008. 'ban_list' => $_POST['remove'],
  1009. )
  1010. );
  1011. // Rehabilitate some members.
  1012. if ($_REQUEST['entity'] == 'member')
  1013. updateBanMembers();
  1014. // Make sure the ban cache is refreshed.
  1015. updateSettings(array('banLastUpdated' => time()));
  1016. }
  1017. $context['selected_entity'] = isset($_REQUEST['entity']) && in_array($_REQUEST['entity'], array('ip', 'hostname', 'email', 'member')) ? $_REQUEST['entity'] : 'ip';
  1018. $listOptions = array(
  1019. 'id' => 'ban_trigger_list',
  1020. 'title' => $txt['ban_trigger_browse'],
  1021. 'items_per_page' => $modSettings['defaultMaxMessages'],
  1022. 'base_href' => $scripturl . '?action=admin;area=ban;sa=browse;entity=' . $context['selected_entity'],
  1023. 'default_sort_col' => 'banned_entity',
  1024. 'no_items_label' => $txt['ban_no_triggers'],
  1025. 'get_items' => array(
  1026. 'function' => 'list_getBanTriggers',
  1027. 'params' => array(
  1028. $context['selected_entity'],
  1029. ),
  1030. ),
  1031. 'get_count' => array(
  1032. 'function' => 'list_getNumBanTriggers',
  1033. 'params' => array(
  1034. $context['selected_entity'],
  1035. ),
  1036. ),
  1037. 'columns' => array(
  1038. 'banned_entity' => array(
  1039. 'header' => array(
  1040. 'value' => $txt['ban_banned_entity'],
  1041. ),
  1042. ),
  1043. 'ban_name' => array(
  1044. 'header' => array(
  1045. 'value' => $txt['ban_name'],
  1046. ),
  1047. 'data' => array(
  1048. 'sprintf' => array(
  1049. 'format' => '<a href="' . $scripturl . '?action=admin;area=ban;sa=edit;bg=%1$d">%2$s</a>',
  1050. 'params' => array(
  1051. 'id_ban_group' => false,
  1052. 'name' => false,
  1053. ),
  1054. ),
  1055. ),
  1056. 'sort' => array(
  1057. 'default' => 'bg.name',
  1058. 'reverse' => 'bg.name DESC',
  1059. ),
  1060. ),
  1061. 'hits' => array(
  1062. 'header' => array(
  1063. 'value' => $txt['ban_hits'],
  1064. ),
  1065. 'data' => array(
  1066. 'db' => 'hits',
  1067. 'style' => 'text-align: center;',
  1068. ),
  1069. 'sort' => array(
  1070. 'default' => 'bi.hits DESC',
  1071. 'reverse' => 'bi.hits',
  1072. ),
  1073. ),
  1074. 'check' => array(
  1075. 'header' => array(
  1076. 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
  1077. ),
  1078. 'data' => array(
  1079. 'sprintf' => array(
  1080. 'format' => '<input type="checkbox" name="remove[]" value="%1$d" class="input_check" />',
  1081. 'params' => array(
  1082. 'id_ban' => false,
  1083. ),
  1084. ),
  1085. 'style' => 'text-align: center',
  1086. ),
  1087. ),
  1088. ),
  1089. 'form' => array(
  1090. 'href' => $scripturl . '?action=admin;area=ban;sa=browse;entity=' . $context['selected_entity'],
  1091. 'include_start' => true,
  1092. 'include_sort' => true,
  1093. ),
  1094. 'additional_rows' => array(
  1095. array(
  1096. 'position' => 'above_column_headers',
  1097. 'value' => '<a href="' . $scripturl . '?action=admin;area=ban;sa=browse;entity=ip">' . ($context['selected_entity'] == 'ip' ? '<img src="' . $settings['images_url'] . '/selected.gif" alt="&gt;" /> ' : '') . $txt['ip'] . '</a>&nbsp;|&nbsp;<a href="' . $scripturl . '?action=admin;area=ban;sa=browse;entity=hostname">' . ($context['selected_entity'] == 'hostname' ? '<img src="' . $settings['images_url'] . '/selected.gif" alt="&gt;" /> ' : '') . $txt['hostname'] . '</a>&nbsp;|&nbsp;<a href="' . $scripturl . '?action=admin;area=ban;sa=browse;entity=email">' . ($context['selected_entity'] == 'email' ? '<img src="' . $settings['images_url'] . '/selected.gif" alt="&gt;" /> ' : '') . $txt['email'] . '</a>&nbsp;|&nbsp;<a href="' . $scripturl . '?action=admin;area=ban;sa=browse;entity=member">' . ($context['selected_entity'] == 'member' ? '<img src="' . $settings['images_url'] . '/selected.gif" alt="&gt;" /> ' : '') . $txt['username'] . '</a>',
  1098. ),
  1099. array(
  1100. 'position' => 'below_table_data',
  1101. 'value' => '<input type="submit" name="remove_triggers" value="' . $txt['ban_remove_selected_triggers'] . '" onclick="return confirm(\'' . $txt['ban_remove_selected_triggers_confirm'] . '\');" class="button_submit" />',
  1102. 'style' => 'text-align: right;',
  1103. ),
  1104. ),
  1105. );
  1106. // Specific data for the first column depending on the selected entity.
  1107. if ($context['selected_entity'] === 'ip')
  1108. {
  1109. $listOptions['columns']['banned_entity']['data'] = array(
  1110. 'function' => create_function('$rowData', '
  1111. return range2ip(array(
  1112. $rowData[\'ip_low1\'],
  1113. $rowData[\'ip_low2\'],
  1114. $rowData[\'ip_low3\'],
  1115. $rowData[\'ip_low4\']
  1116. ), array(
  1117. $rowData[\'ip_high1\'],
  1118. $rowData[\'ip_high2\'],
  1119. $rowData[\'ip_high3\'],
  1120. $rowData[\'ip_high4\']
  1121. ));
  1122. '),
  1123. );
  1124. $listOptions['columns']['banned_entity']['sort'] = array(
  1125. 'default' => 'bi.ip_low1, bi.ip_high1, bi.ip_low2, bi.ip_high2, bi.ip_low3, bi.ip_high3, bi.ip_low4, bi.ip_high4',
  1126. 'reverse' => 'bi.ip_low1 DESC, bi.ip_high1 DESC, bi.ip_low2 DESC, bi.ip_high2 DESC, bi.ip_low3 DESC, bi.ip_high3 DESC, bi.ip_low4 DESC, bi.ip_high4 DESC',
  1127. );
  1128. }
  1129. elseif ($context['selected_entity'] === 'hostname')
  1130. {
  1131. $listOptions['columns']['banned_entity']['data'] = array(
  1132. 'function' => create_function('$rowData', '
  1133. global $smcFunc;
  1134. return strtr($smcFunc[\'htmlspecialchars\']($rowData[\'hostname\']), array(\'%\' => \'*\'));
  1135. '),
  1136. );
  1137. $listOptions['columns']['banned_entity']['sort'] = array(
  1138. 'default' => 'bi.hostname',
  1139. 'reverse' => 'bi.hostname DESC',
  1140. );
  1141. }
  1142. elseif ($context['selected_entity'] === 'email')
  1143. {
  1144. $listOptions['columns']['banned_entity']['data'] = array(
  1145. 'function' => create_function('$rowData', '
  1146. global $smcFunc;
  1147. return strtr($smcFunc[\'htmlspecialchars\']($rowData[\'email_address\']), array(\'%\' => \'*\'));
  1148. '),
  1149. );
  1150. $listOptions['columns']['banned_entity']['sort'] = array(
  1151. 'default' => 'bi.email_address',
  1152. 'reverse' => 'bi.email_address DESC',
  1153. );
  1154. }
  1155. elseif ($context['selected_entity'] === 'member')
  1156. {
  1157. $listOptions['columns']['banned_entity']['data'] = array(
  1158. 'sprintf' => array(
  1159. 'format' => '<a href="' . $scripturl . '?action=profile;u=%1$d">%2$s</a>',
  1160. 'params' => array(
  1161. 'id_member' => false,
  1162. 'real_name' => false,
  1163. ),
  1164. ),
  1165. );
  1166. $listOptions['columns']['banned_entity']['sort'] = array(
  1167. 'default' => 'mem.real_name',
  1168. 'reverse' => 'mem.real_name DESC',
  1169. );
  1170. }
  1171. // Create the list.
  1172. require_once($sourcedir . '/Subs-List.php');
  1173. createList($listOptions);
  1174. // The list is the only thing to show, so make it the default sub template.
  1175. $context['sub_template'] = 'show_list';
  1176. $context['default_list'] = 'ban_trigger_list';
  1177. }
  1178. /**
  1179. * Get ban triggers for the given parameters.
  1180. *
  1181. * @param int $start
  1182. * @param int $items_per_page
  1183. * @param string $sort
  1184. * @param string $trigger_type
  1185. * @return array
  1186. */
  1187. function list_getBanTriggers($start, $items_per_page, $sort, $trigger_type)
  1188. {
  1189. global $smcFunc;
  1190. $where = array(
  1191. 'ip' => 'bi.ip_low1 > 0',
  1192. 'hostname' => 'bi.hostname != {string:blank_string}',
  1193. 'email' => 'bi.email_address != {string:blank_string}',
  1194. );
  1195. $request = $smcFunc['db_query']('', '
  1196. SELECT
  1197. bi.id_ban, bi.ip_low1, bi.ip_high1, bi.ip_low2, bi.ip_high2, bi.ip_low3, bi.ip_high3, bi.ip_low4, bi.ip_high4, bi.hostname, bi.email_address, bi.hits,
  1198. bg.id_ban_group, bg.name' . ($trigger_type === 'member' ? ',
  1199. mem.id_member, mem.real_name' : '') . '
  1200. FROM {db_prefix}ban_items AS bi
  1201. INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group)' . ($trigger_type === 'member' ? '
  1202. INNER JOIN {db_prefix}members AS mem ON (mem.id_member = bi.id_member)' : '
  1203. WHERE ' . $where[$trigger_type]) . '
  1204. ORDER BY ' . $sort . '
  1205. LIMIT ' . $start . ', ' . $items_per_page,
  1206. array(
  1207. 'blank_string' => '',
  1208. )
  1209. );
  1210. $ban_triggers = array();
  1211. while ($row = $smcFunc['db_fetch_assoc']($request))
  1212. $ban_triggers[] = $row;
  1213. $smcFunc['db_free_result']($request);
  1214. return $ban_triggers;
  1215. }
  1216. /**
  1217. * This returns the total number of ban triggers of the given type.
  1218. *
  1219. * @param string $trigger_type
  1220. * @return int
  1221. */
  1222. function list_getNumBanTriggers($trigger_type)
  1223. {
  1224. global $smcFunc;
  1225. $where = array(
  1226. 'ip' => 'bi.ip_low1 > 0',
  1227. 'hostname' => 'bi.hostname != {string:blank_string}',
  1228. 'email' => 'bi.email_address != {string:blank_string}',
  1229. );
  1230. $request = $smcFunc['db_query']('', '
  1231. SELECT COUNT(*)
  1232. FROM {db_prefix}ban_items AS bi' . ($trigger_type === 'member' ? '
  1233. INNER JOIN {db_prefix}members AS mem ON (mem.id_member = bi.id_member)' : '
  1234. WHERE ' . $where[$trigger_type]),
  1235. array(
  1236. 'blank_string' => '',
  1237. )
  1238. );
  1239. list ($num_triggers) = $smcFunc['db_fetch_row']($request);
  1240. $smcFunc['db_free_result']($request);
  1241. return $num_triggers;
  1242. }
  1243. /**
  1244. * This handles the listing of ban log entries, and allows their deletion.
  1245. * Shows a list of logged access attempts by banned users.
  1246. * It is accessed by ?action=admin;area=ban;sa=log.
  1247. * How it works:
  1248. * - allows sorting of several columns.
  1249. * - also handles deletion of (a selection of) log entries.
  1250. */
  1251. function BanLog()
  1252. {
  1253. global $scripturl, $context, $smcFunc, $sourcedir, $txt;
  1254. global $context;
  1255. // Delete one or more entries.
  1256. if (!empty($_POST['removeAll']) || (!empty($_POST['removeSelected']) && !empty($_POST['remove'])))
  1257. {
  1258. checkSession();
  1259. validateToken('admin-bl');
  1260. // 'Delete all entries' button was pressed.
  1261. if (!empty($_POST['removeAll']))
  1262. $smcFunc['db_query']('truncate_table', '
  1263. TRUNCATE {db_prefix}log_banned',
  1264. array(
  1265. )
  1266. );
  1267. // 'Delete selection' button was pressed.
  1268. else
  1269. {
  1270. // Make sure every entry is integer.
  1271. foreach ($_POST['remove'] as $index => $log_id)
  1272. $_POST['remove'][$index] = (int) $log_id;
  1273. $smcFunc['db_query']('', '
  1274. DELETE FROM {db_prefix}log_banned
  1275. WHERE id_ban_log IN ({array_int:ban_list})',
  1276. array(
  1277. 'ban_list' => $_POST['remove'],
  1278. )
  1279. );
  1280. }
  1281. }
  1282. $listOptions = array(
  1283. 'id' => 'ban_log',
  1284. 'items_per_page' => 30,
  1285. 'base_href' => $context['admin_area'] == 'ban' ? $scripturl . '?action=admin;area=ban;sa=log' : $scripturl . '?action=admin;area=logs;sa=banlog',
  1286. 'default_sort_col' => 'date',
  1287. 'get_items' => array(
  1288. 'function' => 'list_getBanLogEntries',
  1289. ),
  1290. 'get_count' => array(
  1291. 'function' => 'list_getNumBanLogEntries',
  1292. ),
  1293. 'no_items_label' => $txt['ban_log_no_entries'],
  1294. 'columns' => array(
  1295. 'ip' => array(
  1296. 'header' => array(
  1297. 'value' => $txt['ban_log_ip'],
  1298. ),
  1299. 'data' => array(
  1300. 'sprintf' => array(
  1301. 'format' => '<a href="' . $scripturl . '?action=trackip;searchip=%1$s">%1$s</a>',
  1302. 'params' => array(
  1303. 'ip' => false,
  1304. ),
  1305. ),
  1306. ),
  1307. 'sort' => array(
  1308. 'default' => 'lb.ip',
  1309. 'reverse' => 'lb.ip DESC',
  1310. ),
  1311. ),
  1312. 'email' => array(
  1313. 'header' => array(
  1314. 'value' => $txt['ban_log_email'],
  1315. ),
  1316. 'data' => array(
  1317. 'db_htmlsafe' => 'email',
  1318. ),
  1319. 'sort' => array(
  1320. 'default' => 'lb.email = \'\', lb.email',
  1321. 'reverse' => 'lb.email != \'\', lb.email DESC',
  1322. ),
  1323. ),
  1324. 'member' => array(
  1325. 'header' => array(
  1326. 'value' => $txt['ban_log_member'],
  1327. ),
  1328. 'data' => array(
  1329. 'sprintf' => array(
  1330. 'format' => '<a href="' . $scripturl . '?action=profile;u=%1$d">%2$s</a>',
  1331. 'params' => array(
  1332. 'id_member' => false,
  1333. 'real_name' => false,
  1334. ),
  1335. ),
  1336. ),
  1337. 'sort' => array(
  1338. 'default' => 'IFNULL(mem.real_name, 1=1), mem.real_name',
  1339. 'reverse' => 'IFNULL(mem.real_name, 1=1) DESC, mem.real_name DESC',
  1340. ),
  1341. ),
  1342. 'date' => array(
  1343. 'header' => array(
  1344. 'value' => $txt['ban_log_date'],
  1345. ),
  1346. 'data' => array(
  1347. 'function' => create_function('$rowData', '
  1348. return timeformat($rowData[\'log_time\']);
  1349. '),
  1350. ),
  1351. 'sort' => array(
  1352. 'default' => 'lb.log_time DESC',
  1353. 'reverse' => 'lb.log_time',
  1354. ),
  1355. ),
  1356. 'check' => array(
  1357. 'header' => array(
  1358. 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
  1359. ),
  1360. 'data' => array(
  1361. 'sprintf' => array(
  1362. 'format' => '<input type="checkbox" name="remove[]" value="%1$d" class="input_check" />',
  1363. 'params' => array(
  1364. 'id_ban_log' => false,
  1365. ),
  1366. ),
  1367. 'style' => 'text-align: center',
  1368. ),
  1369. ),
  1370. ),
  1371. 'form' => array(
  1372. 'href' => $context['admin_area'] == 'ban' ? $scripturl . '?action=admin;area=ban;sa=log' : $scripturl . '?action=admin;area=logs;sa=banlog',
  1373. 'include_start' => true,
  1374. 'include_sort' => true,
  1375. 'token' => 'admin-bl',
  1376. ),
  1377. 'additional_rows' => array(
  1378. array(
  1379. 'position' => 'below_table_data',
  1380. 'value' => '
  1381. <input type="submit" name="removeSelected" value="' . $txt['ban_log_remove_selected'] . '" onclick="return confirm(\'' . $txt['ban_log_remove_selected_confirm'] . '\');" class="button_submit" />
  1382. <input type="submit" name="removeAll" value="' . $txt['ban_log_remove_all'] . '" onclick="return confirm(\'' . $txt['ban_log_remove_all_confirm'] . '\');" class="button_submit" />',
  1383. 'style' => 'text-align: right;',
  1384. ),
  1385. ),
  1386. );
  1387. createToken('admin-bl');
  1388. require_once($sourcedir . '/Subs-List.php');
  1389. createList($listOptions);
  1390. $context['page_title'] = $txt['ban_log'];
  1391. $context['sub_template'] = 'show_list';
  1392. $context['default_list'] = 'ban_log';
  1393. }
  1394. /**
  1395. * Load a list of ban log entries from the database.
  1396. * (no permissions check)
  1397. *
  1398. * @param int $start
  1399. * @param int $items_per_page
  1400. * @param string $sort
  1401. */
  1402. function list_getBanLogEntries($start, $items_per_page, $sort)
  1403. {
  1404. global $smcFunc;
  1405. $request = $smcFunc['db_query']('', '
  1406. SELECT lb.id_ban_log, lb.id_member, IFNULL(lb.ip, {string:dash}) AS ip, IFNULL(lb.email, {string:dash}) AS email, lb.log_time, IFNULL(mem.real_name, {string:blank_string}) AS real_name
  1407. FROM {db_prefix}log_banned AS lb
  1408. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lb.id_member)
  1409. ORDER BY ' . $sort . '
  1410. LIMIT ' . $start . ', ' . $items_per_page,
  1411. array(
  1412. 'blank_string' => '',
  1413. 'dash' => '-',
  1414. )
  1415. );
  1416. $log_entries = array();
  1417. while ($row = $smcFunc['db_fetch_assoc']($request))
  1418. $log_entries[] = $row;
  1419. $smcFunc['db_free_result']($request);
  1420. return $log_entries;
  1421. }
  1422. /**
  1423. * This returns the total count of ban log entries.
  1424. */
  1425. function list_getNumBanLogEntries()
  1426. {
  1427. global $smcFunc;
  1428. $request = $smcFunc['db_query']('', '
  1429. SELECT COUNT(*)
  1430. FROM {db_prefix}log_banned AS lb',
  1431. array(
  1432. )
  1433. );
  1434. list ($num_entries) = $smcFunc['db_fetch_row']($request);
  1435. $smcFunc['db_free_result']($request);
  1436. return $num_entries;
  1437. }
  1438. /**
  1439. * Convert a range of given IP number into a single string.
  1440. * It's practically the reverse function of ip2range().
  1441. *
  1442. * @example
  1443. * range2ip(array(10, 10, 10, 0), array(10, 10, 20, 255)) returns '10.10.10-20.*
  1444. *
  1445. * @param array $low, IPv4 format
  1446. * @param array $high, IPv4 format
  1447. * @return string
  1448. */
  1449. function range2ip($low, $high)
  1450. {
  1451. if (count($low) != 4 || count($high) != 4)
  1452. return '';
  1453. $ip = array();
  1454. for ($i = 0; $i < 4; $i++)
  1455. {
  1456. if ($low[$i] == $high[$i])
  1457. $ip[$i] = $low[$i];
  1458. elseif ($low[$i] == '0' && $high[$i] == '255')
  1459. $ip[$i] = '*';
  1460. else
  1461. $ip[$i] = $low[$i] . '-' . $high[$i];
  1462. }
  1463. // Pretending is fun... the IP can't be this, so use it for 'unknown'.
  1464. if ($ip == array(255, 255, 255, 255))
  1465. return 'unknown';
  1466. return implode('.', $ip);
  1467. }
  1468. /**
  1469. * Checks whether a given IP range already exists in the trigger list.
  1470. * If yes, it returns an error message. Otherwise, it returns an array
  1471. * optimized for the database.
  1472. *
  1473. * @param array $ip_array
  1474. * @param string $fullip
  1475. * @return bool
  1476. */
  1477. function checkExistingTriggerIP($ip_array, $fullip = '')
  1478. {
  1479. global $smcFunc, $scripturl;
  1480. if (count($ip_array) == 4)
  1481. $values = array(
  1482. 'ip_low1' => $ip_array[0]['low'],
  1483. 'ip_high1' => $ip_array[0]['high'],
  1484. 'ip_low2' => $ip_array[1]['low'],
  1485. 'ip_high2' => $ip_array[1]['high'],
  1486. 'ip_low3' => $ip_array[2]['low'],
  1487. 'ip_high3' => $ip_array[2]['high'],
  1488. 'ip_low4' => $ip_array[3]['low'],
  1489. 'ip_high4' => $ip_array[3]['high'],
  1490. );
  1491. else
  1492. return false;
  1493. $request = $smcFunc['db_query']('', '
  1494. SELECT bg.id_ban_group, bg.name
  1495. FROM {db_prefix}ban_groups AS bg
  1496. INNER JOIN {db_prefix}ban_items AS bi ON
  1497. (bi.id_ban_group = bg.id_ban_group)
  1498. AND ip_low1 = {int:ip_low1} AND ip_high1 = {int:ip_high1}
  1499. AND ip_low2 = {int:ip_low2} AND ip_high2 = {int:ip_high2}
  1500. AND ip_low3 = {int:ip_low3} AND ip_high3 = {int:ip_high3}
  1501. AND ip_low4 = {int:ip_low4} AND ip_high4 = {int:ip_high4}
  1502. LIMIT 1',
  1503. $values
  1504. );
  1505. if ($smcFunc['db_num_rows']($request) != 0)
  1506. {
  1507. list ($error_id_ban, $error_ban_name) = $smcFunc['db_fetch_row']($request);
  1508. fatal_lang_error('ban_trigger_already_exists', false, array(
  1509. $fullip,
  1510. '<a href="' . $scripturl . '?action=admin;area=ban;sa=edit;bg=' . $error_id_ban . '">' . $error_ban_name . '</a>',
  1511. ));
  1512. }
  1513. $smcFunc['db_free_result']($request);
  1514. return $values;
  1515. }
  1516. /**
  1517. * As it says... this tries to review the list of banned members, to match new bans.
  1518. * Note: is_activated >= 10: a member is banned.
  1519. */
  1520. function updateBanMembers()
  1521. {
  1522. global $smcFunc;
  1523. $updates = array();
  1524. $allMembers = array();
  1525. $newMembers = array();
  1526. // Start by getting all active bans - it's quicker doing this in parts...
  1527. $request = $smcFunc['db_query']('', '
  1528. SELECT bi.id_member, bi.email_address
  1529. FROM {db_prefix}ban_items AS bi
  1530. INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group)
  1531. WHERE (bi.id_member > {int:no_member} OR bi.email_address != {string:blank_string})
  1532. AND bg.cannot_access = {int:cannot_access_on}
  1533. AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time})',
  1534. array(
  1535. 'no_member' => 0,
  1536. 'cannot_access_on' => 1,
  1537. 'current_time' => time(),
  1538. 'blank_string' => '',
  1539. )
  1540. );
  1541. $memberIDs = array();
  1542. $memberEmails = array();
  1543. $memberEmailWild = array();
  1544. while ($row = $smcFunc['db_fetch_assoc']($request))
  1545. {
  1546. if ($row['id_member'])
  1547. $memberIDs[$row['id_member']] = $row['id_member'];
  1548. if ($row['email_address'])
  1549. {
  1550. // Does it have a wildcard - if so we can't do a IN on it.
  1551. if (strpos($row['email_address'], '%') !== false)
  1552. $memberEmailWild[$row['email_address']] = $row['email_address'];
  1553. else
  1554. $memberEmails[$row['email_address']] = $row['email_address'];
  1555. }
  1556. }
  1557. $smcFunc['db_free_result']($request);
  1558. // Build up the query.
  1559. $queryPart = array();
  1560. $queryValues = array();
  1561. if (!empty($memberIDs))
  1562. {
  1563. $queryPart[] = 'mem.id_member IN ({array_string:member_ids})';
  1564. $queryValues['member_ids'] = $memberIDs;
  1565. }
  1566. if (!empty($memberEmails))
  1567. {
  1568. $queryPart[] = 'mem.email_address IN ({array_string:member_emails})';
  1569. $queryValues['member_emails'] = $memberEmails;
  1570. }
  1571. $count = 0;
  1572. foreach ($memberEmailWild as $email)
  1573. {
  1574. $queryPart[] = 'mem.email_address LIKE {string:wild_' . $count . '}';
  1575. $queryValues['wild_' . $count++] = $email;
  1576. }
  1577. // Find all banned members.
  1578. if (!empty($queryPart))
  1579. {
  1580. $request = $smcFunc['db_query']('', '
  1581. SELECT mem.id_member, mem.is_activated
  1582. FROM {db_prefix}members AS mem
  1583. WHERE ' . implode( ' OR ', $queryPart),
  1584. $queryValues
  1585. );
  1586. while ($row = $smcFunc['db_fetch_assoc']($request))
  1587. {
  1588. if (!in_array($row['id_member'], $allMembers))
  1589. {
  1590. $allMembers[] = $row['id_member'];
  1591. // Do they need an update?
  1592. if ($row['is_activated'] < 10)
  1593. {
  1594. $updates[($row['is_activated'] + 10)][] = $row['id_member'];
  1595. $newMembers[] = $row['id_member'];
  1596. }
  1597. }
  1598. }
  1599. $smcFunc['db_free_result']($request);
  1600. }
  1601. // We welcome our new members in the realm of the banned.
  1602. if (!empty($newMembers))
  1603. $smcFunc['db_query']('', '
  1604. DELETE FROM {db_prefix}log_online
  1605. WHERE id_member IN ({array_int:new_banned_members})',
  1606. array(
  1607. 'new_banned_members' => $newMembers,
  1608. )
  1609. );
  1610. // Find members that are wrongfully marked as banned.
  1611. $request = $smcFunc['db_query']('', '
  1612. SELECT mem.id_member, mem.is_activated - 10 AS new_value
  1613. FROM {db_prefix}members AS mem
  1614. LEFT JOIN {db_prefix}ban_items AS bi ON (bi.id_member = mem.id_member OR mem.email_address LIKE bi.email_address)
  1615. LEFT JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group AND bg.cannot_access = {int:cannot_access_activated} AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time}))
  1616. WHERE (bi.id_ban IS NULL OR bg.id_ban_group IS NULL)
  1617. AND mem.is_activated >= {int:ban_flag}',
  1618. array(
  1619. 'cannot_access_activated' => 1,
  1620. 'current_time' => time(),
  1621. 'ban_flag' => 10,
  1622. )
  1623. );
  1624. while ($row = $smcFunc['db_fetch_assoc']($request))
  1625. {
  1626. // Don't do this twice!
  1627. if (!in_array($row['id_member'], $allMembers))
  1628. {
  1629. $updates[$row['new_value']][] = $row['id_member'];
  1630. $allMembers[] = $row['id_member'];
  1631. }
  1632. }
  1633. $smcFunc['db_free_result']($request);
  1634. if (!empty($updates))
  1635. foreach ($updates as $newStatus => $members)
  1636. updateMemberData($members, array('is_activated' => $newStatus));
  1637. // Update the latest member and our total members as banning may change them.
  1638. updateStats('member');
  1639. }
  1640. ?>