ip.init.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <?php
  2. defined('IS_INITPHP') || die('Access Denied!');
  3. /**
  4. * 扩展类库-IP助手
  5. *
  6. * @version 0.1.0
  7. * @author Anran <id0612@gmail.com>
  8. */
  9. class IpInit {
  10. /**
  11. * IP-获取用户IP
  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 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
  23. $realip = $_SERVER['HTTP_CLIENT_IP'];
  24. } else {
  25. $realip = $_SERVER['REMOTE_ADDR'];
  26. }
  27. } else {
  28. if (getenv('HTTP_X_FORWARDED_FOR')) {
  29. $realip = getenv('HTTP_X_FORWARDED_FOR');
  30. } else if (getenv('HTTP_CLIENT_IP')) {
  31. $realip = getenv('HTTP_CLIENT_IP');
  32. } else {
  33. $realip = getenv('REMOTE_ADDR');
  34. }
  35. }
  36. // 处理多层代理的情况
  37. if (false !== strpos($realip, ',')) {
  38. $realip = reset(explode(',', $realip));
  39. }
  40. // IP地址合法验证
  41. $realip = filter_var($realip, FILTER_VALIDATE_IP, null);
  42. if (false === $realip) {
  43. return '0.0.0.0'; // unknown
  44. }
  45. return $realip;
  46. }
  47. /**
  48. * 检查IP是否在指定的网络范围内
  49. *
  50. * 1. 网络范围表示方法:
  51. * 通配符: 1.2.3.*
  52. * CIDR值: 1.2.3.0/24 或 1.2.3.4/255.255.255.0
  53. * IP段: 1.2.3.0-1.2.3.255
  54. * 2. 仅支持IPv4。
  55. * 3. 考虑到目前实用性不高,而且随着PHP本身的发展,将来或许会有更好的解决方案,
  56. * 暂时先不发布支持IPv6的版本,有兴趣的同学可联系我进一步交流或者自行研究。
  57. * 4. 实现IPv6的支持,需要至少32位无符号整数进行位运算,而PHP只支持32位有符号整数,
  58. * 可以使用float类型突破这个限制,但float类型不支持位运算,这是需要解决的首要问题。
  59. * @param string $ip IP地址
  60. * @param string $range 网络范围
  61. * @return boolean
  62. */
  63. public function ip_in_range($ip, $range) {
  64. if (strpos($range, '/') !== false) {
  65. // CIDR值
  66. list($range, $netmask) = explode('/', $range, 2);
  67. if (strpos($netmask, '.') !== false) {
  68. $netmask = str_replace('*', '0', $netmask);
  69. $netmask_dec = ip2long($netmask);
  70. return ((ip2long($ip) & $netmask_dec) === (ip2long($range) & $netmask_dec));
  71. } else {
  72. $x = explode('.', $range);
  73. while (count($x) < 4) {
  74. $x[] = '0';
  75. }
  76. list($a, $b, $c, $d) = $x;
  77. $range = sprintf('%u.%u.%u.%u', empty($a) ? '0' : $a, empty($b) ? '0' : $b, empty($c) ? '0' : $c, empty($d) ? '0' : $d);
  78. $range_dec = ip2long($range);
  79. $ip_dec = ip2long($ip);
  80. $wildcard_dec = pow(2, (32 - $netmask)) - 1;
  81. $netmask_dec = ~ $wildcard_dec;
  82. return (($ip_dec & $netmask_dec) === ($range_dec & $netmask_dec));
  83. }
  84. } else {
  85. // 通配符格式,转换为IP段进行判断
  86. if (strpos($range, '*') !== false) {
  87. $lower = str_replace('*', '0', $range);
  88. $upper = str_replace('*', '255', $range);
  89. $range = "{$lower}-{$upper}";
  90. }
  91. // IP段
  92. if (strpos($range, '-') !== false) {
  93. list($lower, $upper) = explode('-', $range, 2);
  94. $lower_dec = (float) sprintf('%u', ip2long($lower));
  95. $upper_dec = (float) sprintf('%u', ip2long($upper));
  96. $ip_dec = (float) sprintf('%u', ip2long($ip));
  97. return (($ip_dec >= $lower_dec) && ($ip_dec <= $upper_dec));
  98. }
  99. // 网络范围格式不正确,返回false
  100. return false;
  101. }
  102. }
  103. }