Passed
Push — master ( d31165...fcd029 )
by Richard
05:52 queued 19s
created

protector_ip_cmp()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 8
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 16
rs 8.8333
1
<?php
2
//require_once XOOPS_ROOT_PATH.'/include/cp_header.php' ;
3
include_once 'admin_header.php'; //mb problem: it shows always the same "Center" tab
4
xoops_cp_header();
5
include __DIR__ . '/mymenu.php';
6
require_once XOOPS_ROOT_PATH . '/class/pagenav.php';
7
require_once dirname(__DIR__) . '/class/gtickets.php';
8
9
//dirty trick to get navigation working with system menus
10
if (isset($_GET['num'])) {
11
    $_SERVER['REQUEST_URI'] = 'admin/center.php?page=center';
12
}
13
14
$myts = MyTextSanitizer::getInstance();
15
$db   = XoopsDatabaseFactory::getDatabaseConnection();
16
17
// GET vars
18
$pos = empty($_GET['pos']) ? 0 : (int)$_GET['pos'];
19
$num = empty($_GET['num']) ? 20 : (int)$_GET['num'];
20
21
// Table Name
22
$log_table = $db->prefix($mydirname . '_log');
23
24
// Protector object
25
require_once dirname(__DIR__) . '/class/protector.php';
26
$db        = XoopsDatabaseFactory::getDatabaseConnection();
27
$protector = Protector::getInstance($db->conn);
0 ignored issues
show
Unused Code introduced by
The call to Protector::getInstance() has too many arguments starting with $db->conn. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

27
$protector = Protector::/** @scrutinizer ignore-call */ getInstance($db->conn);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
28
$conf      = $protector->getConf();
29
30
//
31
// transaction stage
32
//
33
34
if (!empty($_POST['action'])) {
35
36
    // Ticket check
37
    if (!$xoopsGTicket->check(true, 'protector_admin')) {
38
        redirect_header(XOOPS_URL . '/', 3, $xoopsGTicket->getErrors());
39
    }
40
41
    if ($_POST['action'] === 'update_ips') {
42
        $error_msg = '';
43
44
        $lines   = empty($_POST['bad_ips']) ? array() : explode("\n", trim($_POST['bad_ips']));
45
        $bad_ips = array();
46
        foreach ($lines as $line) {
47
            @list($bad_ip, $jailed_time) = explode('|', $line, 2);
48
            $bad_ips[trim($bad_ip)] = empty($jailed_time) ? 0x7fffffff : (int)$jailed_time;
49
        }
50
        if (!$protector->write_file_badips($bad_ips)) {
51
            $error_msg .= _AM_MSG_BADIPSCANTOPEN;
52
        }
53
54
        $group1_ips = empty($_POST['group1_ips']) ? array() : explode("\n", trim($_POST['group1_ips']));
55
        foreach (array_keys($group1_ips) as $i) {
56
            $group1_ips[$i] = trim($group1_ips[$i]);
57
        }
58
        $fp = @fopen($protector->get_filepath4group1ips(), 'w');
59
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
60
            @flock($fp, LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for flock(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

60
            /** @scrutinizer ignore-unhandled */ @flock($fp, LOCK_EX);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
61
            fwrite($fp, serialize(array_unique($group1_ips)) . "\n");
62
            @flock($fp, LOCK_UN);
63
            fclose($fp);
64
        } else {
65
            $error_msg .= _AM_MSG_GROUP1IPSCANTOPEN;
66
        }
67
68
        $redirect_msg = $error_msg ? : _AM_MSG_IPFILESUPDATED;
69
        redirect_header('center.php?page=center', 2, $redirect_msg);
70
        exit;
71
    } elseif ($_POST['action'] === 'delete' && isset($_POST['ids']) && is_array($_POST['ids'])) {
72
        // remove selected records
73
        foreach ($_POST['ids'] as $lid) {
74
            $lid = (int)$lid;
75
            $db->query("DELETE FROM $log_table WHERE lid='$lid'");
0 ignored issues
show
Bug introduced by
The method query() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
            $db->/** @scrutinizer ignore-call */ 
76
                 query("DELETE FROM $log_table WHERE lid='$lid'");
Loading history...
76
        }
77
        redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
78
        exit;
79
    } elseif ($_POST['action'] === 'banbyip' && isset($_POST['ids']) && is_array($_POST['ids'])) {
80
        // remove selected records
81
        foreach ($_POST['ids'] as $lid) {
82
            $lid = (int)$lid;
83
            $result = $db->query("SELECT `ip` FROM $log_table WHERE lid='$lid'");
84
            if (false !== $result) {
85
                list($ip) = $db->fetchRow($result);
0 ignored issues
show
Bug introduced by
The method fetchRow() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

85
                /** @scrutinizer ignore-call */ 
86
                list($ip) = $db->fetchRow($result);
Loading history...
86
                $protector->register_bad_ips(0, $ip);
87
            }
88
            $db->freeRecordSet($result);
0 ignored issues
show
Bug introduced by
The method freeRecordSet() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

88
            $db->/** @scrutinizer ignore-call */ 
89
                 freeRecordSet($result);
Loading history...
89
        }
90
        redirect_header('center.php?page=center', 2, _AM_MSG_BANNEDIP);
91
        exit;
92
    } elseif ($_POST['action'] === 'deleteall') {
93
        // remove all records
94
        $db->query("DELETE FROM $log_table");
95
        redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
96
        exit;
97
    } elseif ($_POST['action'] === 'compactlog') {
98
        // compactize records (removing duplicated records (ip,type)
99
        $result = $db->query("SELECT `lid`,`ip`,`type` FROM $log_table ORDER BY lid DESC");
100
        $buf    = array();
101
        $ids    = array();
102
        while (false !== (list($lid, $ip, $type) = $db->fetchRow($result))) {
103
            if (isset($buf[$ip . $type])) {
104
                $ids[] = $lid;
105
            } else {
106
                $buf[$ip . $type] = true;
107
            }
108
        }
109
        $db->query("DELETE FROM $log_table WHERE lid IN (" . implode(',', $ids) . ')');
110
        redirect_header('center.php?page=center', 2, _AM_MSG_REMOVED);
111
        exit;
112
    }
113
}
114
115
//
116
// display stage
117
//
118
119
// query for listing
120
$rs = $db->query("SELECT count(lid) FROM $log_table");
121
list($numrows) = $db->fetchRow($rs);
122
$prs = $db->query("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");
123
124
// Page Navigation
125
$nav      = new XoopsPageNav($numrows, $num, $pos, 'pos', "page=center&num=$num");
126
$nav_html = $nav->renderNav(10);
127
128
// Number selection
129
$num_options = '';
130
$num_array   = array(20, 100, 500, 2000);
131
foreach ($num_array as $n) {
132
    if ($n == $num) {
133
        $num_options .= "<option value='$n' selected>$n</option>\n";
134
    } else {
135
        $num_options .= "<option value='$n'>$n</option>\n";
136
    }
137
}
138
139
// beggining of Output
140
141
// title
142
echo "<h3 style='text-align:left;'>" . $xoopsModule->name() . "</h3>\n";
143
echo '<style>td.log_description {width: 60em; display: inline-block; word-wrap: break-word; white-space: pre-line;}</style>';
144
145
// configs writable check
146
if (!is_writable(dirname(__DIR__) . '/configs')) {
147
    printf("<p style='color:red;font-weight:bold;'>" . _AM_FMT_CONFIGSNOTWRITABLE . "</p>\n", dirname(__DIR__) . '/configs');
148
}
149
150
// bad_ips
151
$bad_ips = $protector->get_bad_ips(true);
152
uksort($bad_ips, 'protector_ip_cmp');
153
$bad_ips4disp = '';
154
foreach ($bad_ips as $bad_ip => $jailed_time) {
155
    $line = $jailed_time ? $bad_ip . '|' . $jailed_time : $bad_ip;
156
    $line = str_replace('|2147483647', '', $line); // remove :0x7fffffff
157
    $bad_ips4disp .= htmlspecialchars($line, ENT_QUOTES) . "\n";
158
}
159
160
// group1_ips
161
$group1_ips = $protector->get_group1_ips();
162
usort($group1_ips, 'protector_ip_cmp');
163
$group1_ips4disp = htmlspecialchars(implode("\n", $group1_ips), ENT_QUOTES);
164
165
// edit configs about IP ban and IPs for group=1
166
echo "
167
<form name='ConfigForm' action='' method='POST'>
168
" . $xoopsGTicket->getTicketHtml(__LINE__, 1800, 'protector_admin') . "
169
<input type='hidden' name='action' value='update_ips' />
170
<table width='95%' class='outer' cellpadding='4' cellspacing='1'>
171
  <tr valign='top' align='left'>
172
    <td class='head'>
173
      " . _AM_TH_BADIPS . "
174
    </td>
175
    <td class='even'>
176
      <textarea name='bad_ips' id='bad_ips' style='width:360px;height:60px;' spellcheck='false'>$bad_ips4disp</textarea>
177
      <br>
178
      " . htmlspecialchars($protector->get_filepath4badips()) . "
179
    </td>
180
  </tr>
181
  <tr valign='top' align='left'>
182
    <td class='head'>
183
      " . _AM_TH_GROUP1IPS . "
184
    </td>
185
    <td class='even'>
186
      <textarea name='group1_ips' id='group1_ips' style='width:360px;height:60px;' spellcheck='false'>$group1_ips4disp</textarea>
187
      <br>
188
      " . htmlspecialchars($protector->get_filepath4group1ips()) . "
189
    </td>
190
  </tr>
191
  <tr valign='top' align='left'>
192
    <td class='head'>
193
    </td>
194
    <td class='even'>
195
      <input type='submit' value='" . _GO . "' />
196
    </td>
197
  </tr>
198
</table>
199
</form>
200
";
201
202
// header of log listing
203
echo "
204
<table width='95%' border='0' cellpadding='4' cellspacing='0'><tr><td>
205
<form action='' method='GET' style='margin-bottom:0;'>
206
  <table width='95%' border='0' cellpadding='4' cellspacing='0'>
207
    <tr>
208
      <td align='left'>
209
        <select name='num' onchange='submit();'>$num_options</select>
210
        <input type='submit' value='" . _SUBMIT . "'>
211
      </td>
212
      <td align='right'>
213
        $nav_html
214
      </td>
215
    </tr>
216
  </table>
217
</form>
218
<form name='MainForm' action='' method='POST' style='margin-top:0;'>
219
" . $xoopsGTicket->getTicketHtml(__LINE__, 1800, 'protector_admin') . "
220
<input type='hidden' name='action' value='' />
221
<table width='95%' class='outer' cellpadding='4' cellspacing='1'>
222
  <tr valign='middle'>
223
    <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>
224
    <th>" . _AM_TH_DATETIME . '</th>
225
    <th>' . _AM_TH_USER . '</th>
226
    <th>' . _AM_TH_IP . '<br>' . _AM_TH_AGENT . '</th>
227
    <th>' . _AM_TH_TYPE . '</th>
228
    <th>' . _AM_TH_DESCRIPTION . '</th>
229
  </tr>
230
';
231
232
// body of log listing
233
$oddeven = 'odd';
234
while (false !== (list($lid, $uid, $ip, $agent, $type, $description, $timestamp, $uname) = $db->fetchRow($prs))) {
235
    $oddeven = ($oddeven === 'odd' ? 'even' : 'odd');
236
    $style = '';
237
238
    $ip = htmlspecialchars($ip, ENT_QUOTES);
239
    $type = htmlspecialchars($type, ENT_QUOTES);
240
    if ('{"' == substr($description, 0, 2) && defined('JSON_PRETTY_PRINT')) {
241
        $temp = json_decode($description);
242
        if (is_object($temp)) {
243
            $description = json_encode($temp, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
244
            $style = ' log_description';
245
        }
246
    }
247
    $description = htmlspecialchars($description, ENT_QUOTES);
248
    $uname = htmlspecialchars(($uid ? $uname : _GUESTS), ENT_QUOTES);
249
250
    // make agents shorter
251
    if (preg_match('/Chrome\/([0-9.]+)/', $agent, $regs)) {
252
        $agent_short = 'Chrome ' . $regs[1];
253
    } elseif (preg_match('/MSIE\s+([0-9.]+)/', $agent, $regs)) {
254
        $agent_short = 'IE ' . $regs[1];
255
    } elseif (false !== stripos($agent, 'Gecko')) {
256
        $agent_short = strrchr($agent, ' ');
257
    } else {
258
        $agent_short = substr($agent, 0, strpos($agent, ' '));
259
    }
260
    $agent4disp = htmlspecialchars($agent, ENT_QUOTES);
261
    $agent_desc = $agent == $agent_short ? $agent4disp : htmlspecialchars($agent_short, ENT_QUOTES) . "<img src='../images/dotdotdot.gif' alt='$agent4disp' title='$agent4disp' />";
262
263
    echo "
264
  <tr>
265
    <td class='$oddeven'><input type='checkbox' name='ids[]' value='$lid' /></td>
266
    <td class='$oddeven'>" . formatTimestamp($timestamp) . "</td>
267
    <td class='$oddeven'>$uname</td>
268
    <td class='$oddeven'>$ip<br>$agent_desc</td>
269
    <td class='$oddeven'>$type</td>
270
    <td class='{$oddeven}{$style}'>$description</td>
271
  </tr>\n";
272
}
273
274
// footer of log listing
275
echo "
276
  <tr>
277
    <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();}' />
278
    &nbsp " . _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>
279
  </tr>
280
</table>
281
<div align='right'>
282
  $nav_html
283
</div>
284
<div style='clear:both;'><br><br></div>
285
<div align='right'>
286
" . _AM_LABEL_COMPACTLOG . "<input type='button' value='" . _AM_BUTTON_COMPACTLOG . "' onclick='if (confirm(\"" . _AM_JS_COMPACTLOGCONFIRM . "\")) {document.MainForm.action.value=\"compactlog\"; submit();}' />
287
&nbsp;
288
" . _AM_LABEL_REMOVEALL . "<input type='button' value='" . _AM_BUTTON_REMOVEALL . "' onclick='if (confirm(\"" . _AM_JS_REMOVEALLCONFIRM . "\")) {document.MainForm.action.value=\"deleteall\"; submit();}' />
289
</div>
290
</form>
291
</td></tr></table>
292
";
293
294
xoops_cp_footer();
295
296
/**
297
 * Callback used by uksort and usort for ip sorting
298
 *
299
 * @param string $a
300
 * @param string $b
301
 *
302
 * @return int
303
 */
304
function protector_ip_cmp($a, $b)
305
{
306
    // ipv6 below ipv4
307
    if ((false === strpos($a, ':')) && false !== strpos($b, ':')) {
308
        return -1;
309
    }
310
    // ipv4 above ipv6
311
    if ((false === strpos($a, '.')) && false !== strpos($b, '.')) {
312
        return 1;
313
    }
314
    // normalize ipv4 before comparing
315
    if ((is_int(strpos($a, '.'))) && (is_int(strpos($b, '.')))) {
0 ignored issues
show
introduced by
The condition is_int(strpos($b, '.')) is always true.
Loading history...
316
        $a = protector_normalize_ipv4($a);
317
        $b = protector_normalize_ipv4($b);
318
    }
319
    return strcasecmp($a, $b);
320
}
321
322
/**
323
 * pad all octets in an ipv4 address to 3 digits for sorting
324
 *
325
 * @param string $n ipv4 address
326
 *
327
 * @return string
328
 */
329
function protector_normalize_ipv4($n)
330
{
331
    $temp = explode('.', $n);
332
    $n = '';
333
    foreach($temp as $k=>$v) {
334
        $t = '00'. $v;
335
        $n .= substr($t, -3);
336
        if ($k<3) {
337
            $n .= '.';
338
        }
339
    }
340
    return $n;
341
}
342