PHP 判断用户是否中国的 IP

因为一些特殊的业务需要判断用户是否在国内访问。因为只需要判断是否国内访问,所以用 IP 库的话会太过于浪费,杀鸡焉用牛刀,通过 Google 搜索找到一个 Python 的算法,遂翻译成 PHP 可用的算法。

首先先把 APNIC 的数据下载回来,并过滤掉无用的数据,JSON 格式化后保存,核心函数如下:

public static function get_china_ip_table()
{
    // 获取 APNIC 的数据
    $tb   = file_get_contents('http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest');

    $tb_array = explode("\n", $tb);

    unset($tb);

    $tb_china = array();

    foreach ($tb_array as $t) {
        $ta = explode("|", $t);

        if (count($ta) >= 7) {
            if ($ta[1] == 'CN' && $ta[2] == 'ipv4') {
                $ip_addr = explode(".", $ta[3]);

                if (count($ip_addr) >= 4) {
                    $num = (int)$ta[4];
                    $a1  = (int)$ip_addr[0];
                    $a2  = (int)$ip_addr[1];
                    $a3  = (int)$ip_addr[2];
                    $a4  = (int)$ip_addr[3];
                    if ($num > 0) {
                        $offset = 0;

                        while ($num > 0) {
                            if ($num >= 65536) {
                                $tb_china[$a1][$a2 + $offset][] = array('s' => 0, 'e' => 65535, 'n' => 65535);
                            } else {
                                $st = $a3 * 256 + $a4;
                                $et = $st + $num - 1;

                                $tb_china[$a1][$a2 + $offset][] = array('s' => $st, 'e' => $et, 'n' => $num);
                            }
                            $num    = $num - 65536;
                            $offset = $offset + 1;
                        }
                    }
                }
            }
        }
    }
    unset($tb_array);

    $ts_china = json_encode($tb_china);
    unset($tb_china);

    $fp = @fopen('保存到文件', 'w');
    fwrite($fp, $ts_china);
    fclose($fp);

    unset($ts_china);
}

然后判断的核心代码:

public static function check_is_china_ip($ip)
{
    $ip_addr = explode('.', $ip);

    if (count($ip_addr) < 4)
        return false;

    $a1 = (int)$ip_addr[0];
    $a2 = (int)$ip_addr[1];
    $a3 = (int)$ip_addr[2];
    $a4 = (int)$ip_addr[3];

    $s_china = file_get_contents('JSON 格式化后保存的文件');

    $tb_china = json_decode($s_china, 1);

    unset($s_china);

    if (!isset($tb_china[$a1][$a2]) || count($tb_china[$a1][$a2]) == 0)
        return false;

    $a = $a3 * 256 + $a4;

    foreach ($tb_china[$a1][$a2] as $d) {
        if ($a >= $d['s'] && $a <= $d['e']) {
            return true;
        }
    }

    return false;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注