IP.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. namespace App\Components;
  3. use Exception;
  4. use GeoIp2\Database\Reader;
  5. use GeoIp2\Exception\AddressNotFoundException;
  6. use GuzzleHttp\Client;
  7. use IP2Location\Database;
  8. use Ip2Region;
  9. use ipip\db\City;
  10. use Log;
  11. use MaxMind\Db\Reader\InvalidDatabaseException;
  12. class IP
  13. {
  14. // 获取IP地址信息
  15. public static function getIPInfo($ip)
  16. {
  17. // IPv6 推荐使用ip.sb
  18. if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
  19. Log::info('识别到IPv6,尝试解析:'.$ip);
  20. $ipInfo = self::IPSB($ip);
  21. } else {
  22. $ipInfo = self::ip2Region($ip);
  23. if (!$ipInfo) {
  24. Log::info('无法识别,尝试使用【IPIP库】库解析:'.$ip);
  25. $ipInfo = self::ip2Location($ip);
  26. }
  27. }
  28. return $ipInfo;
  29. }
  30. // 通过api.ip.sb查询IP地址的详细信息
  31. public static function IPSB($ip)
  32. {
  33. $request = (new Client(['timeout' => 15]))->get('https://api.ip.sb/geoip/'.$ip);
  34. $message = json_decode($request->getBody(), true);
  35. if ($request->getStatusCode() === 200) {
  36. return $message;
  37. }
  38. Log::error('解析IPv6异常:'.$ip.PHP_EOL.var_export($request, true));
  39. return false;
  40. }
  41. // 通过ip2Region查询IP地址的详细信息 ← 聚合 淘宝IP库,GeoIP,纯真IP库
  42. public static function ip2Region(string $ip)
  43. {
  44. $ipInfo = false;
  45. try {
  46. $ipInfo = (new Ip2Region())->memorySearch($ip);
  47. } catch (Exception $e) {
  48. Log::error('【淘宝IP库】错误信息:'.$e->getMessage());
  49. }
  50. if ($ipInfo) {
  51. $location = explode("|", $ipInfo['region']);
  52. return [
  53. 'country' => $location[0] ?: '',
  54. 'province' => $location[2] ?: '',
  55. 'city' => $location[3] ?: '',
  56. ];
  57. }
  58. return $ipInfo;
  59. }
  60. //// 通过ip2Location查询IP地址的详细信息
  61. public static function ip2Location(string $ip)
  62. {
  63. $filePath = database_path('IP2LOCATION-LITE-DB3.IPV6.BIN');
  64. try {
  65. $location = (new Database($filePath, Database::FILE_IO))
  66. ->lookup($ip, [Database::CITY_NAME, Database::REGION_NAME, Database::COUNTRY_NAME,]);
  67. return [
  68. 'country' => $location['countryName'],
  69. 'province' => $location['regionName'],
  70. 'city' => $location['cityName'],
  71. ];
  72. } catch (Exception $e) {
  73. Log::error('【ip2Location】错误信息:'.$e->getMessage());
  74. }
  75. return false;
  76. }
  77. // 通过IPIP查询IP地址的详细信息
  78. public static function IPIP(string $ip): array
  79. {
  80. $filePath = database_path('ipip.ipdb');
  81. $location = (new City($filePath))->findMap($ip, 'CN');
  82. return [
  83. 'country' => $location['country_name'],
  84. 'province' => $location['region_name'],
  85. 'city' => $location['city_name'],
  86. ];
  87. }
  88. // 通过ip.taobao.com查询IP地址的详细信息
  89. public static function TaoBao(string $ip)
  90. {
  91. // 依据 http://ip.taobao.com/instructions 开发
  92. $request = (new Client(['timeout' => 15]))->get('http://ip.taobao.com/outGetIpInfo?ip='.$ip.'&accessKey=alibaba-inc');
  93. $message = json_decode($request->getBody(), true);
  94. if ($request->getStatusCode() === 200) {
  95. if ($message['code'] === 0) {
  96. return [
  97. 'country' => $message['data']['country'] === "XX" ? '' : $message['data']['country'],
  98. 'province' => $message['data']['region'] === "XX" ? '' : $message['data']['region'],
  99. 'city' => $message['data']['city'] === "XX" ? '' : $message['data']['city'],
  100. ];
  101. }
  102. Log::error('【淘宝IP库】返回错误信息:'.$ip.PHP_EOL.var_export($message['msg'], true));
  103. } else {
  104. Log::error('【淘宝IP库】解析异常:'.$ip.PHP_EOL.var_export($request, true));
  105. }
  106. return false;
  107. }
  108. // 通过api.map.baidu.com查询IP地址的详细信息
  109. public static function Baidu(string $ip)
  110. {
  111. if (!env('BAIDU_APP_AK')) {
  112. Log::error('【百度IP库】AK信息缺失');
  113. return false;
  114. }
  115. // 依据 http://lbsyun.baidu.com/index.php?title=webapi/ip-api 开发
  116. $request = (new Client(['timeout' => 15]))->get('https://api.map.baidu.com/location/ip?ak='.env('BAIDU_APP_AK').'&'.$ip.'&coor=bd09ll');
  117. $message = json_decode($request->getBody(), true);
  118. if ($request->getStatusCode() === 200) {
  119. if ($message['status'] === 0) {
  120. return [
  121. 'country' => $message['content']['address_detail']['country'],
  122. 'province' => $message['content']['address_detail']['province'],
  123. 'city' => $message['content']['address_detail']['city'],
  124. ];
  125. }
  126. Log::error('【百度IP库】返回错误信息:'.$ip.PHP_EOL.var_export($message['message'], true));
  127. } else {
  128. Log::error('【百度IP库】解析异常:'.$ip.PHP_EOL.var_export($request, true));
  129. }
  130. return false;
  131. }
  132. // 通过GeoIP2查询IP地址的详细信息
  133. public static function GeoIP2(string $ip)
  134. {
  135. $filePath = database_path('maxmind.mmdb');
  136. try {
  137. $location = (new Reader($filePath))->city($ip);
  138. return [
  139. 'country' => $location->country->names['zh-CN'],
  140. 'province' => '',
  141. 'city' => $location->city->name ?? '',
  142. ];
  143. } catch (AddressNotFoundException $e) {
  144. Log::error('【GeoIP2】查询失败:'.$ip);
  145. } catch (InvalidDatabaseException $e) {
  146. Log::error('【GeoIP2】数据库无效:'.$ip);
  147. }
  148. return false;
  149. }
  150. // 获取访客真实IP
  151. public static function getClientIP()
  152. {
  153. /*
  154. * 访问时用localhost访问的,读出来的是“::1”是正常情况
  155. * ::1说明开启了IPv6支持,这是IPv6下的本地回环地址的表示
  156. * 使用IPv4地址访问或者关闭IPv6支持都可以不显示这个
  157. */
  158. if (isset($_SERVER)) {
  159. if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
  160. $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
  161. $ip = $_SERVER['REMOTE_ADDR'];
  162. } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  163. $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  164. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  165. $ip = $_SERVER['HTTP_CLIENT_IP'];
  166. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  167. $ip = $_SERVER['REMOTE_ADDR'];
  168. } else {
  169. $ip = 'unknown';
  170. }
  171. } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
  172. $ip = getenv('HTTP_X_FORWARDED_FOR');
  173. } elseif (getenv('HTTP_CLIENT_IP')) {
  174. $ip = getenv('HTTP_CLIENT_IP');
  175. } else {
  176. $ip = getenv('REMOTE_ADDR');
  177. }
  178. if (trim($ip) === '::1') {
  179. $ip = '127.0.0.1';
  180. }
  181. return $ip;
  182. }
  183. }