gr68
gr68

Reputation: 502

check if an ip matches any ip contained in an ip list using php

in array $white I have an ip list like this (about 10000-12000 ips)

74.125.244.0/22
207.126.144.0/20
77.238.189. 
212.211.149.128/26
194.25.134.8 
194.25.134.9 
194.25.134.12       
174.2.114.12-174.2.115.255
153.2.242.243
153.2.244.12 
153.2.244.50 
153.2.244.63 
153.2.246.30 
153.2.246.31 
153.2.246.35 
153.2.247.30 
153.2.247.31 
153.2.247.32      

So, the ip list in array $white can contain ip(s) in these three format

153.2.247.32 (simple ip address)
207.126.144.0/20 ( CIDR notation )
174.2.114.12-174.2.115.255 ( Hyphenated ranges )

My goal is to check if ips listed in another array , $ips (about 1000-2000 ips) , are present in the $white list.

The format in the $ips list is only simple ip address like

207.126.144.0
207.126.141.2
201.126.144.5

I am doing this

foreach ($ips as $check) {
if (in_array($check,$white)){
echo "Ip $check exists";
}
}

However it's only good to check simple ip addresses , but I cannot check if the ips listed in $ips are contained in the Hyphenated ranges and CIDR ranges of $white .

I found a solution using ip_in_range.php https://github.com/irazasyed/php-ip-range/blob/master/ip_in_range.php

foreach ($ips as $check) {
    if (in_array($check,$white))
    {
    echo "Ip $check exists";
    }
    else
    {
    foreach( $white as $checkrange )
    {       
if (substr_count($checkrange, '/')>=1 or substr_count($checkrange, '-')>=1 )
{ 
    if (ip_in_range($check, $checkrange)) 
{ 
    echo "Ip $check exists"; 
    break;
}
}

}
}
}

But it's very slow , because $white and $ips are huge lists . Does exist a faster and more efficient solution ?

Upvotes: 0

Views: 1997

Answers (2)

Alex Howansky
Alex Howansky

Reputation: 53563

Pre-expand all the whitelist ranges into one giant list of singular IP addresses. For example, given:

1.2.3.4
2.3.4.5
3.4.5.6-3.4.5.10

You'd process the list once to generate this list:

1.2.3.4
2.3.4.5
3.4.5.6
3.4.5.7
3.4.5.8
3.4.5.9
3.4.5.10

Then, store that list in a key/value cache. Could be something as simple as a native PHP associative array sitting in memory, or something more robust like a Redis database. Then you've got a simple equivalency check for inclusion. Implemented correctly (e.g., via array_key_exists() instead of in_array()), you'll get O(1) performance for an IP lookup, regardless of the size of the whitelist. It can't get faster.

Instead of doing all the range processing over and over again on every single IP check, you're doing it only once when the whitelist changes. You're basically giving up memory to gain CPU.

Upvotes: 2

Zeljka
Zeljka

Reputation: 376

You can try with preg_grep:

foreach ($ips as $check){

    if(preg_grep("/$check/i",$white))
    {
        echo $input." whitelisted";
    }else{
        echo $input." blacklisted";
    }
{

Upvotes: 0

Related Questions