解析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 相关文章推荐
对Session和Cookie的区分与解释
Mar 16 PHP
PHP两种去掉数组重复值的方法比较
Jun 19 PHP
php写入数据到CSV文件的方法
Mar 14 PHP
学习php设计模式 php实现建造者模式
Dec 07 PHP
smarty循环嵌套用法示例分析
Jul 19 PHP
PHP入门教程之面向对象基本概念实例分析
Sep 11 PHP
如何使用php等比例缩放图片
Oct 12 PHP
thinkPHP实现签到功能的方法
Mar 15 PHP
YII框架实现自定义第三方扩展操作示例
Apr 26 PHP
laravel框架上传图片实现实时预览功能
Oct 14 PHP
PHP中通过getopt解析GNU C风格命令行选项
Nov 18 PHP
php数值计算num类简单操作示例
May 15 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数据过滤的方法
2013/10/30 PHP
在CentOS上搭建LAMP+vsftpd环境的简单指南
2015/08/01 PHP
Zend Framework连接Mysql数据库实例分析
2016/03/19 PHP
PHP socket 模拟POST 请求实例代码
2016/07/18 PHP
ThinkPHP打水印及设置水印位置的方法
2016/10/14 PHP
使用Yii2实现主从数据库设置
2016/11/20 PHP
PHP插件PHPMailer发送邮件功能
2017/02/28 PHP
extjs grid设置某列背景颜色和字体颜色的方法
2010/09/03 Javascript
详解JavaScript编程中的数组结构
2015/10/24 Javascript
xcode中获取js文件的路径方法(推荐)
2016/11/05 Javascript
EasyUi 打开对话框后控件赋值及赋值后不显示的问题解决办法
2017/01/19 Javascript
微信小程序 商城开发(ecshop )简单实例
2017/04/07 Javascript
vue的Virtual Dom实现snabbdom解密
2017/05/03 Javascript
jquery.uploadView 实现图片预览上传功能
2017/08/10 jQuery
基于node.js express mvc轻量级框架实践
2017/09/14 Javascript
解决vue+webpack打包路径的问题
2018/03/06 Javascript
vue.js实现的幻灯片功能示例
2019/01/18 Javascript
vue中img src 动态加载本地json的图片路径写法
2019/04/25 Javascript
详解vue 动态加载并注册组件且通过 render动态创建该组件
2019/05/30 Javascript
使用localStorage替代cookie做本地存储
2019/09/25 Javascript
基于VUE实现判断设备是PC还是移动端
2020/07/03 Javascript
利用 JavaScript 实现并发控制的示例代码
2020/12/31 Javascript
vue动态设置路由权限的主要思路
2021/01/13 Vue.js
粗略分析Python中的内存泄漏
2015/04/23 Python
Python序列类型的打包和解包实例
2019/12/21 Python
Python selenium 加载并保存QQ群成员,去除其群主、管理员信息的示例代码
2020/05/28 Python
Python虚拟环境库virtualenvwrapper安装及使用
2020/06/17 Python
详解python3 GUI刷屏器(附源码)
2021/02/18 Python
html5+css3之CSS中的布局与Header的实现
2014/11/21 HTML / CSS
悬挂训练绳:TRX
2017/12/14 全球购物
波兰运动鞋网上商店:e-Sporting
2018/02/16 全球购物
机电一体化职业规划书
2014/01/07 职场文书
求职意向书
2014/07/29 职场文书
普通党员群众路线教育实践活动心得体会
2014/11/04 职场文书
写给妈妈的感谢信
2015/01/22 职场文书
python3 删除所有自定义变量的操作
2021/04/08 Python