PHP轉換IP地址到真實地址的方法詳解

原文章地址:http://www.jb51.net/article/38231.htm

想要把IPv4地址轉為真實的地址,肯定要參考IP數據庫酷含,商業(yè)的IP數據庫存儲在關系型數據庫中邦泄,查詢和使用都非常方便这难,但是成本不是個人和小公 司愿意承受的仔燕,所以簡單應用的思路就是利用一些免費的IP數據庫或者一些大網站提供的查詢API造垛,他們的數據量足夠我們使用了。

1. 利用純真IP數據庫利用本地的QQWry.Dat文件晰搀,優(yōu)點是查詢速度非澄辶桑快,缺點是數據庫文件要放在自己的空間內并且要偶爾更新數據庫外恕。時間關系廢話不多說杆逗,下面是 使用這個文件的函數,如果是在WordPress里面使用這個功能鳞疲,把下面的代碼寫入主題下面的functions.php里面罪郊,然后在 comments-list的輸出即可;如果是其他程序引用尚洽,輸入一個有效的IPv4地址就可以得到一個真實的地址悔橄。

復制代碼代碼如下:

function convertip($ip) {

//IP數據文件路徑

$dat_path = 'QQWry.Dat';

//檢查IP地址

//if(!preg_match("/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/", $ip)) {

//??? return 'IP Address Error';

//}

//打開IP數據文件

if(!$fd = @fopen($dat_path, 'rb')){

return 'IP date file not exists or access denied';

}

//分解IP進行運算,得出整形數

$ip = explode('.', $ip);

$ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];

//獲取IP數據索引開始和結束位置

$DataBegin = fread($fd, 4);

$DataEnd = fread($fd, 4);

$ipbegin = implode('', unpack('L', $DataBegin));

if($ipbegin < 0) $ipbegin += pow(2, 32);

$ipend = implode('', unpack('L', $DataEnd));

if($ipend < 0) $ipend += pow(2, 32);

$ipAllNum = ($ipend - $ipbegin) / 7 + 1;

$BeginNum = 0;

$EndNum = $ipAllNum;

//使用二分查找法從索引記錄中搜索匹配的IP記錄

while($ip1num>$ipNum || $ip2num<$ipNum) {

$Middle= intval(($EndNum + $BeginNum) / 2);

//偏移指針到索引位置讀取4個字節(jié)

fseek($fd, $ipbegin + 7 * $Middle);

$ipData1 = fread($fd, 4);

if(strlen($ipData1) < 4) {

fclose($fd);

return 'System Error';

}

//提取出來的數據轉換成長整形翎朱,如果數據是負數則加上2的32次冪

$ip1num = implode('', unpack('L', $ipData1));

if($ip1num < 0) $ip1num += pow(2, 32);

//提取的長整型數大于我們IP地址則修改結束位置進行下一次循環(huán)

if($ip1num > $ipNum) {

$EndNum = $Middle;

continue;

}

//取完上一個索引后取下一個索引

$DataSeek = fread($fd, 3);

if(strlen($DataSeek) < 3) {

fclose($fd);

return 'System Error';

}

$DataSeek = implode('', unpack('L', $DataSeek.chr(0)));

fseek($fd, $DataSeek);

$ipData2 = fread($fd, 4);

if(strlen($ipData2) < 4) {

fclose($fd);

return 'System Error';

}

$ip2num = implode('', unpack('L', $ipData2));

if($ip2num < 0) $ip2num += pow(2, 32);

//沒找到提示未知

if($ip2num < $ipNum) {

if($Middle == $BeginNum) {

fclose($fd);

return 'Unknown';

}

$BeginNum = $Middle;

}

}

$ipFlag = fread($fd, 1);

if($ipFlag == chr(1)) {

$ipSeek = fread($fd, 3);

if(strlen($ipSeek) < 3) {

fclose($fd);

return 'System Error';

}

$ipSeek = implode('', unpack('L', $ipSeek.chr(0)));

fseek($fd, $ipSeek);

$ipFlag = fread($fd, 1);

}

if($ipFlag == chr(2)) {

$AddrSeek = fread($fd, 3);

if(strlen($AddrSeek) < 3) {

fclose($fd);

return 'System Error';

}

$ipFlag = fread($fd, 1);

if($ipFlag == chr(2)) {

$AddrSeek2 = fread($fd, 3);

if(strlen($AddrSeek2) < 3) {

fclose($fd);

return 'System Error';

}

$AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));

fseek($fd, $AddrSeek2);

} else {

fseek($fd, -1, SEEK_CUR);

}

while(($char = fread($fd, 1)) != chr(0))

$ipAddr2 .= $char;

$AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));

fseek($fd, $AddrSeek);

while(($char = fread($fd, 1)) != chr(0))

$ipAddr1 .= $char;

} else {

fseek($fd, -1, SEEK_CUR);

while(($char = fread($fd, 1)) != chr(0))

$ipAddr1 .= $char;

$ipFlag = fread($fd, 1);

if($ipFlag == chr(2)) {

$AddrSeek2 = fread($fd, 3);

if(strlen($AddrSeek2) < 3) {

fclose($fd);

return 'System Error';

}

$AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));

fseek($fd, $AddrSeek2);

} else {

fseek($fd, -1, SEEK_CUR);

}

while(($char = fread($fd, 1)) != chr(0)){

$ipAddr2 .= $char;

}

}

fclose($fd);

//最后做相應的替換操作后返回結果

if(preg_match('/http/i', $ipAddr2)) {

$ipAddr2 = '';

}

$ipaddr = "$ipAddr1 $ipAddr2";

$ipaddr = preg_replace('/CZ88.Net/is', '', $ipaddr);

$ipaddr = preg_replace('/^s*/is', '', $ipaddr);

$ipaddr = preg_replace('/s*$/is', '', $ipaddr);

if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {

$ipaddr = 'Unknown';

}

$ipaddr = iconv('gbk', 'utf-8//IGNORE', $ipaddr); //轉換編碼橄维,如果網頁的gbk可以刪除此行

return $ipaddr;

}

2. 利用門戶網站的接口目前已知的有騰訊尺铣、新浪拴曲、網易、搜狐和Google提供IP地址查詢API凛忿,但是找得到的只有騰訊澈灼、新浪和網易的,Google的貌似要用 Google Maps所以沒有研究∪郏看了下國內的幾個騰訊提供的是JavaScript的委乌,網易提供的是XML,而新浪的有多種格式可以用荣回,注意非XML的數據源都是 GBK格式的遭贸,不管是JavaScript調用還是PHP調用都要轉換一下編碼,不然得到的是亂碼心软。而更需要注意的是壕吹,如果一次性查詢多個IP,使用門戶 網站的API來查詢會非常緩慢删铃,我大概寫了個for循環(huán)試了下耳贬,不管是用PHP解析XML還是file_get_contents()函數獲取內容,查詢 10次以上會變得非常緩慢猎唁,甚至可能超時咒劲。

騰訊的IP地址API接口地址:http://fw.qq.com/ipaddress,返回的是數據格式為:var IPData = new Array("123.124.2.85","","北京市","");诫隅,一個JavaScript的對象腐魂,目前還不知道如何輸入IP查詢。

新浪的IP地址查詢接口:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js

新浪多地域測試方法:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=123.124.2.85

網易有道的IP地址查詢接口:http://www.youdao.com/smartresult-xml/search.s?type=ip&q=123.124.2.85

//騰訊API的PHP調用方法

復制代碼代碼如下:

function getIpPlace(){

$ip=file_get_contents("http://fw.qq.com/ipaddress");

$ip=str_replace('"',' ',$ip);

$ip2=explode("(",$ip);

$a=substr($ip2[1],0,-2);

$b=explode(",",$a);

return $b;

}

$ip=getIpPlace();

print_r($ip);

//有道API的PHP調用方法

復制代碼代碼如下:

$url = "http:www.youdao.com/smartresult-xml/search.s?type=ip&q=".$ip;

$doc = new DOMDocument();

$doc->load($url);

$smartresult = $doc->getElementsByTagName("product");

foreach($smartresult as $product)

{

$locations = $product->getElementsByTagName("location");

$location = $locations->item(0)->nodeValue;

}

if($location != "")

{

echo $i.".".$ip;

echo "? 來自".$location."的網友";

}

else

{

echo $i.".".$ip;

echo "? 來自火星的網友";

}

public function sinaIPApi($ip){

$str = file_get_contents("http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=".$ip);

$str = iconv("gbk", "utf-8//IGNORE", $str);

preg_match_all("/[/x{4e00}-/x{9fa5}]+/u",$str,$get);

$add = implode('',$get[0]);

return $add;

}

//$get是一個非常棒的二維數組

其中有道和新浪的是我自己寫的逐纬,新浪API也可以像騰訊API那樣用file_get_contents()函數獲取完地址后使用一連串的字符串函 數處理挤渔,我寫的函數使用正則表達式從新浪的返回結果中提供包含中文的字符串,并且分段存入一個二維數組风题,這個可能只是針對新浪的API有用并且存在 bug判导。舉個例子查詢學校分配給我的IP地址后var_dump()一下函數里面的$get變量得到以下結果: array(1) { [0]=> array(6) { [0]=> string(6) "中國" [1]=> string(6) "北京" [2]=> string(6) "北京" [3]=> string(9) "教育網" [4]=> string(6) "學校" [5]=> string(18) "中國地質大學" } },而函數輸出的結果則是“中國北京北京教育網學校中國地質大學”沛硅,希望我的思路和方法能對別人有用眼刃。

最后再次提醒,如果是WordPress請使用第一種方法摇肌,否則使用API同時查詢所有留言者的真實地址會讓PHP超時的擂红,希望各路大牛有更好的方 法,至于限制顯示和顯示方式等神馬的都是WordPress應用問題围小,同時對于Java和C#來說思路也是一樣的昵骤,這些后續(xù)的問題等我考完試再細說。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末肯适,一起剝皮案震驚了整個濱河市变秦,隨后出現的幾起案子,更是在濱河造成了極大的恐慌框舔,老刑警劉巖蹦玫,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赎婚,死亡現場離奇詭異,居然都是意外死亡樱溉,警方通過查閱死者的電腦和手機挣输,發(fā)現死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來福贞,“玉大人撩嚼,你說我怎么就攤上這事⊥诹保” “怎么了绢馍?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肠套。 經常有香客問我舰涌,道長,這世上最難降的妖魔是什么你稚? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任瓷耙,我火速辦了婚禮,結果婚禮上刁赖,老公的妹妹穿的比我還像新娘搁痛。我一直安慰自己,他們只是感情好宇弛,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布鸡典。 她就那樣靜靜地躺著,像睡著了一般枪芒。 火紅的嫁衣襯著肌膚如雪彻况。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天舅踪,我揣著相機與錄音纽甘,去河邊找鬼。 笑死抽碌,一個胖子當著我的面吹牛悍赢,可吹牛的內容都是我干的。 我是一名探鬼主播货徙,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼左权,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痴颊?” 一聲冷哼從身側響起赏迟,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祷舀,沒想到半個月后瀑梗,有當地人在樹林里發(fā)現了一具尸體烹笔,經...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡裳扯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年抛丽,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饰豺。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡亿鲜,死狀恐怖,靈堂內的尸體忽然破棺而出冤吨,到底是詐尸還是另有隱情蒿柳,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布漩蟆,位于F島的核電站垒探,受9級特大地震影響,放射性物質發(fā)生泄漏怠李。R本人自食惡果不足惜圾叼,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捺癞。 院中可真熱鬧夷蚊,春花似錦、人聲如沸髓介。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唐础。三九已至箱歧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間一膨,已是汗流浹背叫胁。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留汞幢,地道東北人驼鹅。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像森篷,于是被迫代替她去往敵國和親兼吓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內容