Quantcast
Channel: 香港網頁開發網誌 » MaxMind
Viewing all articles
Browse latest Browse all 2

地理定位 (Geolocation):比你想像的容易

0
0

Jeremy Kendall 在 PHP Architecture 有一篇文章介紹怎樣使你的網站加入地理定位 (geolocation) 的功能,好處是可以根據訪客的身處的位置,提供適合的內容和語言,令他們享受更貼心的服務。加入這項功能比你想像的容易,甚至完全免費,Jeremy 提供了兩個解決方案,任何一個都可以在十分鐘內搞定。

Jeremy 說,地理定位屬於一個完全解決了的問題,很多人提供了解決方案,我們沒有必要自行編寫這項功能,他介紹了兩個免費的應用程式界面 (API),一個是 Maxmind 的 GeoLite API,另一個是 Quova

GeoLite

GeoLite 的確有些獨特,他們的服務是免費的的,無須登記,他們提供了數據庫下載。這意味著數據存放在你自己的網站上,並利用他們提供的 PHP 函式庫來存取數據庫。

以下的步驟讓 GeoLite 在你的網頁應用程序中運行:

  • 下載 GeoLiteCity 數據庫
  • 把數據庫解壓在你的網頁應用程序中一個可讀取的子目錄
  • 安裝 PEAR GeoLite 函式庫( pear install Net_GeoIP
  • 編程!

你需要編寫的程式可說簡單得無法置信,下面是 Jeremy 測試用的程式:

$geoip = Net_GeoIP::getInstance(dirname(__FILE__) . '/data/GeoLiteCity.dat');
$ipaddress = '72.30.2.43'; // Yahoo!
$location = $geoip->lookupLocation($ipaddress);
var_dump($location);

程式的輸出是這樣:

object(Net_GeoIP_Location)[2]
    protected 'aData' =>
        array
        'countryCode' => string 'US' (length=2)
        'countryCode3' => string 'USA' (length=3)
        'countryName' => string 'United States' (length=13)
        'region' => string 'CA' (length=2)
        'city' => string 'Sunnyvale' (length=9)
        'postalCode' => string '94089' (length=5)
        'latitude' => float 37.4249
        'longitude' => float -122.0074
        'areaCode' => int 408
        'dmaCode' => float 807

Net_GeoIP_Location 物件使用 __get()__set() 魔術成員函式,所以從這物件中檢索數據,只要編寫簡單的 $location->city;

Quova

GeoLite 的安裝和使用的確非常簡單,但為了有一個比較公道和全面的概念,Jeremy 找來另一個同樣是免費的 Quova 測試。

首先我們要申請一個免費的 Quova 開發者帳戶 ,並獲得 API 密鑰。Quova 有十分出色的文檔,Jeremy 在很短時間內便把它啟動和運作。很可惜,他們提供的 PHP 範例卻有點醜陋,Jeremy 花了數分鐘時間把它改寫得漂亮些:

/**
* Quova ipinfo API class
*
* @category Example
* @package Example_Quova
* @subpackage GeoIP
* @version $Id$
*/
/**
* Uses Quova's GeoIP API to get geographical location by IP address
*
* To obtain your Quova API key (apikey) and the shared secret
* that you need to build a digital signature, register your
* application at http://developer.quova.com/.
*
* @category Example
* @package Example_Quova
* @subpackage GeoIP
*/
class Example_Quova_GeoIP
{
/**
* Quova API key
*
* @var string
*/
private $_apiKey;
/**
* Quova shared secret
*
* @var string
*/
private $_secret;
/**
* Default URL for Quova's GeoIP service
*
* @var string
*/
private $_defaultService = 'http://api.quova.com/v1/ipinfo/';
/**
* Public constructor
*
* @param string $apiKey Quova API Key
* @param string $secret Quova shared secret
*/
public function __construct($apiKey, $secret)
{
$this->_apiKey = $apiKey;
$this->_secret = $secret;
}
/**
* Get geographical location of IP address from Quova's API
*
* @param string $ipaddress
* @param string $format json or XML
* @return string XML or json, depending on the value of $format
*/
public function getLocation($ipaddress, $format = 'json')
{
$ch = curl_init();
$parameters = array(
'apikey' => $this->_apiKey,
'sig' => $this->generateSig(),
'format' => $format
);
$url = $this->_defaultService
. $ipaddress
. '?'
. http_build_query($parameters);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
$headers = curl_getinfo($ch);
// Check headers here
curl_close($ch);
return $data;
}
/**
* Checks headers for response code and issues error message if necessary
*
* @param mixed $headers
*/
public function checkHeaders($headers)
{
// this is where I'd test HTTP response codes
}
/**
* Generates sig, an MD5 hash of the API key, the shared secret, and Unix timestamp
*
* @return string MD5 hash
*/
public function generateSig()
{
return md5($this->_apiKey . $this->_secret . gmdate('U'));
}
}

以下是調用 Quova API 的簡單例子:

$apikey = 'dummyApiKey';
$secret = 'dummySecret';
$ipaddress = '72.30.2.43'; // Yahoo!
$quova = new Example_Quova_GeoIp($apikey, $secret);
$location = json_decode($quova->getLocation($ipaddress));
var_dump($location);

這段程式的輸出如下:

object(stdClass)[4]
  public 'ipinfo' =>
    object(stdClass)[5]
      public 'ip_address' => string '72.30.2.43' (length=10)
      public 'ip_type' => string 'Mapped' (length=6)
      public 'Network' =>
        object(stdClass)[6]
          public 'organization' => string 'inktomi corporation' (length=19)
          public 'OrganizationData' =>
            object(stdClass)[7]
              public 'organization_type' => string 'Business Conglomerate' (length=21)
          public 'carrier' => string 'inktomi corporation' (length=19)
          public 'asn' => int 14777
          public 'connection_type' => string 'tx' (length=2)
          public 'line_speed' => string 'high' (length=4)
          public 'ip_routing_type' => string 'fixed' (length=5)
          public 'Domain' =>
            object(stdClass)[8]
              public 'tld' => string 'com' (length=3)
              public 'sld' => string 'yahoo' (length=5)
      public 'Location' =>
        object(stdClass)[9]
          public 'continent' => string 'north america' (length=13)
          public 'latitude' => float 37.33053
          public 'longitude' => float -121.83823
          public 'CountryData' =>
            object(stdClass)[10]
              public 'country' => string 'united states' (length=13)
              public 'country_code' => string 'us' (length=2)
              public 'country_cf' => int 99
          public 'region' => string 'southwest' (length=9)
          public 'StateData' =>
            object(stdClass)[11]
              public 'state' => string 'california' (length=10)
              public 'state_code' => string 'ca' (length=2)
              public 'state_cf' => int 94
          public 'dma' => int 807
          public 'msa' => int 41940
          public 'CityData' =>
            object(stdClass)[12]
              public 'city' => string 'san jose' (length=8)
              public 'postal_code' => string '95122' (length=5)
              public 'time_zone' => int -8
              public 'area_code' => string '408' (length=3)
              public 'city_cf' => int 90

調用 $location->ipinfo->Location->StateData->state_code; 送回兩個字母的美國州代號,太容易了!

陷阱

至於陷阱,也不是太多,比較大的問題是準確性。 免費地理定位數據集一般承諾的準確性大約是半徑 25 英里的範圍,而且不同的數據集也可能給出不同的答案。你會注意到在以上的例子中,同一個 IP 地址 GeoLite 和 Quova 便送回不同的城市和郵政編碼。 Jeremy 用他自己的 IP 地址 (密西西比州 Southaven 市) 測試,GeoLite 送回的地址是田納西州 Collierville 市,而 Quova 則認為在田納西州 Memphis 市。 這兩個城市都在25英里的準確性半徑內,但俱錯誤地報告州份。

結束語

要把地理定位功能添加到網頁應用程序嗎?你只需要 10 分鐘閒暇時間便足夠了。參照上面的例子,你可以毫不費力地啟動這項功能,你必須編寫的程式碼將是微乎其微的,相對於回報你投入的時間肯定是值得的。


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images