PHP Geolocation (change images)

Dear Sitepoint Members,
I am attempting to create a website which displays certain background images (which contain different pricing information) to users based on their country / location. There are 4 different sets of images - each with a different currency.

You can see the sort of thing I am after at
http://vps.net

Here, the source of the page shows that the body class is altered depending on the location of the visitor and in this way, a different set of css rules is used allowing differnet background images to appear based on the users country.

With the help of some sitepoint members, I have managed to get a Javascript example to work using geoplugin.com, but, using javascript does pose issues and I believe it would be preferable to do this serverside.

Geoplugin do provide a PHP Web Service:
http://www.geoplugin.com/webservices/php

My question is whether anyone here knows of the standard way of doing this and also, whether anyone can produce an example of the php required to get this to work using geoplugin.com.

Many thanks in advance for any help that anyone can give.

Kind Regards,
Zed.

Hi Zed,

Regarding !empty(): yes, that’s a mistake I made, your correction is indeed correct :slight_smile:

For the next bit, I’ve made two variations you could try. They both do the same, but the second one is a little easier to understand if you’re not up to speed on ternary operators:


function getCountryClass($countryCode) {
    $classMap = array(
        "US" => "unitedstates-skin", 
        "GB" => "greatbritain-skin"
    );
    $class = isset($classMap[strtoupper($countryCode)]) ? $classMap[strtoupper($countryCode)] : "default-skin" ;
    return $class;
}

function getCountryClass($countryCode) {
    $classMap = array(
        "US" => "unitedstates-skin", 
        "GB" => "greatbritain-skin"
    );
    if(isset($classMap[strtoupper($countryCode)])) {
        return $classMap[strtoupper($countryCode)];
    } else {
        return "default-skin";
    }
}

Hi Immerse,
Many thanks for that - I have managed to get an implementation which works to an extent:


<?php 
session_start();
if(empty($_SESSION['countryCode'])) {
    require_once('geoplugin.class.php');
    $geoplugin = new geoPlugin();
    $geoplugin->locate();
    $countryCode = $geoplugin->countryCode;
    $_SESSION['countryCode'] = $countryCode;
} else {
    $countryCode = $_SESSION['countryCode'];
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="style.css" rel="stylesheet" type="text/css" />

 



</head>
 
<body class="<?php echo $_SESSION['countryCode']; ?>" id="home"> 

<?php echo $_SESSION['countryCode']; ?>
	
</body>
</html>

Am I correct in making the correction of your oricinal code:

if(empty($_SESSION['countryCode'])) {

I changed from:

if(!empty($_SESSION['countryCode'])) {

In terms of the next step, step, I want to be able to set the different country codes in a class map like the earlier javascript implementation Server Herder provided:


<script type="text/javascript"> 
function getCountryClass(){ 
var classMap= { 
    "US": "unitedstates-skin", 
    "GB": "greatbritain-skin", 
    _default: "default-skin"
}, 
countryCode= geoplugin_countryCode(); 
if( countryCode in classMap )
   return classMap[countryCode]; 
else 
   return classMap['_default'];
}
</script>

If you are able to give any advice, it would be very much appreciated.

Kind Regards,
Zed.

Yes, if you don’t get a result, or you don’t get the result you want, simply use the default.

I think setting a timeout of about 2 seconds should be OK, perhaps the docs for the geoplugin class will tell you how you can do that.

Edit>>
Just had a peek at that geoPlugin class, they don’t specify a timeout. It shouldn’t be too hard to hack it in there though.
I’d just leave it for now though, if it starts failing, that’s the time to look at setting a timeout. It’d be a waste of your time to spend ages hacking a timeout in their code if it is never used :slight_smile:

Hi Immerse,
Many thanks for your reply.
I’m not too worried about people tampering with the classes; I will be using this script to simply alter a few background images which will have prices on them - the actual purchasing will be handled by a billing system and the values will not be passed on based on this script.

With regards Setting the cookie - you are right - that would reduce the number of requests and I will look into that.

When you say that it will slow the site down (and it’s a pitty I need it first) - is this a massive problem - presumably I could set a timeout to say that if it is not retrieved within 2 seconds, then use default? It is not a huge problem if people are shown the default if the script fails - the default will be USD which is ok.

In terms of what could go wrong, I will read the geoplugin docs, but, would a good solution be…If anyhting other than the 4 things I want are returned, then default = US?

Thanks for all of your continued help - it’s very useful to hear a professional opinion.

Kind regards,
Zed.

Hi Immerse,
I’ve had a chance to try it out and I have something which works:


<?php 
session_start();
if(empty($_SESSION['countryCode'])) {
    require_once('geoplugin.class.php');
    $geoplugin = new geoPlugin();
    $geoplugin->locate();
    $countryCode = $geoplugin->countryCode;
    $_SESSION['countryCode'] = $countryCode;
	$code = getCountryClass($countryCode);
} else {
    $countryCode = $_SESSION['countryCode'];
	$code = getCountryClass($countryCode);
}

function getCountryClass($countryCode) {
    $classMap = array(
        "US" => "unitedstates-skin", 
        "GB" => "greatbritain-skin"
    );
    $class = isset($classMap[strtoupper($countryCode)]) ? $classMap[strtoupper($countryCode)] : "default-skin" ;
    return $class;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="style.css" rel="stylesheet" type="text/css" />

</head>
 
<body class="<?php echo $code; ?>" id="home"> 

<?php echo $_SESSION['countryCode']; ?>
	
</body>
</html>

With this method, I am able to style the body based on the country class created - perfect!

I guess the method could be done withot using the session variable, but, at least the execution time on other pages during the visitors stay will be slightly reduced as the else statement will be invoked. Am I correct?

My next question is - have I done it the best way - could I do it more efficiently?
Also, in terms of security or if the geoplugin site is unavailable etc. are there things I need to think about?

Many thanks again for all of your help.
Kind Regards,
Zed.

It’s a pity you need the value straight away, as that will slow down the site when people first visit. You’re right about subsequent page views though. Because the countryCode has already been worked out and we store it in the session, it’ll be a lot faster.

How you could improve it?

Well, here’s a short list:

  1. save the countryCode to a cookie so that subsequent visits can read the cookie. That’ll cut down on the number of request to geoplugin quite a lot
  2. Read the geoplugin documentation. That way you can see what could go wrong on their side, and what values that might return, so you can take that into account. Also, they might have more information about setting timeouts and stuff.
  3. Always, and I mean always check the countryCode using geoPlugin again when people order/ pay for stuff. If they manage to change mess around with the classes on your page (using firebug etc.) or if they change the cookie themselves, you should not rely on that information for determining the price the user has to pay. So when they want to pay (or check their basket), check the countryCode again and if it’s different from what you’ve been showing the user, alert them about that (and show the correct prices).

Hi Immerse,
Many many thanks for your reply - it really is very much appreciated.
I’m away from my computer until this evening, but when Im back I’ll add the latest code and let you know how I get on.
Kind Regards,
Zed.

Without knowing how your templating system works it’s difficult, but here’s some code I borrowed from GeoPlugin’s homepage (you’ll need to download their PHP class).


session_start();
if(!empty($_SESSION['countryCode'])) 
    require_once('geoplugin.class.php');
    $geoplugin = new geoPlugin();
    $geoplugin->locate();
    $countryCode = $geoplugin->countryCode;
    $_SESSION['countryCode'] = $countryCode;
} else {
    $countryCode = $_SESSION['countryCode'];
}

// rest of your PHP code

With this, you can use the $countryCode variable to alter your HTML output to use the different skins.