Completed
Pull Request — master (#133)
by Goffy
16:45
created

Protector::setConn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class Protector
5
 */
6
class Protector
7
{
8
    public $mydirname;
9
10
    public $_conn;
11
    public $_conf            = array();
12
    public $_conf_serialized = '';
13
14
    public $_bad_globals = array();
15
16
    public $message                = '';
17
    public $warning                = false;
18
    public $error                  = false;
19
    public $_doubtful_requests     = array();
20
    public $_bigumbrella_doubtfuls = array();
21
22
    public $_dblayertrap_doubtfuls        = array();
23
    public $_dblayertrap_doubtful_needles = array(
24
        'information_schema',
25
        'select',
26
        "'",
27
        '"');
28
29
    public $_logged = false;
30
31
    public $_done_badext   = false;
32
    public $_done_intval   = false;
33
    public $_done_dotdot   = false;
34
    public $_done_nullbyte = false;
35
    public $_done_contami  = false;
36
    public $_done_isocom   = false;
37
    public $_done_union    = false;
38
    public $_done_dos      = false;
39
40
    public $_safe_badext  = true;
41
    public $_safe_contami = true;
42
    public $_safe_isocom  = true;
43
    public $_safe_union   = true;
44
45
    public $_spamcount_uri = 0;
46
47
    public $_should_be_banned_time0 = false;
48
    public $_should_be_banned       = false;
49
50
    public $_dos_stage;
51
52
    public $ip_matched_info;
53
54
    public $last_error_type = 'UNKNOWN';
55
56
    /**
57
     * Constructor
58
     */
59
    protected function __construct()
60
    {
61
        $this->mydirname = 'protector';
62
63
        // Preferences from configs/cache
64
        $this->_conf_serialized = @file_get_contents($this->get_filepath4confighcache());
65
        $this->_conf            = @unserialize($this->_conf_serialized);
66
        if (empty($this->_conf)) {
67
            $this->_conf = array();
68
        }
69
70
        if (!empty($this->_conf['global_disabled'])) {
71
            return;
72
        }
73
74
        // die if PHP_SELF XSS found (disabled in 2.53)
75
        //    if ( preg_match( '/[<>\'";\n ]/' , @$_SERVER['PHP_SELF'] ) ) {
76
        //        $this->message .= "Invalid PHP_SELF '{$_SERVER['PHP_SELF']}' found.\n" ;
77
        //        $this->output_log( 'PHP_SELF XSS' ) ;
78
        //        die( 'invalid PHP_SELF' ) ;
79
        //    }
80
81
        // sanitize against PHP_SELF/PATH_INFO XSS (disabled in 3.33)
82
        //    $_SERVER['PHP_SELF'] = strtr( @$_SERVER['PHP_SELF'] , array( '<' => '%3C' , '>' => '%3E' , "'" => '%27' , '"' => '%22' ) ) ;
83
        //    if( ! empty( $_SERVER['PATH_INFO'] ) ) $_SERVER['PATH_INFO'] = strtr( @$_SERVER['PATH_INFO'] , array( '<' => '%3C' , '>' => '%3E' , "'" => '%27' , '"' => '%22' ) ) ;
84
85
        $this->_bad_globals = array(
86
            'GLOBALS',
87
            '_SESSION',
88
            'HTTP_SESSION_VARS',
89
            '_GET',
90
            'HTTP_GET_VARS',
91
            '_POST',
92
            'HTTP_POST_VARS',
93
            '_COOKIE',
94
            'HTTP_COOKIE_VARS',
95
            '_SERVER',
96
            'HTTP_SERVER_VARS',
97
            '_REQUEST',
98
            '_ENV',
99
            '_FILES',
100
            'xoopsDB',
101
            'xoopsUser',
102
            'xoopsUserId',
103
            'xoopsUserGroups',
104
            'xoopsUserIsAdmin',
105
            'xoopsConfig',
106
            'xoopsOption',
107
            'xoopsModule',
108
            'xoopsModuleConfig');
109
110
        $this->_initial_recursive($_GET, 'G');
111
        $this->_initial_recursive($_POST, 'P');
112
        $this->_initial_recursive($_COOKIE, 'C');
113
    }
114
115
    /**
116
     * @param $val
117
     * @param $key
118
     */
119
    protected function _initial_recursive($val, $key)
120
    {
121
        if (is_array($val)) {
122
            foreach ($val as $subkey => $subval) {
123
                // check bad globals
124 View Code Duplication
                if (in_array($subkey, $this->_bad_globals, true)) {
125
                    $this->message .= "Attempt to inject '$subkey' was found.\n";
126
                    $this->_safe_contami   = false;
127
                    $this->last_error_type = 'CONTAMI';
128
                }
129
                $this->_initial_recursive($subval, $key . '_' . base64_encode($subkey));
130
            }
131
        } else {
132
            // check nullbyte attack
133
            if (@$this->_conf['san_nullbyte'] && false !== strpos($val, chr(0))) {
134
                $val = str_replace(chr(0), ' ', $val);
135
                $this->replace_doubtful($key, $val);
136
                $this->message .= "Injecting Null-byte '$val' found.\n";
137
                $this->output_log('NullByte', 0, false, 32);
138
                // $this->purge() ;
139
            }
140
141
            // register as doubtful requests against SQL Injections
142
            if (preg_match('?[\s\'"`/]?', $val)) {
143
                $this->_doubtful_requests["$key"] = $val;
144
            }
145
        }
146
    }
147
148
    /**
149
     * @return Protector
150
     */
151
    public static function getInstance()
152
    {
153
        static $instance;
154
        if (!isset($instance)) {
155
            $instance = new Protector();
156
        }
157
158
        return $instance;
159
    }
160
161
    /**
162
     * @return bool
163
     */
164
    public function updateConfFromDb()
165
    {
166
        $constpref = '_MI_' . strtoupper($this->mydirname);
167
168
        if (empty($this->_conn)) {
169
            return false;
170
        }
171
172
        $result = @mysqli_query($this->_conn, 'SELECT conf_name,conf_value FROM ' . XOOPS_DB_PREFIX . "_config WHERE conf_title like '" . $constpref . "%'");
173
        if (!$result || mysqli_num_rows($result) < 5) {
174
            return false;
175
        }
176
        $db_conf = array();
177
        while (list($key, $val) = mysqli_fetch_row($result)) {
178
            $db_conf[$key] = $val;
179
        }
180
        $db_conf_serialized = serialize($db_conf);
181
182
        // update config cache
183
        if ($db_conf_serialized != $this->_conf_serialized) {
184
            $fp = fopen($this->get_filepath4confighcache(), 'w');
185
            fwrite($fp, $db_conf_serialized);
186
            fclose($fp);
187
            $this->_conf = $db_conf;
188
        }
189
190
        return true;
191
    }
192
193
    /**
194
     * @param $conn
195
     */
196
    public function setConn($conn)
197
    {
198
        $this->_conn = $conn;
199
    }
200
201
    /**
202
     * @return array
203
     */
204
    public function getConf()
205
    {
206
        return $this->_conf;
207
    }
208
209
    /**
210
     * @param bool $redirect_to_top
211
     */
212
    public function purge($redirect_to_top = false)
213
    {
214
        // clear all session values
215
        if (isset($_SESSION)) {
216
            foreach ($_SESSION as $key => $val) {
217
                $_SESSION[$key] = '';
218
                if (isset($GLOBALS[$key])) {
219
                    $GLOBALS[$key] = '';
220
                }
221
            }
222
        }
223
224
        if (!headers_sent()) {
225
            // clear typical session id of PHP
226
            setcookie('PHPSESSID', '', time() - 3600, '/', '', 0);
227
            if (isset($_COOKIE[session_name()])) {
228
                setcookie(session_name(), '', time() - 3600, '/', '', 0);
229
            }
230
231
            // clear autologin cookie
232
            $xoops_cookie_path = defined('XOOPS_COOKIE_PATH') ? XOOPS_COOKIE_PATH : preg_replace('?http://[^/]+(/.*)$?', "$1", XOOPS_URL);
233
            if ($xoops_cookie_path == XOOPS_URL) {
234
                $xoops_cookie_path = '/';
235
            }
236
            setcookie('autologin_uname', '', time() - 3600, $xoops_cookie_path, '', 0);
237
            setcookie('autologin_pass', '', time() - 3600, $xoops_cookie_path, '', 0);
238
        }
239
240
        if ($redirect_to_top) {
241
            header('Location: ' . XOOPS_URL . '/');
242
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method purge() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
243
        } else {
244
            $ret = $this->call_filter('prepurge_exit');
245
            if ($ret == false) {
246
                die('Protector detects attacking actions');
0 ignored issues
show
Coding Style Compatibility introduced by
The method purge() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
247
            }
248
        }
249
    }
250
251
    /**
252
     * @param string $type
253
     * @param int    $uid
254
     * @param bool   $unique_check
255
     * @param int    $level
256
     *
257
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
258
     */
259
    public function output_log($type = 'UNKNOWN', $uid = 0, $unique_check = false, $level = 1)
260
    {
261
        if ($this->_logged) {
262
            return true;
263
        }
264
265
        if (!($this->_conf['log_level'] & $level)) {
266
            return true;
267
        }
268
269
        if (empty($this->_conn)) {
270
            $this->_conn = @mysqli_connect(XOOPS_DB_HOST, XOOPS_DB_USER, XOOPS_DB_PASS);
271
            if (!$this->_conn) {
272
                die('db connection failed.');
0 ignored issues
show
Coding Style Compatibility introduced by
The method output_log() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
273
            }
274
            if (!mysqli_select_db($this->_conn, XOOPS_DB_NAME)) {
275
                die('db selection failed.');
0 ignored issues
show
Coding Style Compatibility introduced by
The method output_log() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
276
            }
277
        }
278
279
        $ip    = \Xmf\IPAddress::fromRequest()->asReadable();
280
        $agent = @$_SERVER['HTTP_USER_AGENT'];
281
282
        if ($unique_check) {
283
            $result = mysqli_query($this->_conn, 'SELECT ip,type FROM ' . XOOPS_DB_PREFIX . '_' . $this->mydirname . '_log ORDER BY timestamp DESC LIMIT 1');
284
            list($last_ip, $last_type) = mysqli_fetch_row($result);
285
            if ($last_ip == $ip && $last_type == $type) {
286
                $this->_logged = true;
287
288
                return true;
289
            }
290
        }
291
292
        mysqli_query(
293
            $this->_conn,
294
            'INSERT INTO ' . XOOPS_DB_PREFIX . '_' . $this->mydirname . "_log SET ip='"
295
            . mysqli_real_escape_string($this->_conn, $ip) . "',agent='"
296
            . mysqli_real_escape_string($this->_conn, $agent) . "',type='"
297
            . mysqli_real_escape_string($this->_conn, $type) . "',description='"
298
            . mysqli_real_escape_string($this->_conn, $this->message) . "',uid='"
299
            . (int)$uid . "',timestamp=NOW()"
300
        );
301
        $this->_logged = true;
302
303
        return true;
304
    }
305
306
    /**
307
     * @param $expire
308
     *
309
     * @return bool
310
     */
311 View Code Duplication
    public function write_file_bwlimit($expire)
312
    {
313
        $expire = min((int)$expire, time() + 300);
314
315
        $fp = @fopen($this->get_filepath4bwlimit(), 'w');
316
        if ($fp) {
317
            @flock($fp, LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
318
            fwrite($fp, $expire . "\n");
319
            @flock($fp, LOCK_UN);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
320
            fclose($fp);
321
322
            return true;
323
        } else {
324
            return false;
325
        }
326
    }
327
328
    /**
329
     * @return mixed
330
     */
331
    public function get_bwlimit()
332
    {
333
        list($expire) = @file(Protector::get_filepath4bwlimit());
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
334
        $expire = min((int)$expire, time() + 300);
335
336
        return $expire;
337
    }
338
339
    /**
340
     * @return string
341
     */
342
    public static function get_filepath4bwlimit()
343
    {
344
        return XOOPS_TRUST_PATH . '/modules/protector/configs/bwlimit' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
345
    }
346
347
    /**
348
     * @param $bad_ips
349
     *
350
     * @return bool
351
     */
352 View Code Duplication
    public function write_file_badips($bad_ips)
353
    {
354
        asort($bad_ips);
355
356
        $fp = @fopen($this->get_filepath4badips(), 'w');
357
        if ($fp) {
358
            @flock($fp, LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
359
            fwrite($fp, serialize($bad_ips) . "\n");
360
            @flock($fp, LOCK_UN);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
361
            fclose($fp);
362
363
            return true;
364
        } else {
365
            return false;
366
        }
367
    }
368
369
    /**
370
     * @param int  $jailed_time
371
     * @param null $ip
372
     *
373
     * @return bool
374
     */
375
    public function register_bad_ips($jailed_time = 0, $ip = null)
376
    {
377
        if (empty($ip)) {
378
            $ip = \Xmf\IPAddress::fromRequest()->asReadable();
379
        }
380
        if (empty($ip)) {
381
            return false;
382
        }
383
384
        $bad_ips      = $this->get_bad_ips(true);
385
        $bad_ips[$ip] = $jailed_time ?: 0x7fffffff;
386
387
        return $this->write_file_badips($bad_ips);
388
    }
389
390
    /**
391
     * @param bool $with_jailed_time
392
     *
393
     * @return array|mixed
394
     */
395
    public function get_bad_ips($with_jailed_time = false)
396
    {
397
        list($bad_ips_serialized) = @file(Protector::get_filepath4badips());
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
398
        $bad_ips = empty($bad_ips_serialized) ? array() : @unserialize($bad_ips_serialized);
399
        if (!is_array($bad_ips) || isset($bad_ips[0])) {
400
            $bad_ips = array();
401
        }
402
403
        // expire jailed_time
404
        $pos = 0;
405
        foreach ($bad_ips as $bad_ip => $jailed_time) {
406
            if ($jailed_time >= time()) {
407
                break;
408
            }
409
            ++$pos;
410
        }
411
        $bad_ips = array_slice($bad_ips, $pos);
412
413
        if ($with_jailed_time) {
414
            return $bad_ips;
415
        } else {
416
            return array_keys($bad_ips);
417
        }
418
    }
419
420
    /**
421
     * @return string
422
     */
423
    public static function get_filepath4badips()
424
    {
425
        return XOOPS_TRUST_PATH . '/modules/protector/configs/badips' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
426
    }
427
428
    /**
429
     * @param bool $with_info
430
     *
431
     * @return array|mixed
432
     */
433
    public function get_group1_ips($with_info = false)
434
    {
435
        list($group1_ips_serialized) = @file(Protector::get_filepath4group1ips());
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
436
        $group1_ips = empty($group1_ips_serialized) ? array() : @unserialize($group1_ips_serialized);
437
        if (!is_array($group1_ips)) {
438
            $group1_ips = array();
439
        }
440
441
        if ($with_info) {
442
            $group1_ips = array_flip($group1_ips);
443
        }
444
445
        return $group1_ips;
446
    }
447
448
    /**
449
     * @return string
450
     */
451
    public static function get_filepath4group1ips()
452
    {
453
        return XOOPS_TRUST_PATH . '/modules/protector/configs/group1ips' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
454
    }
455
456
    /**
457
     * @return string
458
     */
459
    public function get_filepath4confighcache()
460
    {
461
        return XOOPS_TRUST_PATH . '/modules/protector/configs/configcache' . substr(md5(XOOPS_ROOT_PATH . XOOPS_DB_USER . XOOPS_DB_PREFIX), 0, 6);
462
    }
463
464
    /**
465
     * @param $ips
466
     *
467
     * @return bool
468
     */
469
    public function ip_match($ips)
470
    {
471
        $requestIp = \Xmf\IPAddress::fromRequest()->asReadable();
472
        if (false === $requestIp) { // nothing to match
473
            $this->ip_matched_info = null;
474
            return false;
475
        }
476
        foreach ($ips as $ip => $info) {
477
            if ($ip) {
478
                switch (strtolower(substr($ip, -1))) {
479
                    case '.' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
480
                    case ':' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
481
                        // foward match
482
                        if (substr($requestIp, 0, strlen($ip)) == $ip) {
483
                            $this->ip_matched_info = $info;
484
                            return true;
485
                        }
486
                        break;
487
                    case '0' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
488
                    case '1' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
489
                    case '2' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
490
                    case '3' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
491
                    case '4' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
492
                    case '5' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
493
                    case '6' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
494
                    case '7' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
495
                    case '8' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
496
                    case '9' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
497
                    case 'a' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
498
                    case 'b' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
499
                    case 'c' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
500
                    case 'd' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
501
                    case 'e' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
502
                    case 'f' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
503
                        // full match
504
                        if ($requestIp == $ip) {
505
                            $this->ip_matched_info = $info;
506
                            return true;
507
                        }
508
                        break;
509
                    default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
510
                        // perl regex
511
                        if (@preg_match($ip, $requestIp)) {
512
                            $this->ip_matched_info = $info;
513
                            return true;
514
                        }
515
                        break;
516
                }
517
            }
518
        }
519
        $this->ip_matched_info = null;
520
        return false;
521
    }
522
523
    /**
524
     * @param null $ip
525
     *
526
     * @return bool
527
     */
528
    public function deny_by_htaccess($ip = null)
529
    {
530
        if (empty($ip)) {
531
            $ip = \Xmf\IPAddress::fromRequest()->asReadable();
532
        }
533
        if (empty($ip)) {
534
            return false;
535
        }
536
        if (!function_exists('file_get_contents')) {
537
            return false;
538
        }
539
540
        $target_htaccess = XOOPS_ROOT_PATH . '/.htaccess';
541
        $backup_htaccess = XOOPS_ROOT_PATH . '/uploads/.htaccess.bak';
542
543
        $ht_body = file_get_contents($target_htaccess);
544
545
        // make backup as uploads/.htaccess.bak automatically
546
        if ($ht_body && !file_exists($backup_htaccess)) {
547
            $fw = fopen($backup_htaccess, 'w');
548
            fwrite($fw, $ht_body);
549
            fclose($fw);
550
        }
551
552
        // if .htaccess is broken, restore from backup
553
        if (!$ht_body && file_exists($backup_htaccess)) {
554
            $ht_body = file_get_contents($backup_htaccess);
555
        }
556
557
        // new .htaccess
558
        if ($ht_body === false) {
559
            $ht_body = '';
560
        }
561
562
        if (preg_match("/^(.*)#PROTECTOR#\s+(DENY FROM .*)\n#PROTECTOR#\n(.*)$/si", $ht_body, $regs)) {
563
            if (substr($regs[2], -strlen($ip)) == $ip) {
564
                return true;
565
            }
566
            $new_ht_body = $regs[1] . "#PROTECTOR#\n" . $regs[2] . " $ip\n#PROTECTOR#\n" . $regs[3];
567
        } else {
568
            $new_ht_body = "#PROTECTOR#\nDENY FROM $ip\n#PROTECTOR#\n" . $ht_body;
569
        }
570
571
        // error_log( "$new_ht_body\n" , 3 , "/tmp/error_log" ) ;
572
573
        $fw = fopen($target_htaccess, 'w');
574
        @flock($fw, LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
575
        fwrite($fw, $new_ht_body);
576
        @flock($fw, LOCK_UN);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
577
        fclose($fw);
578
579
        return true;
580
    }
581
582
    /**
583
     * @return array
584
     */
585
    public function getDblayertrapDoubtfuls()
586
    {
587
        return $this->_dblayertrap_doubtfuls;
588
    }
589
590
    /**
591
     * @param $val
592
     * @return null
593
     */
594
    protected function _dblayertrap_check_recursive($val)
595
    {
596
        if (is_array($val)) {
597
            foreach ($val as $subval) {
598
                $this->_dblayertrap_check_recursive($subval);
599
            }
600
        } else {
601
            if (strlen($val) < 6) {
602
                return null;
603
            }
604
            $val = get_magic_quotes_gpc() ? stripslashes($val) : $val;
605
            foreach ($this->_dblayertrap_doubtful_needles as $needle) {
606
                if (false !== stripos($val, $needle)) {
607
                    $this->_dblayertrap_doubtfuls[] = $val;
608
                }
609
            }
610
        }
611
    }
612
613
    /**
614
     * @param  bool $force_override
615
     * @return null
616
     */
617
    public function dblayertrap_init($force_override = false)
618
    {
619
        if (!empty($GLOBALS['xoopsOption']['nocommon']) || defined('_LEGACY_PREVENT_EXEC_COMMON_') || defined('_LEGACY_PREVENT_LOAD_CORE_')) {
620
            return null;
621
        } // skip
622
623
        $this->_dblayertrap_doubtfuls = array();
624
        $this->_dblayertrap_check_recursive($_GET);
625
        $this->_dblayertrap_check_recursive($_POST);
626
        $this->_dblayertrap_check_recursive($_COOKIE);
627
        if (empty($this->_conf['dblayertrap_wo_server'])) {
628
            $this->_dblayertrap_check_recursive($_SERVER);
629
        }
630
631
        if (!empty($this->_dblayertrap_doubtfuls) || $force_override) {
632
            @define('XOOPS_DB_ALTERNATIVE', 'ProtectorMysqlDatabase');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
633
            require_once dirname(__DIR__) . '/class/ProtectorMysqlDatabase.class.php';
634
        }
635
    }
636
637
    /**
638
     * @param $val
639
     */
640
    protected function _bigumbrella_check_recursive($val)
641
    {
642
        if (is_array($val)) {
643
            foreach ($val as $subval) {
644
                $this->_bigumbrella_check_recursive($subval);
645
            }
646
        } else {
647
            if (preg_match('/[<\'"].{15}/s', $val, $regs)) {
648
                $this->_bigumbrella_doubtfuls[] = $regs[0];
649
            }
650
        }
651
    }
652
653
    public function bigumbrella_init()
654
    {
655
        $this->_bigumbrella_doubtfuls = array();
656
        $this->_bigumbrella_check_recursive($_GET);
657
        $this->_bigumbrella_check_recursive(@$_SERVER['PHP_SELF']);
658
659
        if (!empty($this->_bigumbrella_doubtfuls)) {
660
            ob_start(array($this, 'bigumbrella_outputcheck'));
661
        }
662
    }
663
664
    /**
665
     * @param $s
666
     *
667
     * @return string
668
     */
669
    public function bigumbrella_outputcheck($s)
670
    {
671
        if (defined('BIGUMBRELLA_DISABLED')) {
672
            return $s;
673
        }
674
675
        if (function_exists('headers_list')) {
676
            foreach (headers_list() as $header) {
677
                if (false !== stripos($header, 'Content-Type:') && false === stripos($header, 'text/html')) {
678
                    return $s;
679
                }
680
            }
681
        }
682
683
        if (!is_array($this->_bigumbrella_doubtfuls)) {
684
            return 'bigumbrella injection found.';
685
        }
686
687
        foreach ($this->_bigumbrella_doubtfuls as $doubtful) {
688
            if (false !== strpos($s, $doubtful)) {
689
                return 'XSS found by Protector.';
690
            }
691
        }
692
693
        return $s;
694
    }
695
696
    /**
697
     * @return bool
698
     */
699
    public function intval_allrequestsendid()
700
    {
701
        global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
702
703
        if ($this->_done_intval) {
704
            return true;
705
        } else {
706
            $this->_done_intval = true;
707
        }
708
709 View Code Duplication
        foreach ($_GET as $key => $val) {
710
            if (substr($key, -2) === 'id' && !is_array($_GET[$key])) {
711
                $newval     = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
712
                $_GET[$key] = $HTTP_GET_VARS[$key] = $newval;
713
                if ($_REQUEST[$key] == $_GET[$key]) {
714
                    $_REQUEST[$key] = $newval;
715
                }
716
            }
717
        }
718 View Code Duplication
        foreach ($_POST as $key => $val) {
719
            if (substr($key, -2) === 'id' && !is_array($_POST[$key])) {
720
                $newval      = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
721
                $_POST[$key] = $HTTP_POST_VARS[$key] = $newval;
722
                if ($_REQUEST[$key] == $_POST[$key]) {
723
                    $_REQUEST[$key] = $newval;
724
                }
725
            }
726
        }
727 View Code Duplication
        foreach ($_COOKIE as $key => $val) {
728
            if (substr($key, -2) === 'id' && !is_array($_COOKIE[$key])) {
729
                $newval        = preg_replace('/[^0-9a-zA-Z_-]/', '', $val);
730
                $_COOKIE[$key] = $HTTP_COOKIE_VARS[$key] = $newval;
731
                if ($_REQUEST[$key] == $_COOKIE[$key]) {
732
                    $_REQUEST[$key] = $newval;
733
                }
734
            }
735
        }
736
737
        return true;
738
    }
739
740
    /**
741
     * @return bool
742
     */
743
    public function eliminate_dotdot()
744
    {
745
        global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
746
747
        if ($this->_done_dotdot) {
748
            return true;
749
        } else {
750
            $this->_done_dotdot = true;
751
        }
752
753
        foreach ($_GET as $key => $val) {
754
            if (is_array($_GET[$key])) {
755
                continue;
756
            }
757
            if (substr(trim($val), 0, 3) === '../' || false !== strpos($val, '/../')) {
758
                $this->last_error_type = 'DirTraversal';
759
                $this->message .= "Directory Traversal '$val' found.\n";
760
                $this->output_log($this->last_error_type, 0, false, 64);
761
                $sanitized_val = str_replace(chr(0), '', $val);
762
                if (substr($sanitized_val, -2) !== ' .') {
763
                    $sanitized_val .= ' .';
764
                }
765
                $_GET[$key] = $HTTP_GET_VARS[$key] = $sanitized_val;
766
                if ($_REQUEST[$key] == $_GET[$key]) {
767
                    $_REQUEST[$key] = $sanitized_val;
768
                }
769
            }
770
        }
771
772
        /*    foreach ($_POST as $key => $val) {
773
                if( is_array( $_POST[ $key ] ) ) continue ;
774
                if ( substr( trim( $val ) , 0 , 3 ) == '../' || false !== strpos( $val , '../../' ) ) {
775
                    $this->last_error_type = 'ParentDir' ;
776
                    $this->message .= "Doubtful file specification '$val' found.\n" ;
777
                    $this->output_log( $this->last_error_type , 0 , false , 128 ) ;
778
                    $sanitized_val = str_replace( chr(0) , '' , $val ) ;
779
                    if( substr( $sanitized_val , -2 ) != ' .' ) $sanitized_val .= ' .' ;
780
                    $_POST[ $key ] = $HTTP_POST_VARS[ $key ] = $sanitized_val ;
781
                    if ($_REQUEST[ $key ] == $_POST[ $key ]) {
782
                        $_REQUEST[ $key ] = $sanitized_val ;
783
                    }
784
                }
785
            }
786
            foreach ($_COOKIE as $key => $val) {
787
                if( is_array( $_COOKIE[ $key ] ) ) continue ;
788
                if ( substr( trim( $val ) , 0 , 3 ) == '../' || false !== strpos( $val , '../../' ) ) {
789
                    $this->last_error_type = 'ParentDir' ;
790
                    $this->message .= "Doubtful file specification '$val' found.\n" ;
791
                    $this->output_log( $this->last_error_type , 0 , false , 128 ) ;
792
                    $sanitized_val = str_replace( chr(0) , '' , $val ) ;
793
                    if( substr( $sanitized_val , -2 ) != ' .' ) $sanitized_val .= ' .' ;
794
                    $_COOKIE[ $key ] = $HTTP_COOKIE_VARS[ $key ] = $sanitized_val ;
795
                    if ($_REQUEST[ $key ] == $_COOKIE[ $key ]) {
796
                        $_REQUEST[ $key ] = $sanitized_val ;
797
                    }
798
                }
799
            }*/
800
801
        return true;
802
    }
803
804
    /**
805
     * @param $current
806
     * @param $indexes
807
     *
808
     * @return bool
809
     */
810
    public function &get_ref_from_base64index(&$current, $indexes)
811
    {
812
        foreach ($indexes as $index) {
813
            $index = base64_decode($index);
814
            if (!is_array($current)) {
815
                return false;
816
            }
817
            $current =& $current[$index];
818
        }
819
820
        return $current;
821
    }
822
823
    /**
824
     * @param $key
825
     * @param $val
826
     */
827
    public function replace_doubtful($key, $val)
828
    {
829
        global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
830
831
        $index_expression = '';
0 ignored issues
show
Unused Code introduced by
$index_expression is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
832
        $indexes          = explode('_', $key);
833
        $base_array       = array_shift($indexes);
834
835
        switch ($base_array) {
836
            case 'G' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
837
                $main_ref   =& $this->get_ref_from_base64index($_GET, $indexes);
838
                $legacy_ref =& $this->get_ref_from_base64index($HTTP_GET_VARS, $indexes);
839
                break;
840
            case 'P' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
841
                $main_ref   =& $this->get_ref_from_base64index($_POST, $indexes);
842
                $legacy_ref =& $this->get_ref_from_base64index($HTTP_POST_VARS, $indexes);
843
                break;
844
            case 'C' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
845
                $main_ref   =& $this->get_ref_from_base64index($_COOKIE, $indexes);
846
                $legacy_ref =& $this->get_ref_from_base64index($HTTP_COOKIE_VARS, $indexes);
847
                break;
848
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
849
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method replace_doubtful() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
850
        }
851
        if (!isset($main_ref)) {
852
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method replace_doubtful() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
853
        }
854
        $request_ref =& $this->get_ref_from_base64index($_REQUEST, $indexes);
855
        if ($request_ref !== false && $main_ref == $request_ref) {
856
            $request_ref = $val;
857
        }
858
        $main_ref   = $val;
859
        $legacy_ref = $val;
860
    }
861
862
    /**
863
     * @return bool
864
     */
865
    public function check_uploaded_files()
866
    {
867
        if ($this->_done_badext) {
868
            return $this->_safe_badext;
869
        } else {
870
            $this->_done_badext = true;
871
        }
872
873
        // extensions never uploaded
874
        $bad_extensions = array('php', 'phtml', 'phtm', 'php3', 'php4', 'cgi', 'pl', 'asp');
875
        // extensions needed image check (anti-IE Content-Type XSS)
876
        $image_extensions = array(
877
            1  => 'gif',
878
            2  => 'jpg',
879
            3  => 'png',
880
            4  => 'swf',
881
            5  => 'psd',
882
            6  => 'bmp',
883
            7  => 'tif',
884
            8  => 'tif',
885
            9  => 'jpc',
886
            10 => 'jp2',
887
            11 => 'jpx',
888
            12 => 'jb2',
889
            13 => 'swc',
890
            14 => 'iff',
891
            15 => 'wbmp',
892
            16 => 'xbm');
893
894
        foreach ($_FILES as $_file) {
895
            if (!empty($_file['error'])) {
896
                continue;
897
            }
898
            if (!empty($_file['name']) && is_string($_file['name'])) {
899
                $ext = strtolower(substr(strrchr($_file['name'], '.'), 1));
900
                if ($ext === 'jpeg') {
901
                    $ext = 'jpg';
902
                } elseif ($ext === 'tiff') {
903
                    $ext = 'tif';
904
                }
905
906
                // anti multiple dot file (Apache mod_mime.c)
907
                if (count(explode('.', str_replace('.tar.gz', '.tgz', $_file['name']))) > 2) {
908
                    $this->message .= "Attempt to multiple dot file {$_file['name']}.\n";
909
                    $this->_safe_badext    = false;
910
                    $this->last_error_type = 'UPLOAD';
911
                }
912
913
                // anti dangerous extensions
914 View Code Duplication
                if (in_array($ext, $bad_extensions)) {
915
                    $this->message .= "Attempt to upload {$_file['name']}.\n";
916
                    $this->_safe_badext    = false;
917
                    $this->last_error_type = 'UPLOAD';
918
                }
919
920
                // anti camouflaged image file
921
                if (in_array($ext, $image_extensions)) {
922
                    $image_attributes = @getimagesize($_file['tmp_name']);
923
                    if ($image_attributes === false && is_uploaded_file($_file['tmp_name'])) {
924
                        // open_basedir restriction
925
                        $temp_file = XOOPS_ROOT_PATH . '/uploads/protector_upload_temporary' . md5(time());
926
                        move_uploaded_file($_file['tmp_name'], $temp_file);
927
                        $image_attributes = @getimagesize($temp_file);
928
                        @unlink($temp_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
929
                    }
930
931
                    if ($image_attributes === false || $image_extensions[(int)$image_attributes[2]] != $ext) {
932
                        $this->message .= "Attempt to upload camouflaged image file {$_file['name']}.\n";
933
                        $this->_safe_badext    = false;
934
                        $this->last_error_type = 'UPLOAD';
935
                    }
936
                }
937
            }
938
        }
939
940
        return $this->_safe_badext;
941
    }
942
943
    /**
944
     * @return bool
945
     */
946
    public function check_contami_systemglobals()
947
    {
948
        /*    if( $this->_done_contami ) return $this->_safe_contami ;
949
    else $this->_done_contami = true ; */
950
951
        /*    foreach ($this->_bad_globals as $bad_global) {
952
                if ( isset( $_REQUEST[ $bad_global ] ) ) {
953
                    $this->message .= "Attempt to inject '$bad_global' was found.\n" ;
954
                    $this->_safe_contami = false ;
955
                    $this->last_error_type = 'CONTAMI' ;
956
                }
957
            }*/
958
959
        return $this->_safe_contami;
960
    }
961
962
    /**
963
     * @param bool $sanitize
964
     *
965
     * @return bool
966
     */
967
    public function check_sql_isolatedcommentin($sanitize = true)
968
    {
969
        if ($this->_done_isocom) {
970
            return $this->_safe_isocom;
971
        } else {
972
            $this->_done_isocom = true;
973
        }
974
975
        foreach ($this->_doubtful_requests as $key => $val) {
976
            $str = $val;
977
            while ($str = strstr($str, '/*')) { /* */
978
                $str = strstr(substr($str, 2), '*/');
979
                if ($str === false) {
980
                    $this->message .= "Isolated comment-in found. ($val)\n";
981
                    if ($sanitize) {
982
                        $this->replace_doubtful($key, $val . '*/');
983
                    }
984
                    $this->_safe_isocom    = false;
985
                    $this->last_error_type = 'ISOCOM';
986
                }
987
            }
988
        }
989
990
        return $this->_safe_isocom;
991
    }
992
993
    /**
994
     * @param bool $sanitize
995
     *
996
     * @return bool
997
     */
998
    public function check_sql_union($sanitize = true)
999
    {
1000
        if ($this->_done_union) {
1001
            return $this->_safe_union;
1002
        } else {
1003
            $this->_done_union = true;
1004
        }
1005
1006
        foreach ($this->_doubtful_requests as $key => $val) {
1007
            $str = str_replace(array('/*', '*/'), '', preg_replace('?/\*.+\*/?sU', '', $val));
1008
            if (preg_match('/\sUNION\s+(ALL|SELECT)/i', $str)) {
1009
                $this->message .= "Pattern like SQL injection found. ($val)\n";
1010
                if ($sanitize) {
1011
                    //                    $this->replace_doubtful($key, preg_replace('/union/i', 'uni-on', $val));
1012
                    $this->replace_doubtful($key, str_ireplace('union', 'uni-on', $val));
1013
                }
1014
                $this->_safe_union     = false;
1015
                $this->last_error_type = 'UNION';
1016
            }
1017
        }
1018
1019
        return $this->_safe_union;
1020
    }
1021
1022
    /**
1023
     * @param $uid
1024
     *
1025
     * @return bool
1026
     */
1027
    public function stopforumspam($uid)
1028
    {
1029
        if (!function_exists('curl_init')) {
1030
            return false;
1031
        }
1032
1033
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
1034
            return false;
1035
        }
1036
1037
        $query = 'f=serial&ip=' . $_SERVER['REMOTE_ADDR'];
1038
        $query .= isset($_POST['email']) ? '&email=' . $_POST['email'] : '';
1039
        $query .= isset($_POST['uname']) ? '&username=' . $_POST['uname'] : '';
1040
        $url = 'http://www.stopforumspam.com/api?' . $query;
1041
        $ch  = curl_init();
1042
        curl_setopt($ch, CURLOPT_URL, $url);
1043
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1044
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
1045
        $result = unserialize(curl_exec($ch));
1046
        curl_close($ch);
1047
1048
        $spammer = false;
1049
        if (isset($result['email']) && isset($result['email']['lastseen'])) {
1050
            $spammer = true;
1051
        }
1052
1053
        if (isset($result['ip']) && isset($result['ip']['lastseen'])) {
1054
            $last        = strtotime($result['ip']['lastseen']);
1055
            $oneMonth    = 60 * 60 * 24 * 31;
1056
            $oneMonthAgo = time() - $oneMonth;
1057
            if ($last > $oneMonthAgo) {
1058
                $spammer = true;
1059
            }
1060
        }
1061
1062
        if (!$spammer) {
1063
            return false;
1064
        }
1065
1066
        $this->last_error_type = 'SPAMMER POST';
1067
1068
        switch ($this->_conf['stopforumspam_action']) {
1069
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1070
            case 'log' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1071
                break;
1072
            case 'san' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1073
                $_POST = array();
1074
                $this->message .= 'POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
1075
                break;
1076
            case 'biptime0' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1077
                $_POST = array();
1078
                $this->message .= 'BAN and POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
1079
                $this->_should_be_banned_time0 = true;
1080
                break;
1081
            case 'bip' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1082
                $_POST = array();
1083
                $this->message .= 'Ban and POST deleted for IP:' . $_SERVER['REMOTE_ADDR'];
1084
                $this->_should_be_banned = true;
1085
                break;
1086
        }
1087
1088
        $this->output_log($this->last_error_type, $uid, false, 16);
1089
1090
        return true;
1091
    }
1092
1093
    /**
1094
     * @param int  $uid
1095
     * @param bool $can_ban
1096
     *
1097
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1098
     */
1099
    public function check_dos_attack($uid = 0, $can_ban = false)
1100
    {
1101
        global $xoopsDB;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1102
1103
        if ($this->_done_dos) {
1104
            return true;
1105
        }
1106
1107
        $ip      = \Xmf\IPAddress::fromRequest();
1108
        if (false === $ip->asReadable()) {
1109
            return true;
1110
        }
1111
        $uri     = @$_SERVER['REQUEST_URI'];
1112
        $ip4sql  = $xoopsDB->quote($ip->asReadable());
1113
        $uri4sql = $xoopsDB->quote($uri);
1114
1115
        // gargage collection
1116
        $result = $xoopsDB->queryF(
1117
            'DELETE FROM ' . $xoopsDB->prefix($this->mydirname . '_access')
1118
            . ' WHERE expire < UNIX_TIMESTAMP()'
1119
        );
1120
1121
        // for older versions before updating this module
1122
        if ($result === false) {
1123
            $this->_done_dos = true;
1124
1125
            return true;
1126
        }
1127
1128
        // sql for recording access log (INSERT should be placed after SELECT)
1129
        $sql4insertlog = 'INSERT INTO ' . $xoopsDB->prefix($this->mydirname . '_access')
1130
                         . " SET ip={$ip4sql}, request_uri={$uri4sql},"
1131
                         . " expire=UNIX_TIMESTAMP()+'" . (int)$this->_conf['dos_expire'] . "'";
1132
1133
        // bandwidth limitation
1134
        if (@$this->_conf['bwlimit_count'] >= 10) {
1135
            $result = $xoopsDB->query('SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access'));
1136
            list($bw_count) = $xoopsDB->fetchRow($result);
1137
            if ($bw_count > $this->_conf['bwlimit_count']) {
1138
                $this->write_file_bwlimit(time() + $this->_conf['dos_expire']);
1139
            }
1140
        }
1141
1142
        // F5 attack check (High load & same URI)
1143
        $result = $xoopsDB->query(
1144
            'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access')
1145
            . " WHERE ip={$ip4sql} AND request_uri={$uri4sql}");
1146
        list($f5_count) = $xoopsDB->fetchRow($result);
1147 View Code Duplication
        if ($f5_count > $this->_conf['dos_f5count']) {
1148
1149
            // delayed insert
1150
            $xoopsDB->queryF($sql4insertlog);
1151
1152
            // extends the expires of the IP with 5 minutes at least (pending)
1153
            // $result = $xoopsDB->queryF( "UPDATE ".$xoopsDB->prefix($this->mydirname.'_access')." SET expire=UNIX_TIMESTAMP()+300 WHERE ip='$ip4sql' AND expire<UNIX_TIMESTAMP()+300" ) ;
1154
1155
            // call the filter first
1156
            $ret = $this->call_filter('f5attack_overrun');
0 ignored issues
show
Unused Code introduced by
$ret is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1157
1158
            // actions for F5 Attack
1159
            $this->_done_dos       = true;
1160
            $this->last_error_type = 'DoS';
1161
            switch ($this->_conf['dos_f5action']) {
1162
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1163
                case 'exit' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1164
                    $this->output_log($this->last_error_type, $uid, true, 16);
1165
                    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method check_dos_attack() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1166
                case 'none' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1167
                    $this->output_log($this->last_error_type, $uid, true, 16);
1168
1169
                    return true;
1170
                case 'biptime0' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1171
                    if ($can_ban) {
1172
                        $this->register_bad_ips(time() + $this->_conf['banip_time0']);
1173
                    }
1174
                    break;
1175
                case 'bip' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1176
                    if ($can_ban) {
1177
                        $this->register_bad_ips();
1178
                    }
1179
                    break;
1180
                case 'hta' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1181
                    if ($can_ban) {
1182
                        $this->deny_by_htaccess();
1183
                    }
1184
                    break;
1185
                case 'sleep' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1186
                    sleep(5);
1187
                    break;
1188
            }
1189
1190
            return false;
1191
        }
1192
1193
        // Check its Agent
1194
        if (trim($this->_conf['dos_crsafe']) != '' && preg_match($this->_conf['dos_crsafe'], @$_SERVER['HTTP_USER_AGENT'])) {
1195
            // welcomed crawler
1196
            $this->_done_dos = true;
1197
1198
            return true;
1199
        }
1200
1201
        // Crawler check (High load & different URI)
1202
        $result = $xoopsDB->query(
1203
            'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . " WHERE ip={$ip4sql}"
1204
        );
1205
        list($crawler_count) = $xoopsDB->fetchRow($result);
1206
1207
        // delayed insert
1208
        $xoopsDB->queryF($sql4insertlog);
1209
1210 View Code Duplication
        if ($crawler_count > $this->_conf['dos_crcount']) {
1211
1212
            // call the filter first
1213
            $ret = $this->call_filter('crawler_overrun');
0 ignored issues
show
Unused Code introduced by
$ret is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1214
1215
            // actions for bad Crawler
1216
            $this->_done_dos       = true;
1217
            $this->last_error_type = 'CRAWLER';
1218
            switch ($this->_conf['dos_craction']) {
1219
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1220
                case 'exit' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1221
                    $this->output_log($this->last_error_type, $uid, true, 16);
1222
                    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method check_dos_attack() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1223
                case 'none' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1224
                    $this->output_log($this->last_error_type, $uid, true, 16);
1225
1226
                    return true;
1227
                case 'biptime0' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1228
                    if ($can_ban) {
1229
                        $this->register_bad_ips(time() + $this->_conf['banip_time0']);
1230
                    }
1231
                    break;
1232
                case 'bip' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1233
                    if ($can_ban) {
1234
                        $this->register_bad_ips();
1235
                    }
1236
                    break;
1237
                case 'hta' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1238
                    if ($can_ban) {
1239
                        $this->deny_by_htaccess();
1240
                    }
1241
                    break;
1242
                case 'sleep' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1243
                    sleep(5);
1244
                    break;
1245
            }
1246
1247
            return false;
1248
        }
1249
1250
        return true;
1251
    }
1252
1253
    //
1254
    /**
1255
     * @return bool|null
1256
     */
1257
    public function check_brute_force()
1258
    {
1259
        global $xoopsDB;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1260
1261
        $ip      = \Xmf\IPAddress::fromRequest();
1262
        if (false === $ip->asReadable()) {
1263
            return true;
1264
        }
1265
        $uri     = @$_SERVER['REQUEST_URI'];
1266
        $ip4sql  = $xoopsDB->quote($ip->asReadable());
1267
        $uri4sql = $xoopsDB->quote($uri);
1268
1269
        $victim_uname = empty($_COOKIE['autologin_uname']) ? $_POST['uname'] : $_COOKIE['autologin_uname'];
1270
        // some UA send 'deleted' as a value of the deleted cookie.
1271
        if ($victim_uname === 'deleted') {
1272
            return null;
1273
        }
1274
        $mal4sql = $xoopsDB->quote("BRUTE FORCE: $victim_uname");
1275
1276
        // gargage collection
1277
        $result = $xoopsDB->queryF(
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1278
            'DELETE FROM ' . $xoopsDB->prefix($this->mydirname . '_access') . ' WHERE expire < UNIX_TIMESTAMP()'
1279
        );
1280
1281
        // sql for recording access log (INSERT should be placed after SELECT)
1282
        $sql4insertlog = 'INSERT INTO ' . $xoopsDB->prefix($this->mydirname . '_access')
1283
                         . " SET ip={$ip4sql}, request_uri={$uri4sql}, malicious_actions={$mal4sql}, expire=UNIX_TIMESTAMP()+600";
1284
1285
        // count check
1286
        $result = $xoopsDB->query(
1287
            'SELECT COUNT(*) FROM ' . $xoopsDB->prefix($this->mydirname . '_access')
1288
            . " WHERE ip={$ip4sql} AND malicious_actions like 'BRUTE FORCE:%'"
1289
        );
1290
        list($bf_count) = $xoopsDB->fetchRow($result);
1291
        if ($bf_count > $this->_conf['bf_count']) {
1292
            $this->register_bad_ips(time() + $this->_conf['banip_time0']);
1293
            $this->last_error_type = 'BruteForce';
1294
            $this->message .= "Trying to login as '" . addslashes($victim_uname) . "' found.\n";
1295
            $this->output_log('BRUTE FORCE', 0, true, 1);
1296
            $ret = $this->call_filter('bruteforce_overrun');
1297
            if ($ret == false) {
1298
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method check_brute_force() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1299
            }
1300
        }
1301
        // delayed insert
1302
        $xoopsDB->queryF($sql4insertlog);
1303
        return null;
1304
    }
1305
1306
    /**
1307
     * @param $val
1308
     */
1309
    protected function _spam_check_point_recursive($val)
1310
    {
1311
        if (is_array($val)) {
1312
            foreach ($val as $subval) {
1313
                $this->_spam_check_point_recursive($subval);
1314
            }
1315
        } else {
1316
            // http_host
1317
            $path_array = parse_url(XOOPS_URL);
1318
            $http_host  = empty($path_array['host']) ? 'www.xoops.org' : $path_array['host'];
1319
1320
            // count URI up
1321
            $count = -1;
1322
            foreach (preg_split('#https?\:\/\/#i', $val) as $fragment) {
1323
                if (strncmp($fragment, $http_host, strlen($http_host)) !== 0) {
1324
                    ++$count;
1325
                }
1326
            }
1327
            if ($count > 0) {
1328
                $this->_spamcount_uri += $count;
1329
            }
1330
1331
            // count BBCode likd [url=www....] up (without [url=http://...])
1332
            $this->_spamcount_uri += count(preg_split('/\[url=(?!http|\\"http|\\\'http|' . $http_host . ')/i', $val)) - 1;
1333
        }
1334
    }
1335
1336
    /**
1337
     * @param $points4deny
1338
     * @param $uid
1339
     */
1340
    public function spam_check($points4deny, $uid)
1341
    {
1342
        $this->_spamcount_uri = 0;
1343
        $this->_spam_check_point_recursive($_POST);
1344
1345
        if ($this->_spamcount_uri >= $points4deny) {
1346
            $this->message .= @$_SERVER['REQUEST_URI'] . " SPAM POINT: $this->_spamcount_uri\n";
1347
            $this->output_log('URI SPAM', $uid, false, 128);
1348
            $ret = $this->call_filter('spamcheck_overrun');
1349
            if ($ret == false) {
1350
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method spam_check() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1351
            }
1352
        }
1353
    }
1354
1355
    public function disable_features()
1356
    {
1357
        global $HTTP_POST_VARS, $HTTP_GET_VARS, $HTTP_COOKIE_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1358
1359
        // disable "Notice: Undefined index: ..."
1360
        $error_reporting_level = error_reporting(0);
1361
1362
        //
1363
        // bit 1 : disable XMLRPC , criteria bug
1364
        //
1365
        if ($this->_conf['disable_features'] & 1) {
1366
1367
            // zx 2005/1/5 disable xmlrpc.php in root
1368
            if (/* ! stristr( $_SERVER['SCRIPT_NAME'] , 'modules' ) && */
1369
                substr(@$_SERVER['SCRIPT_NAME'], -10) === 'xmlrpc.php'
1370
            ) {
1371
                $this->output_log('xmlrpc', 0, true, 1);
1372
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1373
            }
1374
1375
            // security bug of class/criteria.php 2005/6/27
1376
            if ($_POST['uname'] === '0' || $_COOKIE['autologin_pass'] === '0') {
1377
                $this->output_log('CRITERIA');
1378
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1379
            }
1380
        }
1381
1382
        //
1383
        // bit 11 : XSS+CSRFs in XOOPS < 2.0.10
1384
        //
1385
        if ($this->_conf['disable_features'] & 1024) {
1386
1387
            // root controllers
1388
            if (false === stripos(@$_SERVER['SCRIPT_NAME'], 'modules')) {
1389
                // zx 2004/12/13 misc.php debug (file check)
1390 View Code Duplication
                if (substr(@$_SERVER['SCRIPT_NAME'], -8) === 'misc.php' && ($_GET['type'] === 'debug' || $_POST['type'] === 'debug') && !preg_match('/^dummy_\d+\.html$/', $_GET['file'])) {
1391
                    $this->output_log('misc debug');
1392
                    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1393
                }
1394
1395
                // zx 2004/12/13 misc.php smilies
1396 View Code Duplication
                if (substr(@$_SERVER['SCRIPT_NAME'], -8) === 'misc.php' && ($_GET['type'] === 'smilies' || $_POST['type'] === 'smilies') && !preg_match('/^[0-9a-z_]*$/i', $_GET['target'])) {
1397
                    $this->output_log('misc smilies');
1398
                    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1399
                }
1400
1401
                // zx 2005/1/5 edituser.php avatarchoose
1402
                if (substr(@$_SERVER['SCRIPT_NAME'], -12) === 'edituser.php' && $_POST['op'] === 'avatarchoose' && false !== strpos($_POST['user_avatar'], '..')) {
1403
                    $this->output_log('edituser avatarchoose');
1404
                    exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1405
                }
1406
            }
1407
1408
            // zx 2005/1/4 findusers
1409
            if (substr(@$_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ($_GET['fct'] === 'findusers' || $_POST['fct'] === 'findusers')) {
1410
                foreach ($_POST as $key => $val) {
1411
                    if (false !== strpos($key, "'") || false !== strpos($val, "'")) {
1412
                        $this->output_log('findusers');
1413
                        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1414
                    }
1415
                }
1416
            }
1417
1418
            // preview CSRF zx 2004/12/14
1419
            // news submit.php
1420
            if (substr(@$_SERVER['SCRIPT_NAME'], -23) === 'modules/news/submit.php' && isset($_POST['preview']) && strpos(@$_SERVER['HTTP_REFERER'], XOOPS_URL . '/modules/news/submit.php') !== 0) {
1421
                $HTTP_POST_VARS['nohtml'] = $_POST['nohtml'] = 1;
1422
            }
1423
            // news admin/index.php
1424
            if (substr(@$_SERVER['SCRIPT_NAME'], -28) === 'modules/news/admin/index.php' && ($_POST['op'] === 'preview' || $_GET['op'] === 'preview') && strpos(@$_SERVER['HTTP_REFERER'], XOOPS_URL . '/modules/news/admin/index.php') !== 0) {
1425
                $HTTP_POST_VARS['nohtml'] = $_POST['nohtml'] = 1;
1426
            }
1427
            // comment comment_post.php
1428
            if (isset($_POST['com_dopreview']) && false === strpos(substr(@$_SERVER['HTTP_REFERER'], -16), 'comment_post.php')) {
1429
                $HTTP_POST_VARS['dohtml'] = $_POST['dohtml'] = 0;
1430
            }
1431
            // disable preview of system's blocksadmin
1432
            if (substr(@$_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ($_GET['fct'] === 'blocksadmin' || $_POST['fct'] === 'blocksadmin') && isset($_POST['previewblock']) /* && strpos( $_SERVER['HTTP_REFERER'] , XOOPS_URL.'/modules/system/admin.php' ) !== 0 */) {
1433
                die("Danger! don't use this preview. Use 'altsys module' instead.(by Protector)");
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1434
            }
1435
            // tpl preview
1436
            if (substr(@$_SERVER['SCRIPT_NAME'], -24) === 'modules/system/admin.php' && ($_GET['fct'] === 'tplsets' || $_POST['fct'] === 'tplsets')) {
1437
                if ($_POST['op'] === 'previewpopup' || $_GET['op'] === 'previewpopup' || isset($_POST['previewtpl'])) {
1438
                    die("Danger! don't use this preview.(by Protector)");
0 ignored issues
show
Coding Style Compatibility introduced by
The method disable_features() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1439
                }
1440
            }
1441
        }
1442
1443
        // restore reporting level
1444
        error_reporting($error_reporting_level);
1445
    }
1446
1447
    /**
1448
     * @param        $type
1449
     * @param string $dying_message
1450
     *
1451
     * @return int|mixed
1452
     */
1453
    public function call_filter($type, $dying_message = '')
1454
    {
1455
        require_once __DIR__ . '/ProtectorFilter.php';
1456
        $filter_handler = ProtectorFilterHandler::getInstance();
1457
        $ret            = $filter_handler->execute($type);
1458
        if ($ret == false && $dying_message) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $ret of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
1459
            die($dying_message);
0 ignored issues
show
Coding Style Compatibility introduced by
The method call_filter() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1460
        }
1461
1462
        return $ret;
1463
    }
1464
}
1465