Guide: Gi besøkende ulike websider

Guide: Gi besøkende ulike websider

Har du lurt på hvor folk som besøker websidene dine kommer fra, eller har du lyst til å gi de en litt forskjellig side ut fra hvor de kommer fra? For eksempel en norsk utgave hvis de kommer fra Norge og engelsk hvis ikke. Eller vise flagget til landet de kommer fra? Det finnes mange løsninger på denne utfordringen.

Her viser jeg hvordan man kan gjøre det ved hjelp av PHP og en database over hvilke land ulike IP-adresser tilhører.

ip-to-country.directi.com har en gratis database over hvilke land de ulike IP-adressene er delt ut til. Den kan også lastes ned i CSV-format.

Databasen er i et format som det er vanskelig å jobbe videre med, så vi må først gjøre en del endringer for å få den i et format som PHP kjapt og lett kan søke i ved hvert besøk på sidene dine.

  1. Vi vil gjerne ha den inn i MySQL for å lettere kunne hente ut det vi trenger. Du trenger tilgang på en MySQL server med en database du kan skrive til. Når du har det, kan du kjøre følgende SQL-syntaks for å opprette tabellen du trenger:
    CREATE TABLE `the_database` (
    `IP_FROM` double NOT NULL default ’0′,
    `IP_TO` double NOT NULL default ’0′,
    `COUNTRY_CODE2` char(2) NOT NULL default ”,
    `COUNTRY_CODE3` char(3) NOT NULL default ”,
    `COUNTRY_NAME` varchar(50) NOT NULL default ”
    ) TYPE=MyISAM;

  2. Så vil vi gjerne importere dataene i CSV-filen inn i MySQL(bytt ut /tmp/ip.csv med der du pakket ut filen):

    LOAD DATA INFILE ‘/tmp/ip.csv’ INTO TABLE the_database FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘rn’;

  3. Dette skulle putte alle dataene i CSV-filen fint inn i databasen du laget med koden over. Dette kunne vi brukt til å søke i MySQL hver gang en side lastes, men det er ganske ineffektivt, og folkene på php.net kom på noe lurt. For å bruke deres måte å søke på må dataene legges i en fil i formatet med et slikt felt per linje (og alle IP-adresser må være 10 karakterer, fylt ut med 0-er hvis de er for korte). Det vil se ut noe slikt som dette:
    00339963440033996351GBR
    00503316480083886079USA
    00945854240094585439SWE
    01006632960121195295USA

    For å få ut dataene fra MySQL i dette formatet, kan du kjøre dette for å eksportere det til /tmp/ip-to-country.db (bytt det ut med der du vil lagre filen):

    SELECT CONCAT(
    LPAD(IP_FROM,10,’0′),
    LPAD(IP_TO,10,’0′),
    COUNTRY_CODE3)
    INTO OUTFILE ‘/tmp/ip-to-country.db’
    FIELDS TERMINATED BY ”
    LINES TERMINATED BY ‘n’
    FROM `the_database`
    WHERE 1;

  4. Denne filen må indekseres så den kan søkes gjennom raskere. Jeg har hentet koden for å gjøre det fra php.net og modifisert den en del. Den er ganske lang så jeg har ikke inkludert den her i ren tekst, men koden du trenger å kjøre for å indeksere filen er her:

    http://mortencb.cx/php/country_app1.phps. På toppen der definerer du hvor du har db-filen din, og hvor du vil ha idx-filen. Når du har kjørt det en gang, skal du ha en idx-fil i tillegg til db-filen.

  5. Hva gjør vi med disse lurer du kanskje på? PHP.net har brukt de til å distribuere trafikken sin til en server i det landet du kommer fra, men uansett hva du vil må du ha noe kode som søker gjennom db/idx-filene og finner landet. Jeg har modifisert noe kode php.net bruker, og du kan se det hele her (har ikke inkludert det her siden det er så langt):

    http://mortencb.cx/php/country_app2.phps. Alt du trenger å gjøre er å inkludere de to filene på websidene dine, og kalle funksjonen i2c_go(). Det vil lage en global variabel $COUNTRY med 3-karakters landskoden (RFC3166).

  6. Den igjen kan du bruke til å gjøre ulike ting med. For eksempel vise flagget til den som besøker siden. Da ville det jo vært greit å ha flaggene ferdig i formatet nor.png eller lignende. Jeg har funnet en nesten like god løsning her; http://www.hahn-hotel.com/flags/ gir nemlig ut flaggene gratis i 2karakter-formatet, og det er jo nesten like bra. Men vi trenger litt ekstra kode for å konvertere fra 3 til 2 karakterer. Du kan kjøre dette SQL-kallet for å få ut en grei liste med 2 og 3 karakterer fra det vi la inn lenger oppe:
    CREATE TEMPORARY TABLE temp
    SELECT DISTINCT(COUNTRY_CODE3) as C2,
    COUNTRY_CODE2 as C3
    FROM the_database;
    SELECT CONCAT(‘”‘,C3,’” => “‘,C2,’” ,’)
    INTO OUTFILE ‘/tmp/country.db’
    FIELDS TERMINATED BY ”
    LINES TERMINATED BY ‘n’
    FROM `temp`
    WHERE 1;

    Dette lager en liste som du kan legge inn følgende på toppen: <? $COUNTRIES = array( og følgende på slutten av filen: );?>. Det vil gi deg en fil noe ala dette:

    <? $COUNTRIES = array( “GB” => “GBR” , “US” => “USA” , … “AG” => “ATG” , “DM” => “DMA” ); ?>

  7. Så trenger vi bare en funksjon som henter ut den motsatte landskoden fra den vi har (2 hvis vi har 3 og omvendt):

    <?
    function convert_country_thingy ( $country ) {
        require( “country.db” );
        if( strlen ( $country ) == 3 ) $COUNTRIES = array_flip ( $COUNTRIES );
        if(isset( $COUNTRIES [ $country ])) return $COUNTRIES [ $country ];
        else return “NA” ;
    }
    ?>

  8. Nå er vi i mål. For å vise riktig flagg på den som besøker siden din kan du hvis du har lastet all koden inn i en fil (for eksempel ip-to-country.php) samt har de to country.db/idx-filene gjøre følgende:

    <?
    require( “country_app2.phps” );
    require( “country_app3.phps” );
    i2c_go ();
    if( $COUNTRY != “NA” ) {
        echo “You are logged on from: ” .
    “<A HREF=”http://mortencb.cx/php/country.php”>” .
    “<IMG SRC=”/pics/flags/world 25x15px/” .
    strtolower ( convert_country_thingy ( $COUNTRY )).
    “.png ” ALT= ” $COUNTRY ” ></A>” ;
    }
    else echo “You are from a country unknown to the IP-database.” ;
    ?>

Oppsummering

Håper dette var nyttig og at det ikke var altfor vanskelig. Har du spørsmål skal jeg prøve å svare på de så godt som mulig. Alt som står her står forøvrig også på mine egne websider.