Blocking Website Access by Country with PHP and IpToCountry

An easy method for blocking website access for specific countries or IP ranges. Just a few lines of code and virtually no server load.

By Tim Trott | PHP Tutorials | April 20, 2009

A while back one of my websites came under a massive attack receiving an additional 1000+ hits per day, all malicious construction and all from one particular country. Since I was fast approaching my allocated bandwidth limit I had to take action to stop them accessing the site, and fast!

I decided to take drastic action to block the entire country from accessing my site; I have had no legitimate visits from that country and can probably do without it. Whilst reading about blocking a country (or extension) everybody talks about how difficult and time-consuming it would be to use .htaccess and block IP address ranges manually.

I have found an easy method for blocking a country, it only takes a few lines of code and has virtually no server load, so read on and I'll tell you.

Blocking website access on a per-country basis works like this:

Goto http://www.phptutorial.info/iptocountry/the_script.html  for a look at "country identification without databases." Download the complete database (~540k) and extract it to a folder on your website. It will create a folder called 'ip_files'.

Next, use this bit of PHP at the top of each of your pages. (Code provided on phptutorial.info)

php
if ($_SERVER['HTTP_X_FORWARDED_FOR'])
  $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
else
  $ip   = $_SERVER['REMOTE_ADDR'];

$two_letter_country_code=iptocountry($ip);

function iptocountry($ip)
{
  $numbers = preg_split( "/./", $ip);    

  include("ip_files/".$numbers[0].".php");
  $code=($numbers[0] * 16777216) + ($numbers[1] * 65536) + ($numbers[2] * 256) + ($numbers[3]);    

  foreach($ranges as $key => $value)
  {
    if($key<=$code)
    {
      if($ranges[$key][0]>=$code)
      {
        $country=$ranges[$key][1];break;
      }
    }
  }

  if ($country=="")
  {
    $country="unknown";
  }

  return $country;
}

Then, add this little blocking script at the end of the code above:

php
if ($two_letter_country_code=="US")
  die();

You should replace US with the two letter country code for the country you are trying to block.

I have taken this a bit further on mine, in that, I check for a valid session, and if not found, run all the checks and create a session. This prevents the script from running every page load - just when a new visitor connects.

php
<?php
  session_start();
  if (!isset($_SESSION['FirstVisit'])) 
  {
    if ($two_letter_country_code=="US")
      die();
    else 
      $_SESSION['FirstVisit'] = 1;
  }
?>p

Of course, this blocking website access script isn't a perfect solution and will only protect your PHP pages, but in an emergency?

Note, you can find a full list of country codes listed in countries.php within ip_files folder of the zip file.

Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 44 comment(s). Why not join the discussion!

We respect your privacy, and will not make your email public. Learn how your comment data is processed.

  1. MR

    On Wednesday 28th of April 2021, MR said

    Can this script also works with IPv6?

    Best Regards
    MR

  2. MC

    On Wednesday 11th of December 2019, Mark Czapla said

    Confused about one thing regarding the session.
    It looks like it only stops the test at the end from running.
    Doesn't the script continue to run with every page load?

  3. NZ

    On Thursday 31st of October 2019, netanel zaken said

    My site based on WordPress.. I should put this code on header.php? Or should I put it on WordPress core.
    Somehow it's not blocking completely.

    Thanks!

  4. AN

    On Tuesday 19th of March 2019, Ankush said

    The above is blocking only Us but if I want to block many countries at same time. Is it possible.

    1. Tim Trott

      On Wednesday 20th of March 2019, Tim Trott  Post Author replied

      It is possible to block multiple countries using this code.

      Simply add this line

      $country_codes_to_block = array('US', 'CA', 'RU');

      Then replace the code

      if ($two_letter_country_code=="US")

      with

      if (in_array($two_letter_country_code, $country_codes_to_block))

      Thanks to Shreyansh Jha for adding this code example.

      1. BK

        On Monday 27th of January 2020, Ben Kamphuis replied

        i have tried to use a single php page to place the code and refer to this code instead of adding it to every php page.

        but i am getting the following errors:

        Notice: Undefined index: HTTP_X_FORWARDED_FOR in /home/degferet/public_html/ipblocker/blocker.php on line 2

        Warning: include(ipblocker/ip_files/.php): failed to open stream: No such file or directory in /home/degferet/public_html/ipblocker/blocker.php on line 13

        Warning: include(): Failed opening 'ipblocker/ip_files/.php' for inclusion (include_path='.:/opt/cpanel/ea-php56/root/usr/share/pear') in /home/degferet/public_html/ipblocker/blocker.php on line 13

        Notice: Undefined variable: ranges in /home/degferet/public_html/ipblocker/blocker.php on line 16

        Warning: Invalid argument supplied for foreach() in /home/degferet/public_html/ipblocker/blocker.php on line 16

        Notice: Undefined variable: country in /home/degferet/public_html/ipblocker/blocker.php on line 27

  5. AN

    On Monday 4th of December 2017, Anthony said

    Here's my contribution full contribution. THIS answers a lot of searchers questions and we use it now... A "Thank you
    will suffice ;-)

    1. Unzip files to a new folder. Should have something like | New_Folder | ip_files
    2. Create a database in mysql and call it whatever but for example "poofoo". Table is: "peewee"
    Columns: id, ip, date (fix it how you like)

    I created another table to actually log what is blocked from the block list to check against. The goal of this is to simply block either everyone but, country and/or single ip addresses. Yes, it's programmed to accept 123.45, 123.4, 123.456 or even 123. No need to type the whole ip unless you want to block that particular one or you can just block the whole node if i'm saying that right... Here we go. a nice thank you kindly would suffice, no paypal needed.

    A. Create a connection file in the "new folder" directory | connector.php

    <?php
    $dbase = 'poofoo'; / DATABASE NAME
    $host = 'hostname'; /DATABASE HOST LOCATION/SERVER
    $user = 'theuser_foo'; /USER NAME
    $pass = 'texasroadhouse'; /PASSWORD
    $conn = mysqli_connect($host, $user, $pass, $dbase) or die (mysql_error());
    ?>

    ------

    B. Create a new file within the "new folder" directory | blocker.php

    <?php
    ini_set('display_errors', 'Off');

    if ($_SERVER['HTTP_X_FORWARDED_FOR'])
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];

    else
    $ip = $_SERVER['REMOTE_ADDR'];

    $two_letter_country_code=iptocountry($ip);
    function iptocountry($ip)
    {
    $numbers = explode( ".", $ip);
    include("ip_files/".$numbers[0].".php");
    $code=($numbers[0] * 16777216) + ($numbers[1] * 65536) + ($numbers[2] * 256) + ($numbers[3]);

    foreach($ranges as $key => $value)
    {
    if($key<=$code)
    {
    if($ranges[$key][0]>=$code)
    {
    $country=$ranges[$key][1];break;
    }
    }

    }

    if ($country=="")
    {
    $country="unknown";
    }

    $cur_country = $country;

    include ("connector.php");
    $query = "SELECT * FROM peewee";
    $result = mysqli_query($conn, $query);

    if (!$conn) {
    die;

    }

    while($row = mysqli_fetch_assoc($result)) {

    $cblock = $row['name'];
    /This if statement searches for a string variable and once found, blocks anything else not US based.
    if($cblock === "USA ONLY" and $country != "US") {
    mysqli_free_result($result);
    mysqli_close($conn);
    /send their butts to somewhere else and be done with it
    echo "<META http-equiv='refresh' content='0; URL=http://www.leapfrog.com'>";
    }

    /If they are US based but are on the block list
    $blocked = $row['blocked_country_by_ip_set'];

    }
    /If the database row matches the country array and the boolean of $blocked is true...
    if($cblock === $country and $blocked === 1) {
    $time = date('Y-m-d H:i');
    $insert = "INSERT IGNORE INTO table_of_blocked_logs VALUES ('','$ip','$ip',$time')";
    if ($conn->query($insert) === TRUE) {} else {
    /DO something here not show the error to the person you are actually wanting to block just in case
    exit;
    }

    mysqli_free_result($result);
    mysqli_close($conn);
    echo "<script>alert('Please take a moment to review a very special offer we are running before you review!')</script>";
    echo "<META http-equiv='refresh' content='0; URL=http://www.gerber.com'>";

    }
    }

    / The below bracket might be one to many, if you get the white screen of php death, remove it.
    }

    ?>
    ----

    C. Now at the top of your index.php page(rename to *.php for those using .htm,.html), you can paste the following;

    <?php include "blocker.php" ?>

    Use above for top of the tree and respectfully use your switch as needed when inside directories.

    <?php include "../blocker.php" ?>

  6. SJ

    On Monday 12th of June 2017, Shreyansh Jha said

    For those who are looking to block multiple countries with this code I have a solution for you. However, I have not tested it yet but it should work.

    Step 1: Store country codes in database that you want to block. If you do not want to use database then use array directly or some other methods you like. But I prefer storing country codes in database.

    Step 2: Extract the codes from database and store it in a variable.
    Example: $country_codes_to_block = $row['block_countries']; / Fetched from database.

    Step 3: Replace the code

    if ($two_letter_country_code=="US")

    to

    if (in_array($two_letter_country_code, $country_codes_to_block))

    Step 4: Done. This should block all the countries whose country codes you have stored in database.

    Still not clear? Sorry, I can't be more clear than this. I made it as much simple and easy to understand as possible. Now apply some brains. Happy coding ;)

  7. BR

    On Thursday 10th of March 2016, brody said

    is there a reason why i'm getting Fatal error: Call to undefined function iptocountry()

    for this line of code " $two_letter_country_code=iptocountry($ip); "

  8. JU

    On Wednesday 18th of November 2015, jukka said

    the preg_split should be "/./"

    toright-toleft-dot-toright (sorry for bad english)
    $numbers = preg_split( "/./", $ip);

  9. DE

    On Wednesday 14th of January 2015, Deepak said

    Fatal error: Cannot redeclare iptocountry() (previously declared in /home/u475022455/public_html/head.php:61) in /home/u475022455/public_html/head.php on line 85

    give me solution

  10. MI

    On Monday 11th of August 2014, Miki said

    There is a website called www.myipblocker.com that does country and ip blocking pretty smoothly......

  11. GR

    On Tuesday 1st of July 2014, Grgo said

    Hy,
    Thanks for that. It works good for me over a year, but now I would like to add another country.
    I wonder how you block 2 countries.
    Thanks, G

  12. AL

    On Tuesday 20th of May 2014, adam lee said

    i want block some country's a list of them and any ip or a visitor log in to my page from this country's i want send them to a link .
    so how i can do that ?
    if any one here plz reply me bcz i need it to much .

    and thank you
    adam lee

  13. BE

    On Saturday 15th of February 2014, Ben said

    if ($two_letter_country_code != "US" || !strstr(strtolower($_SERVER['HTTP_USER_AGENT']), "googlebot"))
    die();

    i think this is working. code above allowing me to register at google webmaster tools.

  14. BE

    On Saturday 15th of February 2014, Ben said

    Anyone using this with cloudflare? Is it working?

  15. NE

    On Saturday 3rd of August 2013, Neil said

    Hi Tim,

    Is it possible to block and entire country (say India) yes let one specific IP address from India through?

    Many thanks,
    Neil.

    1. Tim Trott

      On Sunday 4th of August 2013, Tim Trott  Post Author replied

      Hi Neil

      You could do something along the lines of:

      $allowed = array('0.0.0.0', '1.1.1.1');

      if (($two_letter_country_code=="IN") && (!in_array($ip, $allowed))
      {
      / do block here
      }
      else
      {
      / do allow here
      }

      Note: This has not been tested but should get you going.

      Tim

  16. VA

    On Tuesday 9th of July 2013, Vanessa said

    Im in CA USA and my block code reads:

    if ($two_letter_country_code!="US")
    die();

    However - IM dying..... I think I need an updated database but I cant find the correct DB in the php format on software77.net

    Any recomendations would be fantastic.

  17. JO

    On Monday 6th of May 2013, joe said

    I appreciate the help here. My webhost directed me to this link.

    With that said, I am a total noob when it comes to website building/editing.

    I know the above suggestion may sound simple to most of you. But is there a way to dumb it down to someone at my level. I am using wordpress and am a little bit familiar with using an FTP client to modify the coding of the site/as well as doing it thru the WP editor function.

    So, I am reasonably confident I can download the file and get it over to my website via FTP client. I assume I just put it in primary folder for the entire website.

    Once I do that, how do I put the php code into every page on my site to keep it blocked? I have dozens of files with a .php extension on my site.

    Thank you for your patience and your help.

  18. JO

    On Thursday 18th of April 2013, Joey said

    PHP5 turns off the ability to use the include() statement for security reasons by default. As a result, it won't pull in the geoip data. Can you, or anyone, suggest an alternative to using the include() statement? Thanks! Joey

    1. Tim Trott

      On Friday 19th of April 2013, Tim Trott  Post Author replied

      I've not heard of PHP5 disabling include before, is this a particular "feature" of your hosting provider? Do you get any error messages when you use it?

      You could try include_once instead. This function will check to see if the file has already been included and if it has ignore the request instead of throwing an error.

      Tim

  19. PA

    On Tuesday 16th of April 2013, parisa said

    Thank you so much
    it was so usefull;

  20. MD

    On Monday 25th of February 2013, mark dedrick said

    Could you please post the code for this "I have taken this a bit further on mine, in that I check for a valid session, and if not found, run all the checks and create a session" ?. I'm not good at php and don't know how to implement that. Thanks in advance

    1. Tim Trott

      On Tuesday 26th of February 2013, Tim Trott  Post Author replied

      Hi Mark,

      That's going back a bit since I used this code. I'll have a dig through my backups and post what I find.

      Tim

  21. JO

    On Thursday 10th of January 2013, John said

    Thank you. This method has been recommended by the Hostgator support forum, so you must be doing something right!!

    http://support.hostgator.com/articles/specialized-help/technical/can-i-block-an-entire-region-or-country-from-seeing-my-site

  22. BE

    On Tuesday 4th of December 2012, ben said

    How do you allow google bot etc in this script?

  23. TH

    On Thursday 18th of October 2012, themonleymixer said

    I am trying to include this in wordpress and am having a but of trouble, I think it has to do with how wordpress sees directories
    <?php
    if ($_SERVER['HTTP_X_FORWARDED_FOR'])
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    else
    $ip = $_SERVER['REMOTE_ADDR'];

    $two_letter_country_code=iptocountry($ip);

    function iptocountry($ip)
    {
    $numbers = preg_split( "/./", $ip);

    include("ip_files/".$numbers[0].".php");
    $code=($numbers[0] * 16777216) + ($numbers[1] * 65536) + ($numbers[2] * 256) + ($numbers[3]);

    foreach($ranges as $key => $value)
    {
    if($key<=$code)
    {
    if($ranges[$key][0]>=$code)
    {
    $country=$ranges[$key][1];break;
    }
    }
    }

    if ($country=="")
    {
    $country="unknown";
    }

    return $country;
    }
    if ($two_letter_country_code!="US")
    die();
    ?>

    this is what i used to block all non us and this is the result

    Warning: include(ip_files/.php) [function.include]: failed to open stream: No such file or directory in /home/superbha/public_html/wp-content/themes/anonymous-elegance/header.php on line 17

    Warning: include(ip_files/.php) [function.include]: failed to open stream: No such file or directory in /home/superbha/public_html/wp-content/themes/anonymous-elegance/header.php on line 17

    Warning: include() [function.include]: Failed opening 'ip_files/.php' for inclusion (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/superbha/public_html/wp-content/themes/anonymous-elegance/header.php on line 17

    Warning: Invalid argument supplied for foreach() in /home/superbha/public_html/wp-content/themes/anonymous-elegance/header.php on line 20

    1. MR

      On Monday 25th of May 2020, MR replied

      Hi, my tip is, when the file are not found, such as "Warning: include(ip_files/.php) [function.include]: failed to open stream: No such file or directory.." replace the following row.

      $numbers = preg_split( "/./", $ip);
      to this row
      $numbers = preg_split( "/\./", $ip);

      Many thanks to Tim and also to http://www.phptutorial.info/iptocountry/the_script.html for the Script+Tutorial
      Best regards from Germany!
      MR

  24. TU

    On Saturday 22nd of September 2012, tuba said

    thank you for this tutorial!

    I don't want to block any country rather I would like to redirect users to a specific page based on country. Surely helpful.

  25. SP

    On Thursday 30th of August 2012, Spyros said

    So glad I found this, I was trying to use an htaccess method and it wouldn't work. Great article, bookmarked for the future :D

  26. HA

    On Tuesday 8th of May 2012, Harcourt said

    Even though this is an old topic I thought I'd add to it...

    1. You can run PHP on HTML pages by using a "force-type" tag in .htacess, like this:

    1. AddHandler application/x-httpd-php5 .html

    or if that doesn't work...

    2. SetHandler application/x-httpd-php5 .html

    This tells the Server to treat all of your html pages like they are php pages. Only use one, not both!

    This adds an extra load to your Server so you may want to restrict it to certain pages by adding the (FILES index.html) limiter.

    Rather than putting it on every page, use the "include" function at the top of each page, this way you can make changes very quickly if you need to.

    My web pages *were* getting hammered by spammers and hackers from the RIPE and APNIC networks. So I went looking for a *country blocking* system and found this.

    I created my own script that does the same thing, but it uses an entirely different setup. I also use other methods to block hits from some troublesome ISPs.

    So far I haven't had any visits from RIPE or APNIC since using these codes. :-D

  27. SH

    On Wednesday 4th of January 2012, shivi said

    Can i use this code for html as well php pages to block some of the countries from viewing the data.?

    1. Tim Trott

      On Friday 20th of January 2012, Tim Trott  Post Author replied

      The code will only run through the PHP engine, so to run it on html pages you would need to have these processed via PHP. Alternatively you may be able to get jQuery or similar framework to perform the same task client side.

  28. AC

    On Saturday 8th of October 2011, achmad said

    I'm not php proficient, I just wanted to block 2 country for example Uk and Greanada, how to write the code in the end of the script ?

  29. PR

    On Monday 1st of August 2011, Prema said

    Thanks very much for a very useful script.
    Noticed that the script fails on php 5 with the ip split.
    We rewrote that tiny section using explode instead
    and it works fine on our site.

    Was:
    $numbers = preg_split( "/./", $ip);
    Now:
    $numbers = explode( ".", $ip);

    1. BE

      On Saturday 8th of September 2012, ben replied

      Allow spesific country with
      if ($two_letter_country_code != "DE")
      die();

      My question: Is this good for google bot and seo?

      1. Tim Trott

        On Thursday 29th of November 2012, Tim Trott  Post Author replied

        This would be bad for SEO as it would block mostly all web crawlers including googlebot

    2. FA

      On Monday 21st of May 2012, faryit replied

      Thank you :)

  30. DA

    On Wednesday 1st of July 2009, Daniel said

    I need this, but I am php challenged. :) Does the above code block the US, or does it block everything except the US? I need to block ALL countries EXCEPT the US. If anyone reading this can help me, I can be contacted at daniel "@" onelung.net . Thx!

    1. Tim Trott

      On Saturday 4th of July 2009, Tim Trott  Post Author replied

      The code above will block the US. To reverse this and block everything apart from US try the following:

      <pre lang="php">if ($two_letter_country_code != "US")
      die();</pre>

      Hope that helps

  31. GY

    On Monday 18th of August 2008, Gytis said

    my friend modify original code and you can use few countries now :

    $value){
    if($key=$code){$two_letter_country_code=$ranges[$key][1];break;}
    }
    }
    if ($two_letter_country_code==""){$two_letter_country_code="unkown";}
    return $two_letter_country_code;
    }
    ?>

  32. CH

    On Saturday 14th of June 2008, Chris said

    How have you overcome the issue that the IP to country database changes almost daily? Have you looked at any of the services and connecting to them?

  33. PE

    On Monday 11th of June 2007, peter said

    going to try it now, I had someone stalk me from Italy, had some php ip blocks but she kept on using different machines.

    A country block is what I am looking for.

    thanks