php获取用户真实ip
PHP里获取用户IP,获户最常用的取用就是`$_SERVER['REMOTE_ADDR']`。但你要是获户直接拿它当真IP用,八成会翻车。取用我见过太多新手被这个坑得死去活来——明明用户在上海,获户后台看到的取用却是北京某云服务器的IP,因为中间隔了层CDN或者Nginx代理。获户 先说结论:没有百分百可靠的取用获取真实IP的方法,只能靠层层剥离代理头来“猜”。获户HTTP头里的取用`X-Forwarded-For`、`X-Real-IP`、获户`Client-IP`这些字段,取用全是获户客户端或者代理服务器自己填的,随手就能伪造。取用拿这些当真实IP,获户等于把大门敞开让人随便改。 那`REMOTE_ADDR`呢?它确实没法伪造,因为这是TCP连接层的IP,PHP直接从socket拿到的。但问题在于,只要你的服务器前面挂了任何一层代理(云负载均衡、CDN、Nginx反代),这个值就变成代理的IP了,对用户来说毫无意义。 我自己的处理逻辑很简单:先看服务器配置,再决定信任哪个头。比如公司内网部署,Nginx单独一层,那就在Nginx里用`set_real_ip_from`指定信任的代理IP段,然后把真实IP写进`X-Real-IP`。PHP这边直接读它就行——前提是Nginx配置对了,PHP才能信。 如果是云环境,比如阿里云SLB或腾讯云CLB,它们会往请求头里塞`X-Forwarded-For`,但格式是“客户端IP, 代理IP1, 代理IP2”。这时候得取第一个值,还得小心处理逗号。写代码时得先判断头存在不存在,再判断值是不是合法IP,最后用`array_shift`把第一个拎出来。 有个细节很多人忽略:`HTTP_X_FORWARDED_FOR`这个头如果直接暴露给PHP,用户自己发个请求带上`X-Forwarded-For: 1.2.3.4`,你的程序就会认为他来自1.2.3.4。所以更稳妥的做法是,在所有代理层把客户端传进来的这个头全部覆盖掉,只保留代理自己追加的。Nginx里用`proxy_set_header X-Forwarded-For $remote_addr;`就能做到。 还有个偏门情况——用户走IPv6。`REMOTE_ADDR`会返回类似`2001:db8::1`的地址,但有些老代码用`ip2long`处理,直接返回false,导致IP记录失败。你得用`inet_pton`或`filter_var`来兼容两种协议。 写个通用函数其实不难,但真没必要去网上抄那种几十行的“万能版”。我见过一个项目,代码里堆了五六个头检测,从`HTTP_CLIENT_IP`到`HTTP_X_FORWARDED_FOR`全查一遍,最后还失败。问题就出在它把信任边界搞混了——把用户可控的头和代理可信的头混在一起判断。 我的经验是:宁可少拿一个头,也别多信一个头。直接读`REMOTE_ADDR`是底线,如果确认有代理层,就只信任你配置过的那个代理IP来源。代码里写清楚注释,注明“这个头由Nginx统一注入,客户端无法修改”。这样后面接手的人至少不会踩坑。 最后提醒一句,IP这东西本来就是不可靠的。手机用户切WiFi和4G,IP一会儿一变。真要防刷票或者做风控,别把IP当唯一依据,配合User-Agent、Cookie、行为特征一起看才靠谱。别为了一个“真实IP”把自己绕进去,能拿到够用的就行。