解析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读取msn上的用户信息类
Dec 05 PHP
PHP中file_exists与is_file,is_dir的区别介绍
Sep 12 PHP
php 模拟POST提交的2种方法详解
Jun 17 PHP
将word转化为swf 如同百度文库般阅读实现思路及代码
Aug 09 PHP
PHP实现无限级分类(不使用递归)
Oct 22 PHP
yii2.0实现pathinfo的形式访问的配置方法
Apr 06 PHP
Yii2基于Ajax自动获取表单数据的方法
Aug 10 PHP
PHP Header用于页面跳转时的几个注意事项
Oct 21 PHP
php使用file函数、fseek函数读取大文件效率对比分析
Nov 04 PHP
浅谈PHP中类和对象的相关函数
Apr 26 PHP
PHP中ltrim()函数的用法与实例讲解
Mar 28 PHP
Laravel 5.2 文档 数据库 ―― 起步介绍
Oct 21 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
博士208HAF收音机实习报告
2021/03/02 无线电
php与mysql建立连接并执行SQL语句的代码
2011/07/04 PHP
win7+apache+php+mysql环境配置操作详解
2013/06/10 PHP
php保存任意网络图片到服务器的方法
2015/04/14 PHP
php实现倒计时效果
2015/12/19 PHP
PHP简单实现文本计数器的方法
2016/04/28 PHP
JavaScript中的History历史对象
2008/01/16 Javascript
javascript多种数据类型表格排序代码分析
2010/09/11 Javascript
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
2013/01/02 Javascript
node.js中的http.response.write方法使用说明
2014/12/14 Javascript
原生js实现日期联动
2015/01/12 Javascript
Jquery中offset()和position()的区别分析
2015/02/05 Javascript
Javascript 字符串模板的简单实现
2016/02/13 Javascript
JS实现的相册图片左右滚动完整实例
2016/11/23 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
纯javascript前端实现base64图片下载(兼容IE10+)
2018/09/14 Javascript
Vue列表渲染的示例代码
2018/11/01 Javascript
JavaScript学习笔记之数组基本操作示例
2019/01/09 Javascript
vue实现的请求服务器端API接口示例
2019/05/25 Javascript
layui table数据修改的回显方法
2019/09/04 Javascript
vue-cli 为项目设置别名的方法
2019/10/15 Javascript
javascript实现的图片预览和上传功能示例【兼容IE 9】
2020/05/01 Javascript
Python读取数据集并消除数据中的空行方法
2018/07/12 Python
pip 20.3 新版本发布!即将抛弃 Python 2.x(推荐)
2020/12/16 Python
python中实现栈的三种方法
2020/12/19 Python
Python命令行参数argv和argparse该如何使用
2021/02/08 Python
外企C语言笔试题
2013/11/10 面试题
比较一下entity bean和session bean
2013/12/27 面试题
教师绩效考核方案
2014/01/21 职场文书
公司市场专员岗位职责
2014/06/29 职场文书
党的群众路线教育实践活动对照检查材料(个人)
2014/09/24 职场文书
民政局个人整改措施
2014/09/24 职场文书
设备收款委托书范本
2014/10/02 职场文书
习近平在党的群众路线教育实践活动总结大会上的讲话全文
2014/10/25 职场文书
天那边观后感
2015/06/09 职场文书
工资证明格式模板
2015/06/12 职场文书