Ip.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. /**
  3. * Ip.php UTF-8
  4. * IP 地址处理
  5. *
  6. * @date : 2018/5/24 14:01
  7. *
  8. * @license 这不是一个自由软件,未经授权不许任何使用和传播。
  9. * @author : wuyonghong <wyh@huosdk.com>
  10. * @version : HUOSDK 8.0
  11. */
  12. namespace huolib\tool;
  13. class Ip {
  14. private static $ip = null;
  15. private static $fp = null;
  16. private static $offset = null;
  17. private static $index = null;
  18. private static $cached = array();
  19. public static function ins() {
  20. return new static();
  21. }
  22. /**
  23. * 获取IP归属地
  24. *
  25. * @param $ip
  26. *
  27. * @return string
  28. */
  29. public static function getIpHome($ip) {
  30. // TODO: wuyonghong 2018/5/24 获取IP归属地
  31. $_ip_location = self::find($ip);
  32. if (is_array($_ip_location)) {
  33. return implode($_ip_location, '|');
  34. }
  35. return '不明地址';
  36. }
  37. /**
  38. * IP转数字
  39. *
  40. * @param string $ip IP转数字
  41. *
  42. * @return int
  43. */
  44. public static function ipToLong($ip) {
  45. $_long = sprintf("%u", ip2long($ip));
  46. $_long = $_long ? $_long : 0;
  47. return $_long;
  48. }
  49. /**
  50. * IP转数字
  51. *
  52. * @param integer $long 数字转IP
  53. *
  54. * @return int|string
  55. */
  56. public static function longToIp($long = 0) {
  57. if (empty($long) || $long < 0) {
  58. return '0.0.0.0';
  59. }
  60. $_ip = long2ip($long);
  61. return $_ip;
  62. }
  63. /**
  64. * 判断是否是黑名单列表
  65. *
  66. * @param string $ip
  67. *
  68. * @return bool true 为黑名单 false 为不在黑名单中
  69. */
  70. public static function isBlackList($ip) {
  71. return false;
  72. }
  73. public static function find($ip) {
  74. if (empty($ip) === true) {
  75. return 'N/A';
  76. }
  77. $nip = gethostbyname($ip);
  78. $ipdot = explode('.', $nip);
  79. if ($ipdot[0] < 0 || $ipdot[0] > 255 || count($ipdot) !== 4) {
  80. return 'N/A';
  81. }
  82. if (isset(self::$cached[$nip]) === true) {
  83. return self::$cached[$nip];
  84. }
  85. if (self::$fp === null) {
  86. self::init();
  87. }
  88. $nip2 = pack('N', ip2long($nip));
  89. $tmp_offset = (int)$ipdot[0] * 4;
  90. $start = unpack(
  91. 'Vlen',
  92. self::$index[$tmp_offset].self::$index[$tmp_offset + 1].self::$index[$tmp_offset + 2]
  93. .self::$index[$tmp_offset + 3]
  94. );
  95. $index_offset = $index_length = null;
  96. $max_comp_len = self::$offset['len'] - 1024 - 4;
  97. for ($start = $start['len'] * 8 + 1024; $start < $max_comp_len; $start += 8) {
  98. if (self::$index{$start}.self::$index{$start + 1}.self::$index{$start + 2}.self::$index{$start + 3}
  99. >= $nip2
  100. ) {
  101. $index_offset = unpack(
  102. 'Vlen',
  103. self::$index{$start + 4}.self::$index{$start + 5}.self::$index{$start + 6}."\x0"
  104. );
  105. $index_length = unpack('Clen', self::$index{$start + 7});
  106. break;
  107. }
  108. }
  109. if ($index_offset === null) {
  110. return 'N/A';
  111. }
  112. fseek(self::$fp, self::$offset['len'] + $index_offset['len'] - 1024);
  113. $location = explode("\t", fread(self::$fp, $index_length['len']));
  114. $locationCode = self::getLocationCode($location);
  115. $location[] = $locationCode;
  116. self::$cached[$nip] = $location;
  117. return self::$cached[$nip];
  118. }
  119. private static function init() {
  120. if (self::$fp === null) {
  121. self::$ip = new self();
  122. $_file_path = GLOBAL_CONF_PATH.'extra/ip/17monipdb.dat';
  123. self::$fp = fopen($_file_path, 'rb');
  124. if (self::$fp === false) {
  125. throw new Exception('Invalid 17monipdb.dat file!');
  126. }
  127. self::$offset = unpack('Nlen', fread(self::$fp, 4));
  128. if (self::$offset['len'] < 4) {
  129. throw new Exception('Invalid 17monipdb.dat file!');
  130. }
  131. self::$index = fread(self::$fp, self::$offset['len'] - 4);
  132. }
  133. }
  134. private static function getLocationCode($arr) {
  135. $province = $arr[1];
  136. $city = $arr[2];
  137. $locationCode = [];
  138. $locationCode["北京"] = [
  139. "code" => "110000",
  140. "city" => [],
  141. ];
  142. $locationCode["天津"] = [
  143. "code" => "120000",
  144. "city" => [],
  145. ];
  146. $locationCode["河北"] = [
  147. "code" => "130000",
  148. "city" => ["石家庄市" => "130100", "唐山市" => "130200", "秦皇岛市" => "130300", "邯郸市" => "130400", "邢台市" => "130500",
  149. "保定市" => "130600", "张家口市" => "130700", "承德市" => "130800", "沧州市" => "130900", "廊坊市" => "131000",
  150. "衡水市" => "131100"],
  151. ];
  152. $locationCode["山西"] = [
  153. "code" => "140000",
  154. "city" => ["太原市" => "140100", "大同市" => "140200", "阳泉市" => "140300", "长治市" => "140400", "晋城市" => "140500",
  155. "朔州市" => "140600", "晋中市" => "140700", "运城市" => "140800", "忻州市" => "140900", "临汾市" => "141000",
  156. "吕梁市" => "141100"],
  157. ];
  158. $locationCode["内蒙古"] = [
  159. "code" => "150000",
  160. "city" => ["呼和浩特市" => "150100", "包头市" => "150200", "乌海市" => "150300", "赤峰市" => "150400", "通辽市" => "150500",
  161. "鄂尔多斯市" => "150600", "呼伦贝尔市" => "150700", "巴彦淖尔市" => "150800", "乌兰察布市" => "150900",
  162. "兴安盟" => "152200", "锡林郭勒盟" => "152500", "阿拉善盟" => "152900"],
  163. ];
  164. $locationCode["辽宁"] = [
  165. "code" => "210000",
  166. "city" => ["沈阳市" => "210100", "大连市" => "210200", "鞍山市" => "210300", "抚顺市" => "210400", "本溪市" => "210500",
  167. "丹东市" => "210600", "锦州市" => "210700", "营口市" => "210800", "阜新市" => "210900", "辽阳市" => "211000",
  168. "盘锦市" => "211100", "铁岭市" => "211200", "朝阳市" => "211300", "葫芦岛市" => "211400"],
  169. ];
  170. $locationCode["吉林"] = [
  171. "code" => "220000",
  172. "city" => ["长春市" => "220100", "吉林市" => "220200", "四平市" => "220300", "辽源市" => "220400", "通化市" => "220500",
  173. "白山市" => "220600", "松原市" => "220700", "白城市" => "220800", "延边朝鲜族自治州" => "222400"],
  174. ];
  175. $locationCode["黑龙江"] = [
  176. "code" => "230000",
  177. "city" => ["哈尔滨市" => "230100", "齐齐哈尔市" => "230200", "鸡西市" => "230300", "鹤岗市" => "230400",
  178. "双鸭山市" => "230500", "大庆市" => "230600", "伊春市" => "230700", "佳木斯市" => "230800", "七台河市" => "230900",
  179. "牡丹江市" => "231000", "黑河市" => "231100", "绥化市" => "231200", "大兴安岭地区" => "232700"],
  180. ];
  181. $locationCode["上海"] = [
  182. "code" => "310000",
  183. "city" => [],
  184. ];
  185. $locationCode["江苏"] = [
  186. "code" => "320000",
  187. "city" => ["南京市" => "320100", "无锡市" => "320200", "徐州市" => "320300", "常州市" => "320400", "苏州市" => "320500",
  188. "南通市" => "320600", "连云港市" => "320700", "淮安市" => "320800", "盐城市" => "320900", "扬州市" => "321000",
  189. "镇江市" => "321100", "泰州市" => "321200", "宿迁市" => "321300"],
  190. ];
  191. $locationCode["浙江"] = [
  192. "code" => "330000",
  193. "city" => ["杭州市" => "330100", "宁波市" => "330200", "温州市" => "330300", "嘉兴市" => "330400", "湖州市" => "330500",
  194. "绍兴市" => "330600", "金华市" => "330700", "衢州市" => "330800", "舟山市" => "330900", "台州市" => "331000",
  195. "丽水市" => "331100"],
  196. ];
  197. $locationCode["安徽"] = [
  198. "code" => "340000",
  199. "city" => ["合肥市" => "340100", "芜湖市" => "340200", "蚌埠市" => "340300", "淮南市" => "340400", "马鞍山市" => "340500",
  200. "淮北市" => "340600", "铜陵市" => "340700", "安庆市" => "340800", "黄山市" => "341000", "滁州市" => "341100",
  201. "阜阳市" => "341200", "宿州市" => "341300", "巢湖市" => "341400", "六安市" => "341500", "亳州市" => "341600",
  202. "池州市" => "341700", "宣城市" => "341800"],
  203. ];
  204. $locationCode["福建"] = [
  205. "code" => "350000",
  206. "city" => ["福州市" => "350100", "厦门市" => "350200", "莆田市" => "350300", "三明市" => "350400", "泉州市" => "350500",
  207. "漳州市" => "350600", "南平市" => "350700", "龙岩市" => "350800", "宁德市" => "350900"],
  208. ];
  209. $locationCode["江西"] = [
  210. "code" => "360000",
  211. "city" => ["南昌市" => "360100", "景德镇市" => "360200", "萍乡市" => "360300", "九江市" => "360400", "新余市" => "360500",
  212. "鹰潭市" => "360600", "赣州市" => "360700", "吉安市" => "360800", "宜春市" => "360900", "抚州市" => "361000",
  213. "上饶市" => "361100"],
  214. ];
  215. $locationCode["山东"] = [
  216. "code" => "370000",
  217. "city" => ["济南市" => "370100", "青岛市" => "370200", "淄博市" => "370300", "枣庄市" => "370400", "东营市" => "370500",
  218. "烟台市" => "370600", "潍坊市" => "370700", "济宁市" => "370800", "泰安市" => "370900", "威海市" => "371000",
  219. "日照市" => "371100", "莱芜市" => "371200", "临沂市" => "371300", "德州市" => "371400", "聊城市" => "371500",
  220. "滨州市" => "371600", "菏泽市" => "371700"],
  221. ];
  222. $locationCode["河南"] = [
  223. "code" => "410000",
  224. "city" => ["郑州市" => "410100", "开封市" => "410200", "洛阳市" => "410300", "平顶山市" => "410400", "安阳市" => "410500",
  225. "鹤壁市" => "410600", "新乡市" => "410700", "焦作市" => "410800", "濮阳市" => "410900", "许昌市" => "411000",
  226. "漯河市" => "411100", "三门峡市" => "411200", "南阳市" => "411300", "商丘市" => "411400", "信阳市" => "411500",
  227. "周口市" => "411600", "驻马店市" => "411700", "济源市" => "419001"],
  228. ];
  229. $locationCode["湖北"] = [
  230. "code" => "420000",
  231. "city" => ["武汉市" => "420100", "黄石市" => "420200", "十堰市" => "420300", "宜昌市" => "420500", "襄樊市" => "420600",
  232. "鄂州市" => "420700", "荆门市" => "420800", "孝感市" => "420900", "荆州市" => "421000", "黄冈市" => "421100",
  233. "咸宁市" => "421200", "随州市" => "421300", "恩施土家族苗族自治州" => "422800", "仙桃市" => "429004",
  234. "潜江市" => "429005", "天门市" => "429006", "神农架林区" => "429021"],
  235. ];
  236. $locationCode["湖南"] = [
  237. "code" => "430000",
  238. "city" => ["长沙市" => "430100", "株洲市" => "430200", "湘潭市" => "430300", "衡阳市" => "430400", "邵阳市" => "430500",
  239. "岳阳市" => "430600", "常德市" => "430700", "张家界市" => "430800", "益阳市" => "430900", "郴州市" => "431000",
  240. "永州市" => "431100", "怀化市" => "431200", "娄底市" => "431300", "湘西土家族苗族自治州" => "433100"],
  241. ];
  242. $locationCode["广东"] = [
  243. "code" => "440000",
  244. "city" => ["广州市" => "440100", "韶关市" => "440200", "深圳市" => "440300", "珠海市" => "440400", "汕头市" => "440500",
  245. "佛山市" => "440600", "江门市" => "440700", "湛江市" => "440800", "茂名市" => "440900", "肇庆市" => "441200",
  246. "惠州市" => "441300", "梅州市" => "441400", "汕尾市" => "441500", "河源市" => "441600", "阳江市" => "441700",
  247. "清远市" => "441800", "东莞市" => "441900", "中山市" => "442000", "潮州市" => "445100", "揭阳市" => "445200",
  248. "云浮市" => "445300"],
  249. ];
  250. $locationCode["广西"] = [
  251. "code" => "450000",
  252. "city" => ["南宁市" => "450100", "柳州市" => "450200", "桂林市" => "450300", "梧州市" => "450400", "北海市" => "450500",
  253. "防城港市" => "450600", "钦州市" => "450700", "贵港市" => "450800", "玉林市" => "450900", "百色市" => "451000",
  254. "贺州市" => "451100", "河池市" => "451200", "来宾市" => "451300", "崇左市" => "451400"],
  255. ];
  256. $locationCode["海南"] = [
  257. "code" => "460000",
  258. "city" => ["海口市" => "460100", "三亚市" => "460200", "五指山市" => "469001", "琼海市" => "469002",
  259. "儋州市" => "469003", "文昌市" => "469005", "万宁市" => "469006", "东方市" => "469007",
  260. "定安县" => "469021", "屯昌县" => "469022", "澄迈县" => "469023", "临高县" => "469024",
  261. "白沙黎族自治县" => "469025", "昌江黎族自治县" => "469026", "乐东黎族自治县" => "469027", "陵水黎族自治县" => "469028",
  262. "保亭黎族苗族自治县" => "469029", "琼中黎族苗族自治县" => "469030", "西沙群岛" => "469031", "南沙群岛" => "469032",
  263. "中沙群岛的岛礁及其海域" => "469033"],
  264. ];
  265. $locationCode["重庆"] = [
  266. "code" => "500000",
  267. "city" => [],
  268. ];
  269. $locationCode["四川"] = [
  270. "code" => "510000",
  271. "city" => ["成都市" => "510100", "自贡市" => "510300", "攀枝花市" => "510400", "泸州市" => "510500",
  272. "德阳市" => "510600", "绵阳市" => "510700", "广元市" => "510800", "遂宁市" => "510900",
  273. "内江市" => "511000", "乐山市" => "511100", "南充市" => "511300", "眉山市" => "511400",
  274. "宜宾市" => "511500", "广安市" => "511600", "达州市" => "511700", "雅安市" => "511800",
  275. "巴中市" => "511900", "资阳市" => "512000", "阿坝藏族羌族自治州" => "513200", "甘孜藏族自治州" => "513300",
  276. "凉山彝族自治州" => "513400"],
  277. ];
  278. $locationCode["贵州"] = [
  279. "code" => "520000",
  280. "city" => ["贵阳市" => "520100", "六盘水市" => "520200", "遵义市" => "520300", "安顺市" => "520400",
  281. "铜仁地区" => "522200", "黔西南布依族苗族自治州" => "522300", "毕节地区" => "522400",
  282. "黔东南苗族侗族自治州" => "522600", "黔南布依族苗族自治州" => "522700"],
  283. ];
  284. $locationCode["云南"] = [
  285. "code" => "530000",
  286. "city" => ["昆明市" => "530100", "曲靖市" => "530300", "玉溪市" => "530400", "保山市" => "530500",
  287. "昭通市" => "530600", "丽江市" => "530700", "普洱市" => "530800", "临沧市" => "530900",
  288. "楚雄彝族自治州" => "532300", "红河哈尼族彝族自治州" => "532500", "文山壮族苗族自治州" => "532600",
  289. "西双版纳傣族自治州" => "532800", "大理白族自治州" => "532900", "德宏傣族景颇族自治州" => "533100",
  290. "怒江傈僳族自治州" => "533300", "迪庆藏族自治州" => "533400"],
  291. ];
  292. $locationCode["西藏"] = [
  293. "code" => "540000",
  294. "city" => ["拉萨市" => "540100", "昌都地区" => "542100", "山南地区" => "542200", "日喀则地区" => "542300",
  295. "那曲地区" => "542400", "阿里地区" => "542500", "林芝地区" => "542600"],
  296. ];
  297. $locationCode["陕西"] = [
  298. "code" => "610000",
  299. "city" => ["西安市" => "610100", "铜川市" => "610200", "宝鸡市" => "610300", "咸阳市" => "610400", "渭南市" => "610500",
  300. "延安市" => "610600", "汉中市" => "610700", "榆林市" => "610800", "安康市" => "610900", "商洛市" => "611000"],
  301. ];
  302. $locationCode["甘肃"] = [
  303. "code" => "620000",
  304. "city" => ["兰州市" => "620100", "嘉峪关市" => "620200", "金昌市" => "620300", "白银市" => "620400", "天水市" => "620500",
  305. "武威市" => "620600", "张掖市" => "620700", "平凉市" => "620800", "酒泉市" => "620900", "庆阳市" => "621000",
  306. "定西市" => "621100", "陇南市" => "621200", "临夏回族自治州" => "622900", "甘南藏族自治州" => "623000"],
  307. ];
  308. $locationCode["青海"] = [
  309. "code" => "630000",
  310. "city" => ["西宁市" => "630100", "海东地区" => "632100", "海北藏族自治州" => "632200", "黄南藏族自治州" => "632300",
  311. "海南藏族自治州" => "632500", "果洛藏族自治州" => "632600", "玉树藏族自治州" => "632700", "海西蒙古族藏族自治州" => "632800"],
  312. ];
  313. $locationCode["宁夏"] = [
  314. "code" => "640000",
  315. "city" => ["银川市" => "640100", "石嘴山市" => "640200", "吴忠市" => "640300", "固原市" => "640400", "中卫市" => "640500"],
  316. ];
  317. $locationCode["新疆"] = [
  318. "code" => "650000",
  319. "city" => ["乌鲁木齐市" => "650100", "克拉玛依市" => "650200", "吐鲁番地区" => "652100", "哈密地区" => "652200",
  320. "昌吉回族自治州" => "652300", "博尔塔拉蒙古自治州" => "652700", "巴音郭楞蒙古自治州" => "652800", "阿克苏地区" => "652900",
  321. "克孜勒苏柯尔克孜自治州" => "653000", "喀什地区" => "653100", "和田地区" => "653200", "伊犁哈萨克自治州" => "654000",
  322. "塔城地区" => "654200", "阿勒泰地区" => "654300", "石河子市" => "659001", "阿拉尔市" => "659002",
  323. "图木舒克市" => "659003", "五家渠市" => "659004"],
  324. ];
  325. $code = "";
  326. if (!isset($locationCode[$province])) {
  327. return $code;
  328. }
  329. $code = $locationCode[$province]["code"];
  330. if (!empty($city)) {
  331. foreach ($locationCode[$province]["city"] as $key => $loc) {
  332. if (strpos($key, $city) !== false) {
  333. $code = $loc;
  334. break;
  335. }
  336. }
  337. }
  338. return $code;
  339. }
  340. public function __destruct() {
  341. if (self::$fp !== null) {
  342. fclose(self::$fp);
  343. }
  344. }
  345. }