zoukankan      html  css  js  c++  java
  • php中获取用户登陆的IP地址以及常规处理

    本文为原创,转载请注明!   

      在我们开发多站点业务网站中,经常需要获取客户端的ip地址来给用户推荐其所在地址的信息的业务,用php获取客户端的ip地址,我们一般用到的PHP内置方法是$_SERVER['REMOTE_ADDR'].

    但是这个函数只能获取访问者本地连接中设置的IP,局域网网关出口的IP地址,如果访问者使用代理服务器,将不获取代理服务器的IP,而是获取访问者网关的真实IP。如果将这个函数应用到限IP访问的网页中,别人即使通过限IP访问段中的代理服务器,也不能访问该页面。 所以我们一般为了防止欺骗,采用下面的方法来获取:

    /**
     * 获取客户端IP地址
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param boolean $adv 是否进行高级模式获取(有可能被伪装) 
     * @return mixed
     */
    function get_client_ip($type = 0,$adv=false) {
        $type       =  $type ? 1 : 0;
        static $ip  =   NULL;
        if ($ip !== NULL) return $ip[$type];
        if($adv){//高级模式获取(防止伪装)
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                $pos    =   array_search('unknown',$arr);
                if(false !== $pos) unset($arr[$pos]);
                $ip     =   trim($arr[0]);
            }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
                $ip     =   $_SERVER['HTTP_CLIENT_IP'];
            }elseif (isset($_SERVER['REMOTE_ADDR'])) {
                $ip     =   $_SERVER['REMOTE_ADDR'];
            }
        }elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip     =   $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u",ip2long($ip));
        $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];


    代码中用到了两个php内置函数 sprintf()和ip2long(),下面这这两个函数讲解下:
    如何将四个字段以点分开的IP网络址协议地址转换成整数呢?PHP里有这么一个函数ip2long.比如
    <?php
    echo ip2long("10.2.1.3");
    ?>
    我们将得到
    167903491

    这是如何计算的?
    <?php
    function ip2int($ip){
        //我们先把ip分为四段,$ip1,$ip2,$ip3,$ip4
        list($ip1,$ip2,$ip3,$ip4)=explode(".",$ip);
        //然后第一段乘以256的三次方,第二段乘以256的平方,第三段乘以256
        //这即是我们得到的值
        return $ip1*pow(256,3)+$ip2*pow(256,2)+$ip3*256+$ip4;
    }
    ?>
    当ip地址比较大时,ip2long会出现负数:
    <?php
    $ip = '192.168.101.100';
    $ip_long = ip2long($ip);
    echo $ip_long.PHP_EOL;  // -1062705820
    echo long2ip($ip_long); // 192.168.101.100
    ?>

    这个是为什么呢?

    IPv4使用无符号32位地址,因此最多有2的32次方减1(4294967295)个地址。书写用4个小数点分开的10进制数。 
    记为A.B.C.D,例如:192.168.100.100。

    IPv4地址每个10进制数都是无符号的字节,范围在0~255,将IPv4地址转为无符号数,其实就是将每个10进制数放在对应的8位上,组成一个4字节的无符号整型。192.168.100.100,192,168在高8位100,100在低8位。 

    解决方法:

      输出时用%u来格式化为无符号整型。把ip数据保存在数据库(MySQL)中时候,我们习惯用ip2long函数生成整型,然后存放在一个int(11)类型的字段中,但是,在不同的系统平台上,ip2long函数得到的值是

    不同的,因此可能造成在从数据库中读出数据,用long2ip得到ip的时候产生错误,说一下我们碰到的情况:

    我们用一个int(11)类型(范围-2147483648 - 2147483647)来保存把一个ip地址用ip2long处理得到的结果,例如ip是’202.105.77.179′,那么在32位机器上得到的结果是:-899068493,

    而在64位机器上却得到3395898803.然后把它写入数据库,由于超过int(11)的范围,因此64位机器上的结果被保存为int(11)的最大值:2147483647.于是在从数据库中取出的时候,便得到了错误的结果,会得

    到”127.255.255.255″这个ip地址.

    解决的办法很多,比如可以用mysql的函数:INET_ATON和INET_NTOA来处理ip地址;或者把保存ip地址的字段改为bigint类型,这样在64位机器上虽然保存的是3395898803,使用long2ip函数仍能得到正确的结果

    我们会发现,有些ip转化成整数后,是负的,这是因为得到的结果是有符号整型,最大值是2147483647.要把它转化为无符号的,可以用
    sprintf("%u",ip2long($ip);
    就能转换为正整数。而且得到的结果用long2ip也可以正常转换回原来的ip地址。也可以用ip2long来验证一个ip是否是有效的

  • 相关阅读:
    openresty
    ATS 相关
    pandas
    flask
    ansible
    zipline
    bcolz
    数据分析 --- concat
    Go --- 基础使用
    Go --- 基础介绍
  • 原文地址:https://www.cnblogs.com/imnzq/p/6528243.html
Copyright © 2011-2022 走看看