首先说几个坑:
- 我们之前获取IP的方式
private static function clientIp(){
return getenv('HTTP_CLIENT_IP')?:
getenv('HTTP_X_FORWARDED_FOR')?:
getenv('HTTP_X_FORWARDED')?:
getenv('HTTP_FORWARDED_FOR')?:
getenv('HTTP_FORWARDED')?:
getenv('REMOTE_ADDR');
}
现在修改为:
private static function clientIp(){
return
getenv('REMOTE_ADDR')?:
getenv('HTTP_CLIENT_IP')?:
getenv('HTTP_X_FORWARDED_FOR')?:
getenv('HTTP_X_FORWARDED')?:
getenv('HTTP_FORWARDED_FOR')?:
getenv('HTTP_FORWARDED');
}
坑一:HTTP_CLIENT_IP 是代理服务器发送的HTTP头.可以随意伪造!
$_SERVER['HTTP_CLIENT_IP']
HTTP_CLIENT_IP 是代理服务器发送的HTTP头.可以随意伪造!
eg:
curl -H 'client-ip: 8.8.8.8' http://api.local.com/index.php
通过getenv('HTTP_CLIENT_IP') 获取到IP 8.8.8.8
REMOTE_ADDR不可以显式的伪造,虽然可以通过代理将ip地址隐藏,但是这个地址仍然具有参考价值,因为它就是与你的服务器实际连接的ip地址。
坑二:关于IPV4和IPV6
对于服务端来说,可以有IPV4的地址和IPV6的地址。
当客户端连接服务端时,只能使用一种协议去向服务端请求,不会同时使用IPV4和IPV6。当使用IPV4访问时,获取到IPV4的地址,如果使用IPV6访问时获取到IPV6的地址。
如果要使用IPV4地址,必须在服务端DNS上禁用IPV6支持,这样所有客户端必须使用IPV4作为唯一可用的协议。
参考:https://stackoverflow.com/questions/51245053/how-can-i-get-both-ipv4-and-ipv6-address-using-php-code
坑三验证是IPV4还是IPV6
很多人用strpos( $ip , ":")用来确定是否识别出IPv6地址或substr_count( $ip , ".") == 3验证IPv4地址。
但是不是100%准确;例如 ::127.0.0.1或的地址::ffff:10.10.1.1
可以使用:
if( filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ){
// Yes it's valid IPv4
}
if( filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ){
// Yes it's valid IPv6
}
IPV6转换。。。。后面再研究这个……如果想存数据库,至少用varchar(30)来存储
https://www.mikemackintosh.com/5-tips-for-working-with-ipv6-in-php/#comment-12521
inet_pton和inet_pton
dtr_pton dtr_ntop
查询服务端是否支持IPV6 ,过审苹果的包也要求有ipv6地址的哦~
方法一:http://ipv6-test.com/validate.php
http://www.test-ipv6.com/
方法二:windows 下执行: nslookup www.baidu.com 2001开头的是IPv6, 218开头的是IPv4
在mac上执行: dig +nocmd + nostats
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190221210250233.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIxMjk2MDc=,size_16,color_FFFFFF,t_70)
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 28706
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
检验方式:
Got answer 有个status:NO ERROR ,一般status是no error 就没问题。
有错的话对应下面的表:
附一张我本地测试图: