How to check client IP against list of IP ranges in PHP?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How to check client IP against list of IP ranges in PHP?
I'm using $_SERVER['REMOTE_ADDR'] to get the client's IP. I would like to set a certain variable to TRUE if the IP is within one of the ranges I've got in a text file (I guess I could put the ranges into the database if needed). My list is currently formatted like this:
Hey man that's awesome - thanks! I had looked at the ip2long() function before posting, but I didn't realize what it did. I thought it was for doing reverse DNS or something like that. I think what I'm gonna do is put my ranges in the database and then write a function which uses ip2long() to check whether $_SERVER['REMOTE_ADDR'] is in the range. I'll post whatever I come-up with tonight. Once again, thank you very much!
Haha well I'll give him some credit because his example made it easy for me to learn to use ip2long(), but you're the one that pointed me toward the function so you were more vital. In any case, thanks to both of you!
Okay, so I put all my IP ranges in the database and wrote a function which takes an IP as input and checks the database to see if the IP is in the listed ranges. It returns TRUE if the IP is not in any of the ranges. The table where I put the ranges looks like:
$sql = 'SELECT
startip,endip
FROM
iprangetable
WHERE
startip < INET_ATON("'.$_SERVER['REMOTE_ADDR'].'")
ORDER BY
startip DESC
LIMIT 0,1';
In this situation, the IP addresses are stored in the database as internet addresses (a 32 bit number - see the usage for inet_aton to understand), and the database is queried exactly once and returns exactly one value, which is the correct value.
You would make this the startIP, then you would only have to check once to see if your IP was less than the end IP, after you got your return.
Or does the while loop stop running when return is executed?
Returning from the middle of a while loop is bad form.
It is OK, so long as the scripting language cleans up its stack properly on function exit, but I have in the past encountered subtle and pernicious errors by doing this, when the scripting language did NOT clean up its stack properly on this kind of exit.
Better to exit from the top level only, in all cases. I don't know that PHP would have a problem with it, but why buy trouble?
Thanks for that very educational feedback, jiml8. I'm reading up on INET_ATON right now, and will then read up on LIMIT. I haven't used either of those yet in my journey as a PHP/MySQL newbie. One question: Why did you choose to only select rows where StartIP is lower? In other words, is there a specific reason why you didn't just do the whole less than or equal to and greater than or equal to comparison with both EndIP and StartIP in the query? I'm thinking then one could have the function return TRUE/FALSE depending on whether the query returned an empty set or not.
EDIT: Wait, I haven't fully understood your query (yet) it seems. I need to do a lot more reading.
Or does the while loop stop running when return is executed?
The break is not necessary and the code will work without it. As a matter of style it is often considered poor form to have multiple return statements, however with a function as small as yours there is nothing particularly wrong with the return being where it is.
As for the SQL that jiml8 gave I think that it is possibly missing the check on the upper bound, maybe that was left as an exercise
Since the limit was set to 1 I woudl suggest that the ORDER BY is not required.
The purpose of that request is to sort in descending order through the startip index. Since the sort is in descending order, the startip address should be greater than the IP address you are testing, UNTIL you reach and pass your IP address as the count descends.
The very first IP address in the startip field that is LESS THAN your IP address is the ONLY IP address you are interested in (unless you have overlapping IP ranges, which shouldn't be the case).
So you return THAT ROW ONLY, then test the endip field IN THAT ROW to see if that address is greater than the address you are testing. If it is, you have a winner; this IP address is one you are interested in.
Let the database do the work; that is what it is for. This saves a scripted while loop and a whole bunch of database queries. You need the ORDER BY because you are specifying a descending search so you have to be explicit about the index.
Personally I think that it can be confusing (since I was initially) to mix the checking between the SQL and the code. Whilst it works as jiml8 stated I would prefer both the upper and lower checks to be in the SQL. That would also remove the need for the overlapping caveat.
I just setup a table in mysql that has a startip and endip associated with each user.
And in order to see if they are coming from the ip range I can do this.
SELECT * FROM `users` WHERE INET_ATON( '192.168.1.50' ) BETWEEN startip AND endip AND user='$user'
So if it returns a row then it is good.
You could easily flip the logic "NOT BETWEEN" and it would work for your case.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.