有没有更快的方法来检查PHP块的IP

With my continued battle of blocking spammers from Nigeria I've blocked the country code in my htaccess file using GeoIP but some still manage to get through. To add another layer I want to iterate through the following list of IP ranges from Nigeria and block them:

41.75.192.0 41.75.207.255
41.138.160.0    41.138.191.255
41.139.64.0 41.139.127.255  
41.155.0.0  41.155.127.255
41.184.0.0  41.184.255.255
41.189.0.0  41.189.31.255
41.190.0.0  41.190.31.255
41.203.64.0 41.203.95.255
41.203.96.0 41.203.127.255
41.204.224.0    41.204.255.255
41.205.160.0    41.205.191.255
41.206.0.0  41.206.31.255
41.206.224.0    41.206.255.255
41.211.192.0    41.211.255.255
41.216.160.0    41.216.175.255
41.217.0.0  41.217.127.255
41.219.128.0    41.219.191.255
41.219.192.0    41.219.255.255
41.220.64.0 41.220.79.255
41.221.112.0    41.221.127.255
41.221.160.0    41.221.175.255
62.173.32.0 62.173.63.255
62.193.160.0    62.193.191.255
80.248.0.0  80.248.15.255
80.250.32.0 80.250.47.255
81.18.32.0  81.18.47.255
82.128.0.0  82.128.127.255
195.166.224.0   195.166.255.255 
196.1.176.0 196.1.191.255
196.29.208.0    196.29.223.255
196.45.48.0 196.45.63.255
196.45.192.0    196.45.255.255  
196.200.0.0 196.200.15.255
196.200.64.0    196.200.79.255
196.200.112.0   196.200.127.255 
196.207.0.0 196.207.15.255
196.220.0.0 196.220.31.255
212.100.64.0    212.100.95.255
217.14.80.0 217.14.95.255
217.117.0.0 217.117.15.255

Using the following code to check each range is there a more efficient method or way of doing this?

$range_start = ip2long("41.75.192.0");
$range_end   = ip2long("41.75.207.255");
$ip          = ip2long($_SERVER['REMOTE_ADDR']);
if ($ip >= $range_start && $ip <= $range_end) {
   // blocked
}

If you have access to .htaccess, you can block them on a configuration level and you don't need to worry about them in scripts.

order allow,deny
deny from 41.75.192.0
deny from 41.75.207.255

...

deny from 217.117.15.255
allow from all

Letting Apache keep them out altogether will save you a fair bit of trouble.

Doing 120 (3x40) calls to ip2long and 40 ifs is hardly going to be bottleneck for any server. The answer to your question is: No, and you should not bother with it.

You are more likely to have much bigger performance problems in the rest of your website.

With .htaccess its easier

order allow,deny
deny from 41.75.192.
deny from 41.75.193.
...
deny from 41.75.207.
allow from all

Php solution:

$range_start = 192;
$range_end = 207;
$ip = preg_match('/41\.75\.(\d+)\.(\d+)/', $_SERVER['REMOTE_ADDR'], $m);
if(intval($m[1]) >= $range_start && intval($m[1]) <= $range_end) {
    //blocked
}

Here's an example with binary search, keep in mind that the elements in $ips must be sorted. If you use it in production, replace the ip2long('..') in $ips with the integer values - you don't need to calculate them every time.

$ips = array(
            array(ip2long('41.75.192.0'), ip2long('41.75.207.255')),
            array(ip2long('41.138.160.0'), ip2long('41.138.191.255')),
            array(ip2long('41.139.64.0'), ip2long('41.139.127.255'))
);

$ip = '41.138.160.1';

function binary_search(array $a, $ip) {
    $low = 0; 
    $high = count($a) - 1;

    while ($low <= $high) {
        $mid = ($low + $high) / 2;
        if ($a[$mid][0] > $ip) {
            $high = $mid - 1;
        } else if ($a[$mid][1] < $ip) {
            $low = $mid + 1;
        } else {
                return true;
        }
    }           
    return false;
}

var_dump(binary_search($ips, ip2long($ip)));

Using binary search on 40 elements array, you have to do at most 6 iterations. Using linear search - 40.

There are legitimate users who try to access your website from ips that are known for spam. For instance, the Tor network allows you to direct your traffic trough 3-4 ips to protect your privacy. Most users use this for bad purposes, thus most of the ips there are listed by spam lists.

The most efficient approach would be to check a user's info against one of these spam databases when the user tries to perform an action on your site that requires authentication. A check would not only include the IP but also the username and email. I had spam problems on my website and after using one of these links it decreased dramatically. Now it's almost down to zero.

I use for this Spambusted and Botscout. They both have sample code and plugins for the major open-source software out there.

Way more efficient than any programming language version or apache. You could do a system call to add or remove entries inside of php.

create a set

ipset create test hash:net

Populate the set!

ipset add test 212.100.64.0/19
ipset add test 41.211.192.0/18
ipset add test 196.200.112.0/20
ipset add test 41.220.64.0/20
ipset add test 41.206.0.0/19
ipset add test 41.203.64.0/19
ipset add test 62.173.32.0/19
ipset add test 62.193.160.0/19
ipset add test 41.138.160.0/19
ipset add test 196.200.0.0/20
ipset add test 217.14.80.0/20
ipset add test 80.250.32.0/20
ipset add test 195.166.224.0/19
ipset add test 41.221.112.0/20
ipset add test 41.216.160.0/20
ipset add test 196.200.64.0/20
ipset add test 41.139.64.0/18
ipset add test 41.206.224.0/19
ipset add test 41.221.160.0/20
ipset add test 196.45.192.0/18
ipset add test 41.217.0.0/17
ipset add test 82.128.0.0/17
ipset add test 41.203.96.0/19
ipset add test 41.184.0.0/16
ipset add test 41.205.160.0/19
ipset add test 41.219.128.0/18
ipset add test 41.204.224.0/19
ipset add test 217.117.0.0/20
ipset add test 196.220.0.0/19
ipset add test 41.155.0.0/17
ipset add test 196.1.176.0/20
ipset add test 41.190.0.0/19
ipset add test 80.248.0.0/20
ipset add test 196.29.208.0/20
ipset add test 41.189.0.0/19
ipset add test 41.75.192.0/20
ipset add test 81.18.32.0/20
ipset add test 41.219.192.0/18
ipset add test 196.45.48.0/20
ipset add test 196.207.0.0/20

Use the set

iptables -I INPUT 1 -m set --match-set test src -j DROP
iptables -I FORWARD 1 -m set --match-set test src -j DROP

Save the set

ipset save -f /somewhere/something.txt

Load the set

ipset load -f /somewhere/something.txt

Save iptables

iptables-save >/somewhere/something.txt

Load iptables

iptables-restore < /somewhere/something.txt

Cron or systemd to automate save/load process.