PHP 获取用户主机的ip地址


获取用户主机的ip地址,这是个很常见的需求,如何准确获取到呢,下面讲一讲。


正文

获取用户主机的ip地址,这是个很常见的需求,如何准确获取到呢,下面讲一讲。

我们用的框架是Yii2,就放在这个中讲吧,当然核心原理是完全独立的。

上一个方法:

namespace common\components;

use common\misc\LError;
use common\misc\LUtil;
use Yii;
use yii\web\Request;

class LHttpRequest extends Request
{
    public function getUserHostAddress()
    {
        if (!empty($_SERVER['RAW_REMOTE_ADDR'])) {
            $_SERVER["REMOTE_ADDR"] = $_SERVER['RAW_REMOTE_ADDR'];
        } else if (isset($_SERVER['HTTP_CDN_SRC_IP'])) {
            list($_SERVER["REMOTE_ADDR"]) = explode(',', $_SERVER["HTTP_CDN_SRC_IP"]);
            $_SERVER["REMOTE_ADDR"] = trim($_SERVER["REMOTE_ADDR"]);
        } else if (!isset($_SERVER['REMOTE_ADDR']) || LUtil::isLAN($_SERVER['REMOTE_ADDR'])) {
            if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
                list($_SERVER["REMOTE_ADDR"]) = explode(',', $_SERVER["HTTP_X_FORWARDED_FOR"]);
                $_SERVER["REMOTE_ADDR"] = trim($_SERVER["REMOTE_ADDR"]);
            }
        }

        return $_SERVER["REMOTE_ADDR"];
    }

}    

这里继承了Yii的Request类,所以在配置文件中需要重新配置request组件:

"components" => [
    'request' => array(
        'class' => 'common\components\LHttpRequest',
        'enableCookieValidation' => true,
        'enableCsrfValidation' => false,
        'parsers'    =>  [
            'application/json' => 'yii\web\JsonParser',
        ],
    ),
    'response'  =>  array(
        'format'=> yii\web\Response::FORMAT_JSON,
    ),
    'errorHandler'  =>  array(
        'class' => 'common\components\LErrorHandler',
    ),
],

再看一下LUtil::isLAN方法:

namespace common\misc;

class LUtil
{
    public static function isLAN( $ip )
    {
        $ip = ip2long( $ip );
        $net_a = ip2long('10.0.0.0') >> 24; //A类网预留ip的网络地址 10.0.0.0 ~ 10.255.255.255
        $net_b = ip2long('172.16.0.0') >> 20; //B类网预留ip的网络地址 172.16.0.0 ~ 172.31.255.255
        $net_c = ip2long('192.168.0.0') >> 16; //C类网预留ip的网络地址 192.168.0.0 ~ 192.168.255.255

        return $ip >> 24 === $net_a || $ip >> 20 === $net_b || $ip >> 16 === $net_c;
    }
}

下面开始解说:

$_SERVER["REMOTE_ADDR"] 是当前用户的 IP 地址,都存在,不过可能是经过修改的;

$_SERVER["HTTP_X_FORWARDED_FOR"] 可以获得位于代理(网关)后面的直接IP,当然必须这个代理支持;

当然,上面的并不一定确定是用户的真实IP,只是一种获取方法,完善的方法,需要细究。

我们打印$_SERVER看一下:

array(32) {
  ["USER"]=>
  string(8) "www-data"
  ["HOME"]=>
  string(8) "/var/www"
  ["HTTP_UPGRADE_INSECURE_REQUESTS"]=>
  string(1) "1"
  ["HTTP_CONNECTION"]=>
  string(10) "keep-alive"
  ["HTTP_ACCEPT_ENCODING"]=>
  string(13) "gzip, deflate"
  ["HTTP_ACCEPT_LANGUAGE"]=>
  string(59) "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"
  ["HTTP_ACCEPT"]=>
  string(63) "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
  ["HTTP_USER_AGENT"]=>
  string(68) "Mozilla/5.0 (X11; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0"
  ["HTTP_HOST"]=>
  string(8) "test.com"
  ["REDIRECT_STATUS"]=>
  string(3) "200"
  ["SERVER_NAME"]=>
  string(8) "crm.host"
  ["SERVER_PORT"]=>
  string(2) "80"
  ["SERVER_ADDR"]=>
  string(9) "127.0.0.1"
  ["REMOTE_PORT"]=>
  string(5) "43828"
  ["REMOTE_ADDR"]=>
  string(9) "127.0.0.1"
  ["SERVER_SOFTWARE"]=>
  string(12) "nginx/1.10.3"
  ["GATEWAY_INTERFACE"]=>
  string(7) "CGI/1.1"
  ["REQUEST_SCHEME"]=>
  string(4) "http"
  ["SERVER_PROTOCOL"]=>
  string(8) "HTTP/1.1"
  ["DOCUMENT_ROOT"]=>
  string(32) "/var/www/html/test/web"
  ["DOCUMENT_URI"]=>
  string(10) "/index.php"
  ["REQUEST_URI"]=>
  string(1) "/"
  ["SCRIPT_NAME"]=>
  string(10) "/index.php"
  ["CONTENT_LENGTH"]=>
  string(0) ""
  ["CONTENT_TYPE"]=>
  string(0) ""
  ["REQUEST_METHOD"]=>
  string(3) "GET"
  ["QUERY_STRING"]=>
  string(0) ""
  ["SCRIPT_FILENAME"]=>
  string(42) "/var/www/html/test/web/index.php"
  ["FCGI_ROLE"]=>
  string(9) "RESPONDER"
  ["PHP_SELF"]=>
  string(10) "/index.php"
  ["REQUEST_TIME_FLOAT"]=>
  float(1619666810.484)
  ["REQUEST_TIME"]=>
  int(1619666810)
}






参考资料

HTTP 请求头中的 X-Forwarded-For https://blog.csdn.net/u013982161/article/details/55813860

https://www.jb51.net/article/37690.htm

PHP 位运算符 http://www.php.net/manual/zh/language.operators.bitwise.php

ip2long http://www.php.net/manual/en/function.ip2long.php

long2ip http://php.net/manual/en/function.long2ip.php

$_SERVER http://php.net/manual/zh/reserved.variables.server.php

PHP $_SERVER系统变量解说 https://ibaiyang.github.io/blog/php/2018/08/11/PHP-$_SERVER%E7%B3%BB%E7%BB%9F%E5%8F%98%E9%87%8F%E8%A7%A3%E8%AF%B4.html


返回