Google Answers Logo
View Question
 
Q: IP/Block/Range List PHP Script ( Answered 5 out of 5 stars,   0 Comments )
Question  
Subject: IP/Block/Range List PHP Script
Category: Computers > Programming
Asked by: theboistard-ga
List Price: $65.00
Posted: 26 Jul 2004 10:30 PDT
Expires: 25 Aug 2004 10:30 PDT
Question ID: 379235
I need a very simplified script (no extras, no html parsers, no
multi-functioned scripting, etc) with ONE function that I can use to
check whether an IP (in standard form, aka 192.168.1.105) is in a
special "filter" list which contains numerious entries, in form of
single IPs, IP ranges specified as 192.168.1.*, IP ranges specified as
192.168.1.??, and IP ranges specified as 192.168.1.0-100. If the
looked up IP belongs to any of the single IP entries, or is within a
range of any, then it should return a $TRUE, otherwise a $FALSE.

For example, if your function is named chkiplist() and I do :

$ipchk1 = chkiplist(24.25.26.27);
$ipchk2 = chkiplist(24.26.27.28);
$ipchk3 = chkiplist(25.28.27.28);
$ipchk3 = chkiplist(26.27.28.29);

And the block list is:

24.25.26.27
24.26.*.*
25.26.??.2?
26.27.0-50.0-225

ALL of them should return $TRUE, because each of the entries in the
block list corresponds to the IPs looked up, respectively.

Also, I would like to be able to place 'comments' in the block list, in form of a :

# Comment Here
// Another Comment hEre
/ Another Comment here
/* Another Comment here */
; Another comment here

Or you can simply just have the script check whether the line contains
an IP/Range, and if it does not, then the line is a comment.

Overview:

1) Single working function, not a full script, the simpler, the better
2) Uses a txt filter list, one IP/Range per line
3) IP/Range Format:
  - 192.168.1.105 (Single IP)
  - 192.168.1.* (IP Range with *)
  - 192.168.1.100-110 (IP range with -)
  - 192.168.?.* (IP range with ?)
4) Script should be able to ignore comments (text) within the block
.txt list and skip the comments, but check the IP/Range entries.
5) Script should return a simple $TRUE if the looked up IP matches any
of the entries, and a $FALSE if it does not.
6) Script must be clean, but also very short and simple.
7) If possible, have it UNIX/win32 reverse compatible


Please let me know if you need me to include any specifications. Thank you.
Answer  
Subject: Re: IP/Block/Range List PHP Script
Answered By: palitoy-ga on 26 Jul 2004 12:16 PDT
Rated:5 out of 5 stars
 
Hello theboistard

Thank-you for your question.  I have pasted the solution you require below.

I have commented the script so that you can see what it is doing at
each stage - these can be removed once you are happy that you
understand this.

The script returns true (or "1") if a match is not found, if it is not
it returns false (or "").

If you have any questions regarding this function please ask for
clarification and I will do my best to help further.

<?
function chkiplist($ip) {
  # read in the ip address file
  $lines = file("ipaddresses.txt");
  # set a variable as false
  $found = false;
  # loop through the ip address file
  foreach ($lines as $line) {
    # remove line feeds from the line
    $line = chop($line);
    # replace * with a 3 digit number
    $line = str_replace("*","\d{1,3}",$line);
    # replace ? with a single digit
    $line = str_replace("?","\d",$line);
    # if it contains a - character
    if ( strpos($line,"-",0) <> "" ) {
      # split the line and number you are checking into parts
      $line_chunks = split(".",$line);
      $ip_chunks = split("-",$ip);
      # set a variable to count things
      $valid = 0;
      # for each number in the ip address
      for ( $i=0;$i<4; $i++ ) {
	# if the chunk contains a -
	if ( strpos($line_chunks[$i],"-",0) <> "" ) {
	 # if the line chunk is the same as the ip chunk then increment the 
         # counter
	   if ( $line_chunks[$i] == $ip_chunks[$i] ) { $valid++; };
	}
	else { # if no - in the line chunk
	  $splitit = split("-",$line_chunks[$i]);
	  # increment the counter if the chunk is in the range
	  if ( ($splitit[0] >= $ip_chunks[$i]) && ($splitit[1] <=
$ip_chunks[$i]) ) { $valid++; };
	}
      };
      # if all the parts match then return a match
      if ( $valid == 4 ) { $found = true; };
    }
    else { # if the line does not contain a -
      # if the line matches the ip address then return a match
      if ( preg_match ("|$line|",$ip) ) { $found = true; };
    }
  }
  return $found;
}; # end function
?>

Request for Answer Clarification by theboistard-ga on 26 Jul 2004 13:12 PDT
Hello palitoy,

I think your preg_match string is wrong.

I implemented your function and it seems to return a 1 no matter what
parameters I specify, even if I leave a "// Comment". I debugged it to
be because of this line (by changing the return value):

if ( preg_match ("|$line|",$ip) ) { $found = true; };

Let me know if you have an idea why this may happen

Clarification of Answer by palitoy-ga on 27 Jul 2004 01:31 PDT
I am having trouble replicating the problem on my PC as it works as it
should on my PC.

Can you please supply the following to me via Google Answers:

1) The PHP script (or lines) you are using to call the function
(including the IP addresses you are using to test the match).
2) A copy of the ipaddresses.txt file that you are using with the comments.

The preg_match line you indicated simply takes the line direct from
the ipaddresses.txt file and if this regular expression matches the ip
address passed to the function it returns true (1).

Clarification of Answer by palitoy-ga on 27 Jul 2004 01:39 PDT
I have just had an idea!  Your ipaddresses.txt file also includes
blank lines doesn't it?!

In the script I sent to you replace:

# remove line feeds from the line
$line = chop($line);

With:

# remove line feeds from the line
$line = chop($line);
if ( $line == "" ) { continue; };

Request for Answer Clarification by theboistard-ga on 27 Jul 2004 10:27 PDT
hello palitoy,

I got it to work, thank you very much, but I have an additional
request that I would like to add to the main question, and I am
willing to tip you an additional $65.00 if you make the code changes.
You will understand why the tip is so high. I need the following
features, mostly format changes:

1) The filter list will contain an entry such as :

192.168.1.100 - 192.168.1.105

2) The filter list should also work with CLASS B/C ranges :

192.168.* - 192.169.*

3) The filter list should allow comments to be placed AFTER the IP entries:

192.168.* - 192.169.* Here goes my comment

4) The filter list should also work with the following:

192.168.3.x (similar to *)

5) The filter list should also differentiate whether a range is given
or its a comment:

192.168.* - 192.169.*

(The above is a range)

192.168.0.* - My Home Network IPs

(The above is a comment)

I am so very sorry for not including these requests in the main
question. Its just that I received filter lists which contain such
entries, and the list itself is very large for me to reformat the IPs
to the format that the script can recognize.

I am ready to rate you with 5 stars, but if you wish to receive the
additional tip, please include the above features to which I would be
very thankful for.

Thanks

Clarification of Answer by palitoy-ga on 27 Jul 2004 10:39 PDT
I will work on these additions for you and post it as soon as I can...

Request for Answer Clarification by theboistard-ga on 27 Jul 2004 10:50 PDT
Thank you very much, I will wait patiently.

Clarification of Answer by palitoy-ga on 27 Jul 2004 11:13 PDT
I need a little more clarification on the latest additions to the question...

If a line has a comment and an IP address on it what should the
function do?  Point 3) above suggests it should process the IP, point
5) suggests it should not, obviously only one can be right!

Request for Answer Clarification by theboistard-ga on 27 Jul 2004 13:09 PDT
hello palitoy,

im sorry for not making it clear enough, look below for clarification:


I'd say it would be good if the script checks whether the line
contains an IP/RAnge entry or a combination of an IP/RAnge + comment.

Here are some entries:

127.0.0.1 Localhost
10.68.* - 10.69.* 
24.19.14.12 - 24.20.*.* Added on July 24, 2004
14.* - CyberLink Range
192.168.24.* - 192.168.29.* First Floor Network
192.168.1.* - Local Network
68.24.51.* My local ISP
68.95.*.* : Sys Admin's Range
69.10.1?.* -- Linkage Servers
69.12.44.19 - Linkage Servers 2

I'd say the script has to be very "smart" to know whether the part
after the "-" is a comment (like "Local Network") or a part of a
specified range, and it would be very nice if it can even allow
comments on every line, no matter if its an IP, IP Range (in form of
*, -, ?, etc) or whatever.

Please let me know if this is not clear.

Clarification of Answer by palitoy-ga on 28 Jul 2004 02:58 PDT
This took quite a lot of working out but I think I have it now ;-)

I have taken a completely different approach to the problem this time
which is why it took so long.  The function now converts the IP
addresses to a 13-digit number which can then be compared.  This was
necessary for the range checking part.

If you have any queries, let me know!

function chkiplist($ip) {
	# read in the ip address file
	$lines = file("ipaddresses.txt");
	# set a variable as false
	$found = false;
	# convert ip address into a number
	$split_it = split("\.",$ip);
	$ip = "1" . sprintf("%03d",$split_it[0]) .
sprintf("%03d",$split_it[1]) . sprintf("%03d",$split_it[2]) .
sprintf("%03d",$split_it[3]);
	# loop through the ip address file
	foreach ($lines as $line) {
		# remove line feeds from the line
		$line = chop($line);
		# replace x with a *
		$line = str_replace("x","*",$line);
		# remove comments
		$line = preg_replace("|[A-Za-z#/]|","",$line);
		# set a maximum and minimum value
		$max = $line;
		$min = $line;
		# replace * with a 3 digit number
		if ( strpos($line,"*",0) <> "" ) {
			$max = str_replace("*","999",$line);
			$min = str_replace("*","000",$line);
		}
		# replace ? with a single digit
		if ( strpos($line,"?",0) <> "" ) {
			$max = str_replace("?","9",$line);
			$min = str_replace("?","0",$line);
		}
		# if the line is invalid go to the next line
		if ( $max == "" ) { continue; };
		# check for a range
		if ( strpos($max," - ",0) <> "" ) {
			$split_it = split(" - ",$max);
			# if the second part does not match an ip address
			if ( !preg_match("|\d{1,3}\.|",$split_it[1]) ) {
				$max = $split_it[0];
			}
			else { 
				$max = $split_it[1];
			};
		}
		if ( strpos($min," - ",0) <> "" ) {
			$split_it = split(" - ",$min);
			$min = $split_it[0];
		}
		# make $max into a number
		$split_it = split("\.",$max);
		for ( $i=0;$i<4;$i++ ) {
			if ( $i == 0 ) { $max = 1; };
			if ( strpos($split_it[$i],"-",0) <> "" ) {
				$another_split = split("-",$split_it[$i]);
				$split_it[$i] = $another_split[1];
			} 
		$max .= sprintf("%03d",$split_it[$i]);
		}
		# make $min into a number
		$split_it = split("\.",$min);
		for ( $i=0;$i<4;$i++ ) {
			if ( $i == 0 ) { $min = 1; };
			if ( strpos($split_it[$i],"-",0) <> "" ) {
				$another_split = split("-",$split_it[$i]);
				$split_it[$i] = $another_split[0];
			} 
		$min .= sprintf("%03d",$split_it[$i]);
		}
		# check for a match
		if ( ($ip <= $max) && ($ip >= $min) ) {
			$found = true;
			break;
		};
	}
	return $found;
}; # end function

Request for Answer Clarification by theboistard-ga on 28 Jul 2004 10:02 PDT
Neatly done, thank you so very much.

I am going to rate this question, and then if I have any problems, I
will post them as a comment. Please check back every once in awhile
for a few days just incase, thank you.

Clarification of Answer by palitoy-ga on 28 Jul 2004 10:49 PDT
Thank-you for the 5-star rating, tip and generous comments they are
all much appreciated.  If you need any more help regarding this please
just ask for clarification as you have been doing and I will do my
best to help (if you do it this way it is flagged up as something for
me to clarify whereas just a comment I may miss).

Thanks again.
theboistard-ga rated this answer:5 out of 5 stars and gave an additional tip of: $70.00
palitoy is officially my PHP hero!

not only he answered my question with ease and speed unlike any other,
but he also listened in to my problems that followed shortly after,
then took additonal requests to add more features, and even recoded
the whole script, thus doing two jobs for the deal of one.

thank you so very much palitoy, you are trully a great google researcher.

Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy