Usando GeoIP e Google Maps – Parte 2

Saudações pessoal.

Como eu havia dito, vou tentar compartilhar com vocês mais algumas coisas sobre a utilização do GeoIP e do Google Maps.

Sem enrolação hoje, vamos às novidades.



Google Maps Javascript API V3

Em 05/2009, o Google lançou oficialmente a nova versão do Google Maps API, agora denominada Google Maps Javascript API V3 (versão 3). A grande diferença dessa versão para as anteriores, é que seu código foi melhor estruturado, para ser mais leve, mais eficiente, ser executado em dispositivos móveis com mais facilidade, além de ter incluído algumas novas funcionalidades, como o suporte ao padrão de geolocalização W3C, que, em resumo, permitem, com código javascript, acessar informações sobre localização em um dispositivo que possua GPS, como os smartphones de hoje em dia.

Mas, de modo prático, o que muda pra gente? Primeiro, que não precisamos mais daquela chatice de “chave de API” e, segundo, que a versão 2 “tem previsão de remoção”: ou seja, daqui a pouco, os códigos que utilizam a versão 2 do Google Maps API deixarão de funcionar. Mas, não se alarmem: como o próprio Google disse, a utilização da nova API é muito semelhante a anterior. Vejam esse tutorial completo sobre como começar a usar a versão 3 do Google Maps API, e vamos para o próximo item.

MaxMind GeoIP: novas APIs

Recentemente, recebi um comentário sobre uma dúvida na utilização da API para PHP do GeoIP. Mas eu realmente não lembrava de existir essa API quando criei o primeiro post sobre esse assunto. Realmente, utilizar aqueles pacotes PEAR é muito chato, além de ser mais complicado. Diante disso, fui até o site da MaxMind, na parte de APIs, e verifique que realmente existem várias APIs novinhas, e mais fáceis de ser utilizadas. Então, vou tentar mostrar aqui duas delas: a API para PHP puro, e a API para JavaScript.

GeoIP PHP API

Existem três maneiras de se usar o GeoIP utilizando o PHP como base. Uma, a gente já mostrou no post anterior, que é utilizando o pacote PEAR NetGeoIP. Outra maneira é utilizando um “mod” pro Apache, o mod_geoip. A terceira maneira é utilizando PHP puro, como o próprio site chama.

Existem duas diferenças básicas entre usar uma ou outra abordagem: a facilidade de uso e o desempenho, sendo que utilizando o PHP puro é o jeito mais fácil e rápido de implementar uma solução GeoIP, enquanto utilizar o mod_geoip é a maneira mais trabalhosa, mas que gera o resultando mais eficiente. Neste post, iremos usar o PHP puro.

Como vimos antes, a primeira coisa a se fazer é baixar a base de dados e colocá-la no seu servidor web. Neste caso, estamos utilizando a base de dados gratuita GeoLite City, que contém informações a nível de cidades. Após terminar de baixar, basta descompactar e fazer o upload para algum diretório do seu servidor web (veja lá no final desse post como fazer isso de uma maneira bem mais prática). No meu caso, utilizei o diretório /home/interpossi/geoip/, dessa forma, toda vez que eu precisar do base de dados, basta eu informar o caminho /home/interpossi/geoip/GeoLiteCity.dat. Você pode utilizar qualquer diretório, desde que lembre dele depois. 😛 Um dica é não criar esse diretório dentro de /public_html, para não torná-lo público. Duvido que alguém irá querer acessar a base dessa maneira, mas…

Agora, é necessário baixar os arquivos da API. Para o nosso exemplo, iremos precisar apenas dos seguintes arquivos:

Agora é só fazer nosso arquivo de teste, que, devido a minha suprema criatividade, chamei de teste.php. Veja como ficou o código:

<?php

include("geoipcity.inc");
include("geoipregionvars.php");

//base de dados
$base = geoip_open("/home/interpos/geoip/GeoLiteCity.dat",GEOIP_STANDARD);

//pega um registro de localizacao baseado no IP do cliente (REMOTE_ADDR)
$localizacao = geoip_record_by_addr($base,$_SERVER["REMOTE_ADDR"]);

//fecha o arquivo (pra economizar memoria)
geoip_close($base);

//imprime na tela as informacoes obtidas

?>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <style type="text/css">
      table { padding: 3px; }
      th { border: 2px outset #C0C0C0; padding: 3px; text-align: right;}
      td { border: 2px outset #C0C0C0; padding: 3px; text-align: left;}
    </style>
  </head>
  <body>
    <h1>Seu IP sugere que esta seja sua localização:</h1>
    <?
    echo "<table><tr>";
    echo "<th>Codigo do Continente: </th><td>" . $localizacao->continent_code . "</td></tr><tr>";
    echo "<th>Codigo do pais: </th><td>" . $localizacao->country_code . "</td></tr><tr>";
    echo "<th>Codigo do pais com 3 letras: </th><td>" . $localizacao->country_code3 . "</td></tr><tr>";
    echo "<th>Nome do pais: </th><td>" . $localizacao->country_name . "</td></tr><tr>";
    echo "<th>Codigo do estado: </th><td>" . $localizacao->region . "</td></tr><tr>";
    echo "<th>Nome do estado: </th><td>" . $GEOIP_REGION_NAME[$localizacao->country_code][$localizacao->region] . "</td></tr><tr>";
    echo "<th>Nome da cidade: </th><td>" . $localizacao->city . "</td></tr><tr>";
    echo "<th>Latitude: </th><td>" . $localizacao->latitude . "</td></tr><tr>";
    echo "<th>Longitude: </th><td>" . $localizacao->longitude . "</td></tr>";
    echo "</table>";
    ?>
    <h2><a href="#">Retornar para o artigo</a></h2>
  </body>
</html>

Veja esse código em ação.

Para utilizarmos essa nova abordagem com o Google Maps é muito simples, basta usar os atributos “latitude e longitude” no código JavaScript do mapa. Vejam o código-fonte. Ele fala por si só (assim espero. Qualquer dúvida, postem comentários…).

<?php

include("geoipcity.inc");
include("geoipregionvars.php");

//base de dados
$base = geoip_open("/home/interpos/geoip/GeoLiteCity.dat",GEOIP_STANDARD);

//pega um registro de localizacao baseado no IP do cliente (REMOTE_ADDR)
$localizacao = geoip_record_by_addr($base,$_SERVER["REMOTE_ADDR"]);

//fecha o arquivo (mas os dados continuam em $localizacao
geoip_close($base);
?>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <!-- tamanho do viewport: mais utilizado em dispositivos moveis -->
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    <style type="text/css">
      #map_canvas{
        width:640px;
        height:480px;
        margin: 10px;
        border: 1px solid black;
      }
    </style>

    <!-- sensor=false : indicado para dizer se o dispositivo possui ou nao sensor GPS -->
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    
    <script type="text/javascript">
    function initialize() {
      var latlng = new google.maps.LatLng(<? echo $localizacao->latitude; ?>, <? echo $localizacao->longitude; ?>);
      var options = {
        zoom: 6,
        center: latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
      var map = new google.maps.Map(document.getElementById("map_canvas"), options);
      var marker = new google.maps.Marker({
        position: latlng, 
        map: map,
        title:"Seu IP sugere que você esteja por aqui"
      });   

    }
    </script>
  </head>
  <body onload="initialize()">
    <h1>Seu IP sugere que esta seja sua localização:</h1>
    <div id="map_canvas"></div>
    <h2><a href="#">Retornar para o artigo</a></h2>
  </body>
</html>

Veja esse código em ação.

Tranquilinho né? Vamos ao próximo, e sem dúvida, mais interessante.

GeoIP JavaScript API

Um outra API que encontrei no site da MaxMind foi essa: bibliotecas GeoIP para JavaScript.

Eu, particularmente, me dou muito bem com o JavaScript. Então, a ideia de poder usar o GeoIP direto no código JS já me pareceu boa. Além disso, o uso da API do JavaScript permite a você utilizar a base de dados “paga” da MaxMind. Sim! Teoricamente, você teria resultados mais precisos. A única imposição deles é que você deixe um link pro site da MaxMind na página em que utilizar o JS deles (ou pague a licensa de 250 dólares por ano). (Mais ainda, com um pouco de criatividade, praticamente qualquer linguagem que possa fazer uma requisição HTTP consegue ter acesso ao GeoIP, bastando pra isso, recuperar as informações desse link, e claro, exibindo o “linkzinho” da MaxMind);

Então, como fazemos pra usar? Simples, no seu “código” html (html é código? não né.. linguagem de marcação) inclua o script deles:

<script language="JavaScript" src="http://j.maxmind.com/app/geoip.js"></script>

E depois é só chamar os métodos, como o geoip_latitude() e geoip_longitude(). Veja um código de exemplo:

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <!-- tamanho do viewport: mais utilizado em dispositivos moveis -->
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    <style type="text/css">
      #map_canvas{
        width:640px;
        height:480px;
        margin: 10px;
        border: 1px solid black;
      }
    </style>
  
    <!-- funcoes (se eh que podem ser chamadas assim) geoip -->  
    <script language="JavaScript" src="http://j.maxmind.com/app/geoip.js"></script>

    <!-- sensor=false : indicado para dizer se o dispositivo possui ou nao sensor GPS -->
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    
    <script type="text/javascript">
    function initialize() {
      var latlng = new google.maps.LatLng(geoip_latitude(), geoip_longitude());
      var options = {
        zoom: 9,
        center: latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
      var map = new google.maps.Map(document.getElementById("map_canvas"), options);
      var marker = new google.maps.Marker({
        position: latlng, 
        map: map,
        title:"Seu IP sugere que você esteja em "+geoip_city()+" - "+geoip_region_name()
      });   

    }
    </script>
  </head>
  <body onload="initialize()">
    <h1>Seu IP sugere que esta seja sua localização:</h1>
    <div id="map_canvas"></div>
    <h2><a href="#">Retornar para o artigo</a></h2>
  </body>
</html>


Veja esse código em ação.

Notem que as únicas coisas a se fazer é incluir a biblioteca JS e chamar suas duas funções geoip_latitude()geoip_longitude(), enviando seus resultados diretamente pro código do Google Maps.

Comparem a localização estimada da versão PHP com a versão JS: qual foi mais preciso pra vocês?

Dica bonus: baixar e atualizar a base de dados GeoIP

Essa dica é simplesmente um script PHP para baixar a base de dados diretamente para o servidor, evitando que você tenha que baixar para o seu computador e depois fazer upload pro servidor, etc.

O script é simples, e para usá-lo você só precisa baixar o arquivo updateDB.php, configurá-lo colocando o diretório do seu servidor para o qual você deseja que ele baixe a base de dados, e fazer o upload do arquivo modificado para o seu servidor. Depois é só acessar esse arquivo pelo seu navegador que o script será executado, a base de dados será baixada no local especificado, e ainda será descompactada. Só lembrando, no meu caso, o diretório que utilizo é o /home/interpossi/geoip/, então o meu código vai estar configurado para este diretório.

Veja o código do script:

<?php

  /* ALTERE ESSE VARIAVEL PARA O DIRETORIO NO SEU SERVIDOR ONDE DEVERA FICAR A BASE DE DADOS GEOIP */
  $dir = '/home/interpossi/geoip/';


  /* VOCE NAO PRECISA ALTERAR NADA DAQUI EM DIANTE */
  $file_source = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz';
  $file_target = $dir."GeoLiteCity.dat.gz";
  $file_decompressed = $dir."GeoLiteCity.dat";
  
  @set_time_limit(180);

  /* baixando o arquivo */

  $rh = fopen($file_source, 'rb') or die('download_file '. __('error: reading or opening file', 'visitor-maps'));
  $wh = fopen($file_target, 'wb') or die('download_file '. __('error: cannot write to file, check server permission settings', 'visitor-maps'));

  $counter = 0;
  $megs  = 1;
  $every = 1024;
  while (!feof($rh)) {
    if (($counter % $every) == 0) {
      echo '('.$megs.')';
      $megs++;
    }
    if (fwrite($wh, fread($rh, 1024)) === FALSE) {
      die('download_file '. __('error: cannot write to file, check server permission settings', 'visitor-maps'));
      return true;
    }
    $counter++;
  }
  fclose($rh);
  fclose($wh);

  /* descompactando */

  $sfp = gzopen($file_target, "rb");
  $fp = fopen($file_decompressed, "w");

  while ($string = gzread($sfp, 4096)) {
    fwrite($fp, $string, strlen($string));
  }

  gzclose($sfp);
  fclose($fp);

?>

Preste atenção: a variável que você precisa modificar é a $dir. Siga o exemplo, não deixando de terminar o caminho do diretório com /.

Conclusões finais

Bom, espero que seja útil pra vocês, e para a Rosemeire, que me chamou atenção para essas novas APIs.

Se alguém tiver alguma dúvida, alguma sugestão, compartilhem através dos comentários.

E até a próxima.

Sobre maverick