ip_area.class.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * ip_area.class.php 根据ip地址获取ip所在地区的类
  4. *
  5. * @copyright (C) 2005-2010 PHPCMS
  6. * @license http://www.phpcms.cn/license/
  7. * @lastmodify 2010-6-7
  8. */
  9. class ip_area {
  10. public $fp = NULL; //定义文件指针
  11. public $func; //处理的方法
  12. private $offset;
  13. private $index;
  14. /**
  15. * 构造函数
  16. *
  17. */
  18. public function __construct() {
  19. if(@file_exists(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'mini.Dat')) {
  20. $this->func = 'data_mini';
  21. $this->fp = @fopen(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'mini.Dat', 'rb');
  22. $this->offset = unpack('Nlen', fread($this->fp, 4));
  23. $this->index = fread($this->fp, $this->offset['len'] - 4);
  24. } elseif(@file_exists(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'QQWry.Dat')) {
  25. $this->func = 'data_full';
  26. $this->fp = @fopen(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'QQWry.Dat', 'rb');
  27. } elseif(@file_exists(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'qqwry.dat')) {
  28. $this->func = 'data_full';
  29. $this->fp = @fopen(PC_PATH.DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'ipdata'.DIRECTORY_SEPARATOR.'qqwry.dat', 'rb');
  30. }
  31. }
  32. /**
  33. * 取得地区名
  34. * @param string $ip IP地址
  35. * @ return string/null
  36. */
  37. public function get($ip) {
  38. $return = '';
  39. if(preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip)) {
  40. $iparray = explode('.', $ip);
  41. if($iparray[0] == 10 || $iparray[0] == 127 || ($iparray[0] == 192 && $iparray[1] == 168) || ($iparray[0] == 172 && ($iparray[1] >= 16 && $iparray[1] <= 31))) {
  42. $return = 'LAN';
  43. } elseif($iparray[0] > 255 || $iparray[1] > 255 || $iparray[2] > 255 || $iparray[3] > 255) {
  44. $return = 'Invalid IP Address';
  45. } else {
  46. $return = $this->func ? $this->{$this->func}($ip) : '';
  47. if(strpos($return, ' ') !== false) $return = substr($return, 0, strpos($return,' '));
  48. }
  49. if(strtolower(pc_base::load_config('system', 'charset')) == 'utf-8') $return = iconv('gbk', 'utf-8', $return);
  50. }
  51. return $return;
  52. }
  53. /**
  54. * 通过外部接口方式获取详细地址信息
  55. * @return $localinfo province 省份 city城市 sp网络 提供商 pinyin拼音
  56. */
  57. public function getcitybyapi($ip) {
  58. $api_url = $localinfo = '';
  59. $xml = pc_base::load_sys_class('xml');
  60. pc_base::load_sys_func('iconv');
  61. $api_url = 'http://ipquery.sdo.com/getipinfo.php?ip='.$ip;
  62. $data = $xml->xml_unserialize(@file_get_contents($api_url));
  63. if (CHARSET == 'gbk') {
  64. $data = !empty($data) ? array_iconv($data, 'utf-8', 'gbk') : array();
  65. }
  66. if($data['ip']['result']) {
  67. $localinfo['province'] = $data['ip']['country'];
  68. $localinfo['city'] = $data['ip']['city'];
  69. $localinfo['sp'] = $data['ip']['sp'];
  70. //$name = strtolower(CHARSET) == 'gbk' ? $localinfo['city'] : iconv(CHARSET,'gbk',$localinfo['city']);
  71. $name = str_replace(L('city'),'',$localinfo['city']);
  72. $letters = gbk_to_pinyin($name);
  73. $localinfo['pinyin'] =strtolower(implode('', $letters));
  74. }
  75. return $localinfo;
  76. }
  77. /**
  78. *获取城市名称
  79. */
  80. public function getcity($ip) {
  81. $localinfo = '';
  82. $address = $this->get($ip);
  83. if(strpos($address,L('province'))!== false && strpos($address,L('city'))!== false){
  84. $address = explode(L('province'), $address);
  85. $address=$address[1];
  86. }
  87. $address = str_replace(L('city'),'',$address);
  88. $localinfo['city']= trim($address);
  89. $name = CHARSET == 'gbk' ? $localinfo['city'] : iconv('utf-8','gbk',$localinfo['city']);
  90. $name = str_replace(L('city'),'',$name);
  91. $letters = gbk_to_pinyin($name);
  92. $localinfo['pinyin'] =strtolower(implode('', $letters));
  93. return $localinfo;
  94. }
  95. /**
  96. * 使用mini.Dat ip数据包获取地区
  97. * @param string $ip IP地址
  98. * @ return string/null
  99. */
  100. private function data_mini($ip) {
  101. $ipdot = explode('.', $ip);
  102. $ipdot[0] = (int)$ipdot[0];
  103. $ipdot[1] = (int)$ipdot[1];
  104. $ip = pack('N', ip2long($ip));
  105. $length = $this->offset['len'] - 1028;
  106. $start = unpack('Vlen', $this->index[$ipdot[0] * 4] . $this->index[$ipdot[0] * 4 + 1] . $this->index[$ipdot[0] * 4 + 2] . $this->index[$ipdot[0] * 4 + 3]);
  107. for($start = $start['len'] * 8 + 1024; $start < $length; $start += 8) {
  108. if($this->index{$start} . $this->index{$start + 1} . $this->index{$start + 2} . $this->index{$start + 3} >= $ip) {
  109. $this->index_offset = unpack('Vlen', $this->index{$start + 4} . $this->index{$start + 5} . $this->index{$start + 6} . "\x0");
  110. $this->index_length = unpack('Clen', $this->index{$start + 7});
  111. break;
  112. }
  113. }
  114. fseek($this->fp, $this->offset['len'] + $this->index_offset['len'] - 1024);
  115. if($this->index_length['len']) {
  116. return str_replace('- ', '', fread($this->fp, $this->index_length['len']));
  117. } else {
  118. return 'Unknown';
  119. }
  120. }
  121. /**
  122. * 使用QQWry.Dat ip数据包获取地区
  123. * @param string $ip IP地址
  124. * @ return string/null
  125. */
  126. private function data_full($ip) {
  127. rewind($this->fp);
  128. $ip = explode('.', $ip);
  129. $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
  130. if(!($DataBegin = fread($this->fp, 4)) || !($DataEnd = fread($this->fp, 4)) ) return;
  131. @$ipbegin = implode('', unpack('L', $DataBegin));
  132. if($ipbegin < 0) $ipbegin += pow(2, 32);
  133. @$ipend = implode('', unpack('L', $DataEnd));
  134. if($ipend < 0) $ipend += pow(2, 32);
  135. $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
  136. $BeginNum = $ip2num = $ip1num = 0;
  137. $ipAddr1 = $ipAddr2 = '';
  138. $EndNum = $ipAllNum;
  139. while($ip1num > $ipNum || $ip2num < $ipNum) {
  140. $Middle= intval(($EndNum + $BeginNum) / 2);
  141. fseek($this->fp, $ipbegin + 7 * $Middle);
  142. $ipData1 = fread($this->fp, 4);
  143. if(strlen($ipData1) < 4) {
  144. fclose($this->fp);
  145. return 'System Error';
  146. }
  147. $ip1num = implode('', unpack('L', $ipData1));
  148. if($ip1num < 0) $ip1num += pow(2, 32);
  149. if($ip1num > $ipNum) {
  150. $EndNum = $Middle;
  151. continue;
  152. }
  153. $DataSeek = fread($this->fp, 3);
  154. if(strlen($DataSeek) < 3) {
  155. fclose($this->fp);
  156. return 'System Error';
  157. }
  158. $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
  159. fseek($this->fp, $DataSeek);
  160. $ipData2 = fread($this->fp, 4);
  161. if(strlen($ipData2) < 4) {
  162. fclose($this->fp);
  163. return 'System Error';
  164. }
  165. $ip2num = implode('', unpack('L', $ipData2));
  166. if($ip2num < 0) $ip2num += pow(2, 32);
  167. if($ip2num < $ipNum) {
  168. if($Middle == $BeginNum) {
  169. fclose($this->fp);
  170. return 'Unknown';
  171. }
  172. $BeginNum = $Middle;
  173. }
  174. }
  175. $ipFlag = fread($this->fp, 1);
  176. if($ipFlag == chr(1)) {
  177. $ipSeek = fread($this->fp, 3);
  178. if(strlen($ipSeek) < 3) {
  179. fclose($this->fp);
  180. return 'System Error';
  181. }
  182. $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
  183. fseek($this->fp, $ipSeek);
  184. $ipFlag = fread($this->fp, 1);
  185. }
  186. if($ipFlag == chr(2)) {
  187. $AddrSeek = fread($this->fp, 3);
  188. if(strlen($AddrSeek) < 3) {
  189. fclose($this->fp);
  190. return 'System Error';
  191. }
  192. $ipFlag = fread($this->fp, 1);
  193. if($ipFlag == chr(2)) {
  194. $AddrSeek2 = fread($this->fp, 3);
  195. if(strlen($AddrSeek2) < 3) {
  196. fclose($this->fp);
  197. return 'System Error';
  198. }
  199. $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
  200. fseek($this->fp, $AddrSeek2);
  201. } else {
  202. fseek($this->fp, -1, SEEK_CUR);
  203. }
  204. while(($char = fread($this->fp, 1)) != chr(0))
  205. $ipAddr2 .= $char;
  206. $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
  207. fseek($this->fp, $AddrSeek);
  208. while(($char = fread($this->fp, 1)) != chr(0))
  209. $ipAddr1 .= $char;
  210. } else {
  211. fseek($this->fp, -1, SEEK_CUR);
  212. while(($char = fread($this->fp, 1)) != chr(0))
  213. $ipAddr1 .= $char;
  214. $ipFlag = fread($this->fp, 1);
  215. if($ipFlag == chr(2)) {
  216. $AddrSeek2 = fread($this->fp, 3);
  217. if(strlen($AddrSeek2) < 3) {
  218. fclose($this->fp);
  219. return 'System Error';
  220. }
  221. $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
  222. fseek($this->fp, $AddrSeek2);
  223. } else {
  224. fseek($this->fp, -1, SEEK_CUR);
  225. }
  226. while(($char = fread($this->fp, 1)) != chr(0))
  227. $ipAddr2 .= $char;
  228. }
  229. if(preg_match('/http/i', $ipAddr2)) $ipAddr2 = '';
  230. $ipaddr = "$ipAddr1 $ipAddr2";
  231. $ipaddr = preg_replace('/CZ88\.NET/is', '', $ipaddr);
  232. $ipaddr = preg_replace('/^\s*/is', '', $ipaddr);
  233. $ipaddr = preg_replace('/\s*$/is', '', $ipaddr);
  234. if(preg_match('/http/i', $ipaddr) || $ipaddr == '') $ipaddr = 'Unknown';
  235. return ''.$ipaddr;
  236. }
  237. private function close() {
  238. @fclose($this->fp);
  239. }
  240. }
  241. ?>