24/11/2009

PHP identificar País de um IP

Muitas vezes temos necessidade de identificar o endereço Ip de um pedido ao nosso site ,pois bem este post pretende exemplificar uma aplicação simpes como isso poderá ser feito.
IP_Final Existem muitos serviços que permitem identificar o ip de forma gratuita bastando para isso utilizar os serviço que eles fornecem, o que pretendido neste post não é recorer a esses serviços mas sim criar o nosso proprio , por uma simples razão que não queremos estar dependentes inteiramente de outros que de um dia para o outro podem ficar offline e deteriorar em muito as velocidade do nosso site.Este post é baseado nos exemplos dos sites http://vincent.delau.nl  e http://bartomedia.blogspot.com .
Vou utilizar o ficheiro csv com a identificação dos paises e ips fornecido gratuitamente pela maxmind o GeoLite Country .


Ao fim de fazermos o download do ficheiro vamos importa-lo para uma base de dados MySql:
Passos:
  1. Criar a nossa base de dados
    CREATE DATABASE geoip;
    USE geoip;

  2. Criar as nossas tabelas

    O nosso ficheiro csv tem os seguintes dados :

    "62.28.91.200","62.28.255.255","1042045896","1042087935","PT","Portugal"
    "62.29.0.0","62.29.127.255","1042087936","1042120703","TR","Turkey"
    "62.29.128.0","62.29.255.255","1042120704","1042153471","PL","Poland"

    Como tal criamos a nossa tabela CSV para comtemplar todos os dados do ficheiro:

    CREATE TABLE csv (
    start_ip CHAR(15) NOT NULL,
    end_ip CHAR(15) NOT NULL,
    start INT UNSIGNED NOT NULL,
    end INT UNSIGNED NOT NULL,
    cc CHAR(2) NOT NULL,
    cn VARCHAR(50) NOT NULL
    );

    Esta tabela apenas vais servir para carregar os dados do csv pois tem muitos dados duplicado e poderá ser optimizada no fim deverá ser limpa .

    A optimização que vamos fazer é colocar os nomes dos países e as suas abreviaturas em apenas uma tabela e assim evitar a duplicação desses dados na
    tabela dos IP’s.

    CREATE TABLE cc (
    ci TINYINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    cc CHAR(2) NOT NULL,
    cn VARCHAR(50) NOT NULL
    );

    Outras das coisas que vamos fazer é guardar o ASCII do IP em vez da notação IP, uma vez que é mais leve e o php permite converter o Ip de forma simples para ASCII utilizando as funções ip2long() e long2ip().
    Logo a nossa tabela Ip vai ter a seguinte estrutura:

    CREATE TABLE ip (
    start INT UNSIGNED NOT NULL,
    end INT UNSIGNED NOT NULL,
    ci TINYINT UNSIGNED NOT NULL
    );
    

  3. Importar os dados para as nossas tabelas :

    Podemos importar o ficheiro csv por linha de comandos :
    mysqlimport --fields-terminated-by=","
    --fields-optionally-enclosed-by="\""
    --lines-terminated-by="\n"
    --host=<hostname>
    --user=<username>
    --password=<password>
    geoip csv.csv

    Ou se tiver o phpmyadmin poderá importa-lo facilmente selecionando a tabela  e a tab de Import onde deve seleccionando o ficheiro e nas opções deve colocar na opção ‘Campos terminados por’ ->,(Virgula) na opção Campos delimitados por colocar –> “ e ‘Campos delimitados por’ e ‘Linhas terminadas por’ colocar –> \n.

    dir_import import_csv_options

  4. Otimizar as tabelas e limpara tabela csv.
    Para optimizar as tabelas teremos de executar os seguintes comandos SQL :

    INSERT INTO cc SELECT DISTINCT NULL,cc,cn FROM csv;
    INSERT INTO ip SELECT start,end,ci FROM csv NATURAL JOIN cc;
    Truncate csv;  --> ‘Limpa’ a tabel csv.

  5. Criar o nossos ficheiros PHP para mostrar o país do IP do pedido.
Criamos o ficheiro para ir buscar dados:
function getALLfromIP($addr,$db) { 
  // this sprintf() wrapper is needed, because the PHP long is signed by default 
  $ipnum = sprintf("%u", ip2long($addr)); 
  $query = "SELECT cc, cn FROM ip NATURAL JOIN cc WHERE ${ipnum} BETWEEN start AND end"; 
  $result = mysql_query($query, $db); 
  if((! $result) or mysql_numrows($result) < 1) { 
    //exit("mysql_query returned nothing: ".(mysql_error()?mysql_error():$query)); 
    return false; 
  } 
  return mysql_fetch_array($result); 
} 
function getCCfromIP($addr,$db) { 
  $data = getALLfromIP($addr,$db); 
  if($data) return $data['cc']; 
    return false; 
} 
function getCOUNTRYfromIP($addr,$db) { 
  $data = getALLfromIP($addr,$db); 
  if($data) return $data['cn']; 
    return false; 
} 
function getCCfromNAME($name,$db) { 
  $addr = gethostbyname($name); 
  return getCCfromIP($addr,$db); 
} 
function getCOUNTRYfromNAME($name,$db) { 
  $addr = gethostbyname($name); 
  return getCOUNTRYfromIP($addr,$db); 
} 
Para mostrar os dados , não se esqueça de substituir o USERNAME e PASSWORD pelos seus dados de acesso a base de dados geoip criada ,
se quiser mostrar também a bandeira do pais pode fazer download gratuito de bandeiras no site http://www.ip2location.com/flagsoftheworld.aspx colocar na pasta do servidor ,findo isto já podera conhecer o pais de um determinado ip com bandeira :
require('geoip.inc.php'); 
$db = mysql_connect("localhost","USERNAME","PASSWORD") or die ("mysql_connect() failed: " . mysql_error());  mysql_select_db("geoip",$db) or die ("mysql_select_db() failed: " . mysql_error()); 
$remote = $_SERVER['REMOTE_ADDR'];  $cc=getCCfromIP($remote,$db);  echo "<p>".$cc."</p>\n";  $patch="flags/".$cc.".gif";  if(file_exists($patch))      echo "<img src=\"".$patch."\"/>";  echo "<p>".getCOUNTRYfromIP($remote,$db)."</p>\n"; 
Pode fazer o download do exemplo e da base de dados :

Sem comentários: