IP轉物理地址的原理

 

 

首先,IP對應的國家是比較好查的,ICANN及其它幾個機構都有關於某個IP段所屬國家和ISP信息,並且他們基本上都提供了免費查詢。但難題在 於每個洲的管理機構不同,且數據量龐大,不易收集。將IP對應到某個國家的某個ISP後還要了結到它是分配給哪個地區(城市)的,比如中國電信福建分公司 的IP段會分給廈門、福州等城市,而相對於這個就是比較難找了,可能ISP會有數據庫會提供查詢,可能也查不到,這些數據的來源就靠平時的積累、用戶的貢 獻了。

當然,現在許多出名的數據庫經過幾年的發展已經比較完整和詳細了,像免費的純真數據庫都有十幾萬條了,如過向國外的商業網站購買企業級應用的數據 庫,它的準確度就有點驚人了。國外的 ip2location.com 提供的數據庫就是如此,作爲一個英文數據庫,它除了對美國等地區的數據比較完整以外,甚至中國的數據的精確程度都不亞於國內的數據庫。它還提供了IP對應 的經緯度,如果搭配Google 提供的Google Earth 的API,就可以在網頁上看到Google Earth了。就保存的方法來看,一般有一個文件(如純真的QQwry.dat)或數據庫。在數據量龐大(如幾十萬條)的情況下,用文件保存明顯優於數據庫,這一點在後面會詳解。無論採用哪種方式保存數據,它的一般格式爲:起點IP,終點IP,國家,地區
33996344,33996351,United Kingdom,XXX某 些比較詳細的數據庫還有ISP,國家縮略名,對應郵編,甚至該地的經緯度!起點IP,終點IP不是我們常見的 XXX.XXX.XXX.XXX的形式,而是一個8-10位十進制數字構成的。這也是爲了便於數據的搜索。該數據由IP轉換而成,在PHP中有 ip2long() 函數可以轉換,自己也可以寫一個相同的函數function dottedquad2long($ip){
$ip_arr = split(‘\.’,$ip);
$iplong = (16777216 * $ip_arr[0]) + (65536 * $ip_arr[1]) + (256 * $ip_arr[2]) + $ip_arr[3];
return $iplong;
}在一個文件的數據庫中,通常每個數據間用某種間隔符間隔,當要查找一個IP如64.233.189.104,先將該IP轉化爲十進制數字 1089060200 ,再在文件中多次利用二分法查找該IP對應的區間,約通過10-20次查找,就可以準確地找到對應的位置了。另外一種利用數據庫保存數據的方法相比於文件的查找,PHP做的工作比較簡單,但交給MySQL做的任務就比較艱鉅了。現在一般的小型的數據庫(如我找到的只有國家信息的數據),都有十萬餘條。要在那麼多的數據庫中查找一個區間,使用的時間倒不如用文件查找來得快。
關於查找數據在數據庫和文件分別所用的時間我在上一篇文章中有提到過,一般來說用文件保存的數據查找速度明顯優於數據庫。接下來就是我的完整的IP查詢的方法了數據庫信息
數據庫 ip 中表 ipdata 裏面有:id
startipnum 起點IP數字 如:33996344
endipnum終點IP數字 如:33996351
areaslug 國家/地區縮寫 如:GB
area 國家全名 如: United Kingdom<?php//調用的圖片類型,默認gif
if($_GET['imgtype'] == ‘png’){
$imgtype = ‘png’;
}else{
$imgtype = ‘gif’;
}//分析請求(支持IP,主機查詢)
if(!$_GET['s']){
$ip = $_SERVER["REMOTE_ADDR"];//無請求,查詢訪問者的IP信息
}else{
$s = trim(strtolower($_GET['s']));//轉換爲小寫
if(ereg(‘[a-z]‘,$s) && substr($s ,-1,1) != ‘x’){
$ip = gethostbyname($s);//如果是主機,則轉換爲對應IP
}else{
if(substr($s ,-1,1) == ‘x’){
$ip = str_replace(‘x’,’0′,$s);//爲用戶隱私考慮,允許最後一位用英文字符x取代。
}else{
$ip = $s;
}
}
}
$ip = long2ip(ip2long($ip));
$sip = sprintf(‘%u’,ip2long($ip));
//再進一步分析整理出合法的IP地址,並轉換爲數字形式,便於在數據庫中查找
$sql = “SELECT * FROM `ipdata` WHERE $sip >= `startipnum` AND $sip <= `endipnum`”;
//組織SQL在數據庫中查找IP對應的區間
$link = mysql_connect(“localhost”, “root”, “”);
mysql_select_db(‘ip’, $link);
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
$return = $row;
}
//進行查詢,得出結果
if(!$return['areaslug'] || $return['areaslug'] == ‘-h’){//沒有結果或結果位置,返回問號的圖標
header(‘Content-type: p_w_picpath/png’);
readfile(‘icon/png/other.png’);
}else{//根據調用格式不同分別調用對應的圖標
if($imgtype == ‘png’){
header(‘Content-type: p_w_picpath/png’);
readfile(‘icon/png/’.strtolower($return['areaslug']).’.png’);
}else{
header(‘Content-type: p_w_picpath/gif’);
readfile(‘icon/gif/’.strtolower($return['areaslug']).’.gif’);
}
}?>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章