解析php根据ip查询所在地区(非常有用,赶集网就用到)


Posted in PHP onJuly 01, 2013

dat文件,关于ip对应地区的信息文件
qqwry.dat文件
网上自己下载

class类文件,解析qqwry.data文件的
IpLocation.php文件

<?php
class IpLocation {
    /**
    * @var resource 指针
    */
    private $fp;
    /**
    * 第一条IP记录的偏移地址
    * @var int
    */
    private $firstip;
    /**
    * 最后一条IP记录的偏移地址
    * @var int
    */
    private $lastip;
    /**
    * IP记录的总条数(不包含版本信息记录)
    * @var int
    */
    private $totalip;
    /**
    * 构造函数,打开 QQWry.Dat 文件并初始化类中的信息
    * @param string $filename
    * @return IpLocation
    */
    public function __construct($filename = "qqwry.dat") {
        $this->fp = 0;
        if (($this->fp = @fopen($filename, 'rb')) !== false) {
            $this->firstip = $this->getlong();
            $this->lastip = $this->getlong();
            $this->totalip = ($this->lastip - $this->firstip) / 7;
        }
    }
    /**
    * 返回读取的长整型数
    * @access private
    * @return int
    */
    public function getlong() {
        //将读取的little-endian编码的4个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 4));
        return $result['long'];
    }
    /**
    * 返回读取的3个字节的长整型数
    *
    * @access private
    * @return int
    */
    public function getlong3() {
        //将读取的little-endian编码的3个字节转化为长整型数
        $result = unpack('Vlong', fread($this->fp, 3).chr(0));
        return $result['long'];
    }
    /**
    * 返回压缩后可进行比较的IP地址
    *
    * @access private
    * @param string $ip
    * @return string
    */
    public function packip($ip) {
        // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False,
        // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串
        return pack('N', intval(ip2long($ip)));
    }
    /**
    * 返回读取的字符串
    *
    * @access private
    * @param string $data
    * @return string
    */
    public function getstring($data = "") {
        $char = fread($this->fp, 1);
        while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束
            $data .= $char; // 将读取的字符连接到给定字符串之后
            $char = fread($this->fp, 1);
        }
        return mb_convert_encoding($data, 'utf-8', 'gb2312');
    }
    /**
    * 返回地区信息
    *
    * @access private
    * @return string
    */
    public function getarea() {
        $byte = fread($this->fp, 1); // 标志字节
        switch (ord($byte)) {
            case 0: // 没有区域信息
                $area = "";
            break;
            case 1:
            case 2: // 标志字节为1或2,表示区域信息被重定向
                fseek($this->fp, $this->getlong3());
                $area = $this->getstring();
            break;
            default: // 否则,表示区域信息没有被重定向
                $area = $this->getstring($byte);
            break;
        }
        return $area;
    }
    /**
    * 根据所给 IP 地址或域名返回所在地区信息
    * @access public
    * @param string $ip
    * @return array
    */
    function getlocation($ip) {
        if (!$this->fp) return null; // 如果数据文件没有被正确打开,则直接返回空
        $location['ip'] = gethostbyname($ip); // 将输入的域名转化为IP地址
        $ip = $this->packip($location['ip']); // 将输入的IP地址转化为可比较的IP地址
        // 不合法的IP地址会被转化为255.255.255.255
        // 对分搜索
        $l = 0; // 搜索的下边界
        $u = $this->totalip; // 搜索的上边界
        $findip = $this->lastip; // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息)
        while ($l <= $u) { // 当上边界小于下边界时,查找失败
            $i = floor(($l + $u) / 2); // 计算近似中间记录
            fseek($this->fp, $this->firstip + $i * 7);
            $beginip = strrev(fread($this->fp, 4)); // 获取中间记录的开始IP地址
            // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式
            // 以便用于比较,后面相同。
            if ($ip < $beginip) { // 用户的IP小于中间记录的开始IP地址时
                $u = $i - 1; // 将搜索的上边界修改为中间记录减一
            }else{
                fseek($this->fp, $this->getlong3());
                $endip = strrev(fread($this->fp, 4)); // 获取中间记录的结束IP地址
                if ($ip > $endip) { // 用户的IP大于中间记录的结束IP地址时
                    $l = $i + 1; // 将搜索的下边界修改为中间记录加一
                }else{ // 用户的IP在中间记录的IP范围内时
                    $findip = $this->firstip + $i * 7;
                    break; // 则表示找到结果,退出循环
                }
            }
        }
        //获取查找到的IP地理位置信息
        fseek($this->fp, $findip);
        $location['beginip'] = long2ip($this->getlong()); // 用户IP所在范围的开始地址
        $offset = $this->getlong3();
        fseek($this->fp, $offset);
        $location['endip'] = long2ip($this->getlong()); // 用户IP所在范围的结束地址
        $byte = fread($this->fp, 1); // 标志字节
        switch (ord($byte)) {
            case 1: // 标志字节为1,表示国家和区域信息都被同时重定向
                $countryOffset = $this->getlong3(); // 重定向地址
                fseek($this->fp, $countryOffset);
                $byte = fread($this->fp, 1); // 标志字节
                switch (ord($byte)) {
                    case 2: // 标志字节为2,表示国家信息又被重定向
                        fseek($this->fp, $this->getlong3());
                        $location['country'] = $this->getstring();
                        fseek($this->fp, $countryOffset + 4);
                        $location['area'] = $this->getarea();
                        break;
                    default: // 否则,表示国家信息没有被重定向
                        $location['country'] = $this->getstring($byte);
                        $location['area'] = $this->getarea();
                        break;
                }
                break;
            case 2: // 标志字节为2,表示国家信息被重定向
                fseek($this->fp, $this->getlong3());
                $location['country'] = $this->getstring();
                fseek($this->fp, $offset + 8);
                $location['area'] = $this->getarea();
                break;
            default: // 否则,表示国家信息没有被重定向
                $location['country'] = $this->getstring($byte);
                $location['area'] = $this->getarea();
                break;
        }
        if ($location['country'] == " CZ88.NET") { // CZ88.NET表示没有有效信息
            $location['country'] = "未知";
        }
        if ($location['area'] == " CZ88.NET") {
            $location['area'] = "";
        }
        return $location;
    }    /**
    * 析构函数,用于在页面执行结束后自动关闭打开的文件。
    *
    */
    function __desctruct() {
        if ($this->fp) {
            fclose($this->fp);
        }
        $this->fp = 0;
    }
}
?>

这个也可以网上下载,也可以copy这里的,这里的也是很全的。
执行文件,我这里叫ip_location.php文件
<?php 
function getIpPlace(){
 require_once("IpLocation.php")//加载类文件IpLocation.php
 $ipfile = "qqwry.dat";  //获取ip对应地区的信息文件
 $iplocation = new IpLocation($ipfile); //new IpLocation($ipfile) $ipfile ip对应地区信息文件
 $ipresult = $iplocation->getlocation("ip地址"); //根据ip地址获得地区 getlocation("ip地区")
 return $ipresult;
}
print_r($getIpPlace()); //调用方法
?>

PHP 相关文章推荐
用PHP连接MySQL代码的参数说明
Jun 07 PHP
延长phpmyadmin登录时间的方法
Feb 06 PHP
CI框架源码阅读,系统常量文件constants.php的配置
Feb 28 PHP
Apache下禁止php文件被直接访问的解决方案
Apr 25 PHP
PHP中操作ini配置文件的方法
Apr 25 PHP
深入PHP nl2br()格式化输出的详解
Jun 05 PHP
php采用file_get_contents代替使用curl实例
Nov 07 PHP
php上传功能集后缀名判断和随机命名(强力推荐)
Sep 10 PHP
PHP执行SQL文件并将SQL文件导入到数据库
Sep 17 PHP
Centos PHP 扩展Xchche的安装教程
Jul 09 PHP
PHP正则表达式笔记与实例详解
May 09 PHP
TP5(thinkPHP5框架)基于bootstrap实现的单图上传插件用法示例
May 29 PHP
浅析php插件 HTMLPurifier HTML解析器
Jul 01 #PHP
浅析php插件 Simple HTML DOM 用DOM方式处理HTML
Jul 01 #PHP
php curl选项列表(超详细)
Jul 01 #PHP
基于simple_html_dom的使用小结
Jul 01 #PHP
解析php php_openssl.dll的作用
Jul 01 #PHP
关于php 接口问题(php接口主要也就是运用curl,curl函数)
Jul 01 #PHP
浅析PKI加密解密 OpenSSL
Jul 01 #PHP
You might like
生成静态页面的php函数,php爱好者站推荐
2007/03/19 PHP
PHP请求Socket接口测试实例
2016/08/12 PHP
PHP面向对象自动加载机制原理与用法分析
2016/10/14 PHP
php中实现字符串翻转的方法
2017/02/22 PHP
Javascript学习笔记1 数据类型
2010/01/11 Javascript
Jquery Ajax学习实例 向页面发出请求,返回XML格式数据
2010/03/14 Javascript
jquery异步请求实例代码
2011/06/21 Javascript
js实现三张图(文)片一起切换的banner焦点图
2015/08/25 Javascript
javascript图片切换综合实例(循环切换、顺序切换)
2016/01/13 Javascript
jquery+Jscex打造游戏力度条
2020/09/12 Javascript
jQuery插件zTree实现更新根节点中第i个节点名称的方法示例
2017/03/08 Javascript
jQuery插件HighCharts绘制的2D堆柱状图效果示例【附demo源码下载】
2017/03/14 Javascript
JS简单实现数组去重的方法分析
2017/10/14 Javascript
动态加载权限管理模块中的Vue组件
2018/01/16 Javascript
微信小程序Echarts图表组件使用方法详解
2019/06/25 Javascript
Python struct模块解析
2014/06/12 Python
python文件操作之目录遍历实例分析
2015/05/20 Python
Python 调用 zabbix api的方法示例
2019/01/06 Python
弄懂这56个Python使用技巧(轻松掌握Python高效开发)
2019/09/18 Python
Python 类,property属性(简化属性的操作),@property,property()用法示例
2019/10/12 Python
Python离线安装各种库及pip的方法
2020/11/28 Python
一款纯css3实现的圆形旋转分享按钮旋转角度可自己调整
2014/09/02 HTML / CSS
CSS实现进度条和订单进度条的示例
2020/11/05 HTML / CSS
ASOS英国官网:英国在线时装和化妆品零售商
2017/05/19 全球购物
英国最大的女士服装零售商:Bonmarché
2017/08/17 全球购物
MAC Cosmetics官方网站:魅可专业艺术彩妆
2019/04/10 全球购物
俄罗斯最大的在线珠宝大卖场:Nebo
2019/12/08 全球购物
奥林匹亚体育:Olympia Sports
2020/12/30 全球购物
亿企通软件测试面试题
2012/04/10 面试题
预备党员转正思想汇报
2014/01/12 职场文书
小学毕业感言300字
2014/02/19 职场文书
2014年小学植树节活动方案
2014/03/02 职场文书
技术岗位竞聘演讲稿
2014/05/16 职场文书
新员工考核评语
2014/12/31 职场文书
2016年秋季新学期致辞
2015/07/30 职场文书
《红领巾真好》教学反思
2016/02/16 职场文书