ip.init.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * 扩展类库-IP助手
  4. *
  5. * @version 0.1.0
  6. * @author Anran
  7. */
  8. class IpInit {
  9. /**
  10. * IP-获取用户IP
  11. *
  12. * @return string
  13. */
  14. public function get_ip() {
  15. static $realip = null;
  16. if (null !== $realip) {
  17. return $realip;
  18. }
  19. if (isset($_SERVER)) {
  20. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  21. $realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  22. } else
  23. if (isset($_SERVER['HTTP_CLIENT_IP'])) {
  24. $realip = $_SERVER['HTTP_CLIENT_IP'];
  25. } else {
  26. $realip = $_SERVER['REMOTE_ADDR'];
  27. }
  28. } else {
  29. if (getenv('HTTP_X_FORWARDED_FOR')) {
  30. $realip = getenv('HTTP_X_FORWARDED_FOR');
  31. } else
  32. if (getenv('HTTP_CLIENT_IP')) {
  33. $realip = getenv('HTTP_CLIENT_IP');
  34. } else {
  35. $realip = getenv('REMOTE_ADDR');
  36. }
  37. }
  38. // 处理多层代理的情况
  39. if (false !== strpos($realip, ',')) {
  40. $realip = reset(explode(',', $realip));
  41. }
  42. // IP地址合法验证
  43. $realip = filter_var($realip, FILTER_VALIDATE_IP, null);
  44. if (false === $realip) {
  45. return '0.0.0.0'; // unknown
  46. }
  47. return $realip;
  48. }
  49. /**
  50. * 检查IP是否在指定的网络范围内
  51. *
  52. * 1. 网络范围表示方法:
  53. * 通配符: 1.2.3.*
  54. * CIDR值: 1.2.3.0/24 或 1.2.3.4/255.255.255.0
  55. * IP段: 1.2.3.0-1.2.3.255
  56. * 2. 仅支持IPv4。
  57. * 3. 考虑到目前实用性不高,而且随着PHP本身的发展,将来或许会有更好的解决方案,
  58. * 暂时先不发布支持IPv6的版本,有兴趣的同学可联系我进一步交流或者自行研究。
  59. * 4. 实现IPv6的支持,需要至少32位无符号整数进行位运算,而PHP只支持32位有符号整数,
  60. * 可以使用float类型突破这个限制,但float类型不支持位运算,这是需要解决的首要问题。
  61. *
  62. * @param string $ip
  63. * IP地址
  64. * @param string $range
  65. * 网络范围
  66. * @return boolean
  67. */
  68. public function ip_in_range($ip, $range) {
  69. if (strpos($range, '/') !== false) {
  70. // CIDR值
  71. list ($range, $netmask) = explode('/', $range, 2);
  72. if (strpos($netmask, '.') !== false) {
  73. $netmask = str_replace('*', '0', $netmask);
  74. $netmask_dec = ip2long($netmask);
  75. return ((ip2long($ip) & $netmask_dec) === (ip2long($range) & $netmask_dec));
  76. } else {
  77. $x = explode('.', $range);
  78. while (count($x) < 4) {
  79. $x[] = '0';
  80. }
  81. list ($a, $b, $c, $d) = $x;
  82. $range = sprintf('%u.%u.%u.%u', empty($a) ? '0' : $a, empty($b) ? '0' : $b, empty($c) ? '0' : $c, empty($d) ? '0' : $d);
  83. $range_dec = ip2long($range);
  84. $ip_dec = ip2long($ip);
  85. $wildcard_dec = pow(2, (32 - $netmask)) - 1;
  86. $netmask_dec = ~ $wildcard_dec;
  87. return (($ip_dec & $netmask_dec) === ($range_dec & $netmask_dec));
  88. }
  89. } else {
  90. // 通配符格式,转换为IP段进行判断
  91. if (strpos($range, '*') !== false) {
  92. $lower = str_replace('*', '0', $range);
  93. $upper = str_replace('*', '255', $range);
  94. $range = "{$lower}-{$upper}";
  95. }
  96. // IP段
  97. if (strpos($range, '-') !== false) {
  98. list ($lower, $upper) = explode('-', $range, 2);
  99. $lower_dec = (float) sprintf('%u', ip2long($lower));
  100. $upper_dec = (float) sprintf('%u', ip2long($upper));
  101. $ip_dec = (float) sprintf('%u', ip2long($ip));
  102. return (($ip_dec >= $lower_dec) && ($ip_dec <= $upper_dec));
  103. }
  104. // 网络范围格式不正确,返回false
  105. return false;
  106. }
  107. }
  108. /**
  109. * 将ipv4的地址转换为无符号整型
  110. * @param string $ip
  111. * @return interger
  112. */
  113. public function ipv4ToInt($ip)
  114. {
  115. $arr = explode('.', $ip);
  116. return $arr[0] * pow(256, 3) + $arr[1] * pow(256, 2) + $arr[2] * 256 + $arr[3];
  117. }
  118. /**
  119. * 将无符号整型转换为ipv4的地址
  120. * 超过2100000000有符号整型限制时,取模计算会出现问题。乘除不会。
  121. * @param int $int
  122. * @return string
  123. */
  124. public function intToIpv4($int)
  125. {
  126. $arr = array();
  127. for ($i = 0; $i < 4; $i++) {
  128. $arr[$i] = intval($int / pow(256, 3 - $i));
  129. $int = $int - $arr[$i] * pow(256, 3 - $i);
  130. }
  131. return implode('.', $arr);
  132. }
  133. /**
  134. * 是否合法的IP
  135. *
  136. * @param string $ip
  137. * @return bool
  138. */
  139. public function isIp($ip)
  140. {
  141. return preg_match('/^\d+\.\d+\.\d+\.\d+$/', $ip);
  142. }
  143. }