Web Design that taps into the haromny and vision of your dreams.

Blocking Website Access by Country with PHP

Using PHP to Block Website Access by Country

Written By on in Coding

374 words, estimated reading time 2 minutes.

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 the drastic action to block the entire country from accessing my site; I have had not legitimate visits from that country and can probably do without. Whilst reading about blocking a country (or extension) everybody talks about how difficult and time consuming it would be using .htaccess and blocking 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.

It 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)

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:

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
  session_start();
  if (!isset($_SESSION['FirstVisit'])) 
  {
    if ($two_letter_country_code=="US")
      die();
    else 
      $_SESSION['FirstVisit'] = 1;
  }
?>p

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

Note, you can find a list of country codes listed in countries.php within ip_files.

Last updated on: Wednesday 21st June 2017

 

Comments
Anthony

Anthony

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" ?>

Reply to Anthony
Shreyansh Jha

Shreyansh Jha

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 ;)

Reply to Shreyansh Jha
brody

brody

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); "

Reply to brody
jukka

jukka

the preg_split should be "/./"

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

Reply to jukka
Deepak

Deepak

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

Reply to Deepak
Miki

Miki

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

Reply to Miki
Grgo

Grgo

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

Reply to Grgo
adam lee

adam lee

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

Reply to adam lee
Ben

Ben

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.

Reply to Ben
Ben

Ben

Anyone using this with cloudflare? Is it working?

Reply to Ben
Neil

Neil

Hi Tim,

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

Many thanks,
Neil.

Reply to Neil
Tim Trott

Tim Trott

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

Reply to Tim Trott
Vanessa

Vanessa

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.

Reply to Vanessa
joe

joe

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.

Reply to joe
Joey

Joey

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

Reply to Joey
Tim Trott

Tim Trott

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

Reply to Tim Trott
parisa

parisa

Thank you so much
it was so usefull;

Reply to parisa
mark dedrick

mark dedrick

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

Reply to mark dedrick
Tim Trott

Tim Trott

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

Reply to Tim Trott
John

John

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

Reply to John
ben

ben

How do you allow google bot etc in this script?

Reply to ben
themonleymixer

themonleymixer

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
[code]
<?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();
?>
[/code]

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

[code]

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

[/code]

Reply to themonleymixer
tuba

tuba

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.

Reply to tuba
Spyros

Spyros

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

Reply to Spyros
Harcourt

Harcourt

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

Reply to Harcourt
shivi

shivi

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

Reply to shivi
Tim Trott

Tim Trott

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.

Reply to Tim Trott
achmad

achmad

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 ?

Reply to achmad
Prema

Prema

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);

Reply to Prema
ben

ben

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

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

Reply to ben
Tim Trott

Tim Trott

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

Reply to Tim Trott
faryit

faryit

Thank you :)

Reply to faryit
Daniel

Daniel

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!

Reply to Daniel
Tim Trott

Tim Trott

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

Reply to Tim Trott
Gytis

Gytis

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;
}
?>
Reply to Gytis
Chris

Chris

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?

Reply to Chris
peter

peter

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

Reply to peter

 

Leave a Reply

Your email address will not be published.





If you find something abusive or that does not comply with our terms or guidelines please flag it as inappropriate.

 

Copyright © 2001-2018 Tim Trott, all rights reserved. Web Design by Azulia Designs

This web page is licensed for your personal, private, non-commercial use only.

Disclaimer, Privacy & LegalSitemapContact Me