1: | <?php
|
2: |
|
3: | use Xmf\Request;
|
4: |
|
5: |
|
6: | include_once __DIR__ . '/admin_header.php';
|
7: | xoops_cp_header();
|
8: | include __DIR__ . '/mymenu.php';
|
9: | require_once XOOPS_ROOT_PATH . '/class/pagenav.php';
|
10: | require_once dirname(__DIR__) . '/class/gtickets.php';
|
11: |
|
12: |
|
13: | if (isset($_GET['num'])) {
|
14: | $_SERVER['REQUEST_URI'] = 'admin/center.php?page=center';
|
15: | }
|
16: |
|
17: | $myts = \MyTextSanitizer::getInstance();
|
18: | $db = XoopsDatabaseFactory::getDatabaseConnection();
|
19: |
|
20: |
|
21: | $pos = Request::getInt('pos', 0, 'GET');
|
22: | $num = Request::getInt('num', 20, 'GET');
|
23: |
|
24: |
|
25: | $log_table = $db->prefix($mydirname . '_log');
|
26: |
|
27: |
|
28: | require_once dirname(__DIR__) . '/class/protector.php';
|
29: | $db = XoopsDatabaseFactory::getDatabaseConnection();
|
30: | $protector = Protector::getInstance($db->conn);
|
31: | $conf = $protector->getConf();
|
32: |
|
33: |
|
34: |
|
35: |
|
36: |
|
37: | if (!empty($_POST['action'])) {
|
38: |
|
39: |
|
40: | if (!$xoopsGTicket->check(true, 'protector_admin')) {
|
41: | redirect_header(XOOPS_URL . '/', 3, $xoopsGTicket->getErrors());
|
42: | }
|
43: |
|
44: | if ($_POST['action'] === 'update_ips') {
|
45: | $error_msg = '';
|
46: |
|
47: | $lines = empty($_POST['bad_ips']) ? array() : explode("\n", trim($_POST['bad_ips']));
|
48: | $bad_ips = array();
|
49: | foreach ($lines as $line) {
|
50: | @list($bad_ip, $jailed_time) = explode('|', $line, 2);
|
51: | $bad_ips[trim($bad_ip)] = empty($jailed_time) ? 0x7fffffff : (int)$jailed_time;
|
52: | }
|
53: | if (!$protector->write_file_badips($bad_ips)) {
|
54: | $error_msg .= _AM_MSG_BADIPSCANTOPEN;
|
55: | }
|
56: |
|
57: | $group1_ips = empty($_POST['group1_ips']) ? array() : explode("\n", trim($_POST['group1_ips']));
|
58: | foreach (array_keys($group1_ips) as $i) {
|
59: | $group1_ips[$i] = trim($group1_ips[$i]);
|
60: | }
|
61: | $fp = @fopen($protector->get_filepath4group1ips(), 'w');
|
62: | if ($fp) {
|
63: | @flock($fp, LOCK_EX);
|
64: | fwrite($fp, serialize(array_unique($group1_ips)) . "\n");
|
65: | @flock($fp, LOCK_UN);
|
66: | fclose($fp);
|
67: | } else {
|
68: | $error_msg .= _AM_MSG_GROUP1IPSCANTOPEN;
|
69: | }
|
70: |
|
71: | $redirect_msg = $error_msg ? : _AM_MSG_IPFILESUPDATED;
|
72: | redirect_header('center.php?page=center', 2, $redirect_msg);
|
73: | exit;
|
74: | } elseif ($_POST['action'] === 'delete' && isset($_POST['ids']) && \is_array($_POST['ids'])) {
|
75: |
|
76: | foreach ($_POST['ids'] as $lid) {
|
77: | $lid = (int)$lid;
|
78: | $db->query("DELETE FROM $log_table WHERE lid='$lid'");
|
79: | }
|
80: | redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
|
81: | exit;
|
82: | } elseif ($_POST['action'] === 'banbyip' && isset($_POST['ids']) && \is_array($_POST['ids'])) {
|
83: |
|
84: | foreach ($_POST['ids'] as $lid) {
|
85: | $lid = (int)$lid;
|
86: | $sql = "SELECT `ip` FROM $log_table WHERE lid='$lid'";
|
87: | $result = $db->query($sql);
|
88: |
|
89: | if (!$db->isResultSet($result)) {
|
90: | list($ip) = $db->fetchRow($result);
|
91: | $protector->register_bad_ips(0, $ip);
|
92: | }
|
93: |
|
94: | if ($db->isResultSet($result)) {
|
95: | $db->freeRecordSet($result);
|
96: | }
|
97: |
|
98: | }
|
99: | redirect_header('center.php?page=center', 2, _AM_MSG_BANNEDIP);
|
100: | exit;
|
101: | } elseif ($_POST['action'] === 'deleteall') {
|
102: |
|
103: | $db->query("DELETE FROM $log_table");
|
104: | redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
|
105: | exit;
|
106: | } elseif ($_POST['action'] === 'compactlog') {
|
107: |
|
108: | $sql = "SELECT `lid`,`ip`,`type` FROM $log_table ORDER BY lid DESC";
|
109: | $result = $db->query($sql);
|
110: | if (!$db->isResultSet($result)) {
|
111: | throw new \RuntimeException(
|
112: | \sprintf(_DB_QUERY_ERROR, $sql) . $db->error(), E_USER_ERROR
|
113: | );
|
114: | }
|
115: | $buf = array();
|
116: | $ids = array();
|
117: | while (false !== (list($lid, $ip, $type) = $db->fetchRow($result))) {
|
118: | if (isset($buf[$ip . $type])) {
|
119: | $ids[] = $lid;
|
120: | } else {
|
121: | $buf[$ip . $type] = true;
|
122: | }
|
123: | }
|
124: | $db->query("DELETE FROM $log_table WHERE lid IN (" . implode(',', $ids) . ')');
|
125: | redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
|
126: | exit;
|
127: | }
|
128: | }
|
129: |
|
130: |
|
131: |
|
132: |
|
133: |
|
134: |
|
135: | $sql = "SELECT count(lid) FROM $log_table";
|
136: | $result = $db->query($sql);
|
137: | if (!$db->isResultSet($result)) {
|
138: | throw new \RuntimeException(
|
139: | \sprintf(_DB_QUERY_ERROR, $sql) . $db->error(), E_USER_ERROR
|
140: | );
|
141: | }
|
142: | list($numrows) = $db->fetchRow($result);
|
143: |
|
144: | $sql = "SELECT l.lid, l.uid, l.ip, l.agent, l.type, l.description, UNIX_TIMESTAMP(l.timestamp), u.uname FROM $log_table l LEFT JOIN " . $db->prefix('users') . " u ON l.uid=u.uid ORDER BY timestamp DESC LIMIT $pos,$num";
|
145: | $result = $db->query($sql);
|
146: | if (!$db->isResultSet($result)) {
|
147: | throw new \RuntimeException(
|
148: | \sprintf(_DB_QUERY_ERROR, $sql) . $db->error(), E_USER_ERROR
|
149: | );
|
150: | }
|
151: |
|
152: |
|
153: | $nav = new XoopsPageNav($numrows, $num, $pos, 'pos', "page=center&num=$num");
|
154: | $nav_html = $nav->renderNav(10);
|
155: |
|
156: |
|
157: | $num_options = '';
|
158: | $num_array = array(20, 100, 500, 2000);
|
159: | foreach ($num_array as $n) {
|
160: | if ($n == $num) {
|
161: | $num_options .= "<option value='$n' selected>$n</option>\n";
|
162: | } else {
|
163: | $num_options .= "<option value='$n'>$n</option>\n";
|
164: | }
|
165: | }
|
166: |
|
167: |
|
168: |
|
169: |
|
170: | echo "<h3 style='text-align:left;'>" . $xoopsModule->name() . "</h3>\n";
|
171: | echo '<style>td.log_description {width: 60em; display: inline-block; word-wrap: break-word; white-space: pre-line;}</style>';
|
172: |
|
173: |
|
174: | if (!is_writable(dirname(__DIR__) . '/configs')) {
|
175: | printf("<p style='color:red;font-weight:bold;'>" . _AM_FMT_CONFIGSNOTWRITABLE . "</p>\n", dirname(__DIR__) . '/configs');
|
176: | }
|
177: |
|
178: |
|
179: | $bad_ips = $protector->get_bad_ips(true);
|
180: | uksort($bad_ips, 'protector_ip_cmp');
|
181: | $bad_ips4disp = '';
|
182: | foreach ($bad_ips as $bad_ip => $jailed_time) {
|
183: | $line = $jailed_time ? $bad_ip . '|' . $jailed_time : $bad_ip;
|
184: | $line = str_replace('|2147483647', '', $line);
|
185: | $bad_ips4disp .= htmlspecialchars($line, ENT_QUOTES) . "\n";
|
186: | }
|
187: |
|
188: |
|
189: | $group1_ips = $protector->get_group1_ips();
|
190: | usort($group1_ips, 'protector_ip_cmp');
|
191: | $group1_ips4disp = htmlspecialchars(implode("\n", $group1_ips), ENT_QUOTES);
|
192: |
|
193: |
|
194: | echo "
|
195: | <form name='ConfigForm' action='' method='POST'>
|
196: | " . $xoopsGTicket->getTicketHtml(__LINE__, 1800, 'protector_admin') . "
|
197: | <input type='hidden' name='action' value='update_ips' />
|
198: | <table width='95%' class='outer' cellpadding='4' cellspacing='1'>
|
199: | <tr valign='top' align='left'>
|
200: | <td class='head'>
|
201: | " . _AM_TH_BADIPS . "
|
202: | </td>
|
203: | <td class='even'>
|
204: | <textarea name='bad_ips' id='bad_ips' style='width:360px;height:60px;' spellcheck='false'>$bad_ips4disp</textarea>
|
205: | <br>
|
206: | " . htmlspecialchars($protector->get_filepath4badips(), ENT_QUOTES) . "
|
207: | </td>
|
208: | </tr>
|
209: | <tr valign='top' align='left'>
|
210: | <td class='head'>
|
211: | " . _AM_TH_GROUP1IPS . "
|
212: | </td>
|
213: | <td class='even'>
|
214: | <textarea name='group1_ips' id='group1_ips' style='width:360px;height:60px;' spellcheck='false'>$group1_ips4disp</textarea>
|
215: | <br>
|
216: | " . htmlspecialchars($protector->get_filepath4group1ips(), ENT_QUOTES) . "
|
217: | </td>
|
218: | </tr>
|
219: | <tr valign='top' align='left'>
|
220: | <td class='head'>
|
221: | </td>
|
222: | <td class='even'>
|
223: | <input type='submit' value='" . _GO . "' />
|
224: | </td>
|
225: | </tr>
|
226: | </table>
|
227: | </form>
|
228: | ";
|
229: |
|
230: |
|
231: | echo "
|
232: | <table width='95%' border='0' cellpadding='4' cellspacing='0'><tr><td>
|
233: | <form action='' method='GET' style='margin-bottom:0;'>
|
234: | <table width='95%' border='0' cellpadding='4' cellspacing='0'>
|
235: | <tr>
|
236: | <td align='left'>
|
237: | <select name='num' onchange='submit();'>$num_options</select>
|
238: | <input type='submit' value='" . _SUBMIT . "'>
|
239: | </td>
|
240: | <td align='right'>
|
241: | $nav_html
|
242: | </td>
|
243: | </tr>
|
244: | </table>
|
245: | </form>
|
246: | <form name='MainForm' action='' method='POST' style='margin-top:0;'>
|
247: | " . $xoopsGTicket->getTicketHtml(__LINE__, 1800, 'protector_admin') . "
|
248: | <input type='hidden' name='action' value='' />
|
249: | <table width='95%' class='outer' cellpadding='4' cellspacing='1'>
|
250: | <tr valign='middle'>
|
251: | <th width='5'><input type='checkbox' name='dummy' onclick=\"with(document.MainForm){for (i=0;i<length;i++) {if (elements[i].type=='checkbox') {elements[i].checked=this.checked;}}}\" /></th>
|
252: | <th>" . _AM_TH_DATETIME . '</th>
|
253: | <th>' . _AM_TH_USER . '</th>
|
254: | <th>' . _AM_TH_IP . '<br>' . _AM_TH_AGENT . '</th>
|
255: | <th>' . _AM_TH_TYPE . '</th>
|
256: | <th>' . _AM_TH_DESCRIPTION . '</th>
|
257: | </tr>
|
258: | ';
|
259: |
|
260: |
|
261: | $oddeven = 'odd';
|
262: | while (false !== (list($lid, $uid, $ip, $agent, $type, $description, $timestamp, $uname) = $db->fetchRow($result))) {
|
263: | $oddeven = ($oddeven === 'odd' ? 'even' : 'odd');
|
264: | $style = '';
|
265: |
|
266: | $ip = htmlspecialchars($ip, ENT_QUOTES);
|
267: | $type = htmlspecialchars($type, ENT_QUOTES);
|
268: | if ('{"' == substr($description, 0, 2) && defined('JSON_PRETTY_PRINT')) {
|
269: | $temp = json_decode($description);
|
270: | if (is_object($temp)) {
|
271: | $description = json_encode($temp, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
|
272: | $style = ' log_description';
|
273: | }
|
274: | }
|
275: | $description = htmlspecialchars($description, ENT_QUOTES);
|
276: | $uname = htmlspecialchars(($uid ? $uname : _GUESTS), ENT_QUOTES);
|
277: |
|
278: |
|
279: | if (preg_match('/Chrome\/([0-9.]+)/', $agent, $regs)) {
|
280: | $agent_short = 'Chrome ' . $regs[1];
|
281: | } elseif (preg_match('/MSIE\s+([0-9.]+)/', $agent, $regs)) {
|
282: | $agent_short = 'IE ' . $regs[1];
|
283: | } elseif (false !== stripos($agent, 'Gecko')) {
|
284: | $agent_short = strrchr($agent, ' ');
|
285: | } else {
|
286: | $agent_short = substr($agent, 0, strpos($agent, ' '));
|
287: | }
|
288: | $agent4disp = htmlspecialchars($agent, ENT_QUOTES);
|
289: | $agent_desc = $agent == $agent_short ? $agent4disp : htmlspecialchars($agent_short, ENT_QUOTES) . "<img src='../images/dotdotdot.gif' alt='$agent4disp' title='$agent4disp' />";
|
290: |
|
291: | echo "
|
292: | <tr>
|
293: | <td class='$oddeven'><input type='checkbox' name='ids[]' value='$lid' /></td>
|
294: | <td class='$oddeven'>" . formatTimestamp($timestamp) . "</td>
|
295: | <td class='$oddeven'>$uname</td>
|
296: | <td class='$oddeven'>$ip<br>$agent_desc</td>
|
297: | <td class='$oddeven'>$type</td>
|
298: | <td class='{$oddeven}{$style}'>$description</td>
|
299: | </tr>\n";
|
300: | }
|
301: |
|
302: |
|
303: | echo "
|
304: | <tr>
|
305: | <td colspan='8' align='left'>" . _AM_LABEL_REMOVE . "<input type='button' value='" . _AM_BUTTON_REMOVE . "' onclick='if (confirm(\"" . _AM_JS_REMOVECONFIRM . "\")) {document.MainForm.action.value=\"delete\"; submit();}' />
|
306: |   " . _AM_LABEL_BAN_BY_IP . "<input type='button' value='" . _AM_BUTTON_BAN_BY_IP . "' onclick='if (confirm(\"" . _AM_JS_BANCONFIRM . "\")) {document.MainForm.action.value=\"banbyip\"; submit();}' /></td>
|
307: | </tr>
|
308: | </table>
|
309: | <div align='right'>
|
310: | $nav_html
|
311: | </div>
|
312: | <div style='clear:both;'><br><br></div>
|
313: | <div align='right'>
|
314: | " . _AM_LABEL_COMPACTLOG . "<input type='button' value='" . _AM_BUTTON_COMPACTLOG . "' onclick='if (confirm(\"" . _AM_JS_COMPACTLOGCONFIRM . "\")) {document.MainForm.action.value=\"compactlog\"; submit();}' />
|
315: |
|
316: | " . _AM_LABEL_REMOVEALL . "<input type='button' value='" . _AM_BUTTON_REMOVEALL . "' onclick='if (confirm(\"" . _AM_JS_REMOVEALLCONFIRM . "\")) {document.MainForm.action.value=\"deleteall\"; submit();}' />
|
317: | </div>
|
318: | </form>
|
319: | </td></tr></table>
|
320: | ";
|
321: |
|
322: | xoops_cp_footer();
|
323: |
|
324: | |
325: | |
326: | |
327: | |
328: | |
329: | |
330: | |
331: |
|
332: | function protector_ip_cmp($a, $b)
|
333: | {
|
334: |
|
335: | if ((false === strpos($a, ':')) && false !== strpos($b, ':')) {
|
336: | return -1;
|
337: | }
|
338: |
|
339: | if ((false === strpos($a, '.')) && false !== strpos($b, '.')) {
|
340: | return 1;
|
341: | }
|
342: |
|
343: | if ((is_int(strpos($a, '.'))) && (is_int(strpos($b, '.')))) {
|
344: | $a = protector_normalize_ipv4($a);
|
345: | $b = protector_normalize_ipv4($b);
|
346: | }
|
347: | return strcasecmp($a, $b);
|
348: | }
|
349: |
|
350: | |
351: | |
352: | |
353: | |
354: | |
355: | |
356: |
|
357: | function protector_normalize_ipv4($n)
|
358: | {
|
359: | $temp = explode('.', $n);
|
360: | $n = '';
|
361: | foreach($temp as $k=>$v) {
|
362: | $t = '00'. $v;
|
363: | $n .= substr($t, -3);
|
364: | if ($k<3) {
|
365: | $n .= '.';
|
366: | }
|
367: | }
|
368: | return $n;
|
369: | }
|
370: | |