PHP根据IP地址获取所在城市具体实现


Posted in PHP onNovember 27, 2013

文件目录:

ipLocation
-----qqwry
----------QQWry.Dat
-----ipCity.class.php

ipCity.class.php文件代码:

<?php
class ipCity {
    /**
     * 根据ip地址获取对应所在城市
     * @param type $userip 用户IP地址
     * @return string
     */
    public function getCity( $userip, $dat_path = '' ) {
        //IP数据库路径,这里用的是QQ IP数据库 20110405 纯真版
        empty( $dat_path ) && $dat_path = FCPATH . 'plugin/ipLocation/qqwry/QQWry.Dat';
        //判断IP地址是否有效
        if ( preg_match( "/^([0-9]{1,3}.){3}[0-9]{1,3}$/", $userip ) == 0 ) {
            return 'IP Address Invalid';
        }
        //打开IP数据库
        if ( !$fd = @fopen( $dat_path, 'rb' ) ) {
            return 'IP data file not exists or access denied';
        }
        //explode函数分解IP地址,运算得出整数形结果
        $userip = explode( '.', $userip );
        $useripNum = $userip[0] * 16777216 + $userip[1] * 65536 + $userip[2] * 256 + $userip[3];
        //获取IP地址索引开始和结束位置
        $DataBegin = fread( $fd, 4 );
        $DataEnd = fread( $fd, 4 );
        $useripbegin = implode( '', unpack( 'L', $DataBegin ) );
        if ( $useripbegin < 0 )
            $useripbegin += pow( 2, 32 );
        $useripend = implode( '', unpack( 'L', $DataEnd ) );
        if ( $useripend < 0 )
            $useripend += pow( 2, 32 );
        $useripAllNum = ($useripend - $useripbegin) / 7 + 1;
        $BeginNum = 0;
        $EndNum = $useripAllNum;
        //使用二分查找法从索引记录中搜索匹配的IP地址记录
        while ( $userip1num > $useripNum || $userip2num < $useripNum ) {
            $Middle = intval( ($EndNum + $BeginNum) / 2 );
            //偏移指针到索引位置读取4个字节
            fseek( $fd, $useripbegin + 7 * $Middle );
            $useripData1 = fread( $fd, 4 );
            if ( strlen( $useripData1 ) < 4 ) {
                fclose( $fd );
                return 'File Error';
            }
            //提取出来的数据转换成长整形,如果数据是负数则加上2的32次幂
            $userip1num = implode( '', unpack( 'L', $useripData1 ) );
            if ( $userip1num < 0 )
                $userip1num += pow( 2, 32 );
            //提取的长整型数大于我们IP地址则修改结束位置进行下一次循环
            if ( $userip1num > $useripNum ) {
                $EndNum = $Middle;
                continue;
            }
            //取完上一个索引后取下一个索引
            $DataSeek = fread( $fd, 3 );
            if ( strlen( $DataSeek ) < 3 ) {
                fclose( $fd );
                return 'File Error';
            }
            $DataSeek = implode( '', unpack( 'L', $DataSeek . chr( 0 ) ) );
            fseek( $fd, $DataSeek );
            $useripData2 = fread( $fd, 4 );
            if ( strlen( $useripData2 ) < 4 ) {
                fclose( $fd );
                return 'File Error';
            }
            $userip2num = implode( '', unpack( 'L', $useripData2 ) );
            if ( $userip2num < 0 )
                $userip2num += pow( 2, 32 );
            //找不到IP地址对应城市
            if ( $userip2num < $useripNum ) {
                if ( $Middle == $BeginNum ) {
                    fclose( $fd );
                    return 'No Data';
                }
                $BeginNum = $Middle;
            }
        }
        $useripFlag = fread( $fd, 1 );
        if ( $useripFlag == chr( 1 ) ) {
            $useripSeek = fread( $fd, 3 );
            if ( strlen( $useripSeek ) < 3 ) {
                fclose( $fd );
                return 'System Error';
            }
            $useripSeek = implode( '', unpack( 'L', $useripSeek . chr( 0 ) ) );
            fseek( $fd, $useripSeek );
            $useripFlag = fread( $fd, 1 );
        }
        if ( $useripFlag == chr( 2 ) ) {
            $AddrSeek = fread( $fd, 3 );
            if ( strlen( $AddrSeek ) < 3 ) {
                fclose( $fd );
                return 'System Error';
            }
            $useripFlag = fread( $fd, 1 );
            if ( $useripFlag == chr( 2 ) ) {
                $AddrSeek2 = fread( $fd, 3 );
                if ( strlen( $AddrSeek2 ) < 3 ) {
                    fclose( $fd );
                    return 'System Error';
                }
                $AddrSeek2 = implode( '', unpack( 'L', $AddrSeek2 . chr( 0 ) ) );
                fseek( $fd, $AddrSeek2 );
            } else {
                fseek( $fd, -1, SEEK_CUR );
            }
            while ( ($char = fread( $fd, 1 )) != chr( 0 ) )
                $useripAddr2 .= $char;
            $AddrSeek = implode( '', unpack( 'L', $AddrSeek . chr( 0 ) ) );
            fseek( $fd, $AddrSeek );
            while ( ($char = fread( $fd, 1 )) != chr( 0 ) )
                $useripAddr1 .= $char;
        } else {
            fseek( $fd, -1, SEEK_CUR );
            while ( ($char = fread( $fd, 1 )) != chr( 0 ) )
                $useripAddr1 .= $char;
            $useripFlag = fread( $fd, 1 );
            if ( $useripFlag == chr( 2 ) ) {
                $AddrSeek2 = fread( $fd, 3 );
                if ( strlen( $AddrSeek2 ) < 3 ) {
                    fclose( $fd );
                    return 'System Error';
                }
                $AddrSeek2 = implode( '', unpack( 'L', $AddrSeek2 . chr( 0 ) ) );
                fseek( $fd, $AddrSeek2 );
            } else {
                fseek( $fd, -1, SEEK_CUR );
            }
            while ( ($char = fread( $fd, 1 )) != chr( 0 ) ) {
                $useripAddr2 .= $char;
            }
        }
        fclose( $fd );
        //返回IP地址对应的城市结果
        if ( preg_match( '/http/i', $useripAddr2 ) ) {
            $useripAddr2 = '';
        }
        $useripaddr = "$useripAddr1 $useripAddr2";
        $useripaddr = preg_replace( '/CZ88.Net/is', '', $useripaddr );
        $useripaddr = preg_replace( '/^s*/is', '', $useripaddr );
        $useripaddr = preg_replace( '/s*$/is', '', $useripaddr );
        if ( preg_match( '/http/i', $useripaddr ) || $useripaddr == '' ) {
            $useripaddr = 'No Data';
        } elseif ( !$this->is_utf8( $useripaddr ) ) {
            $useripaddr = iconv( 'GBK', 'UTF-8', $useripaddr );
        }
        return $useripaddr;
    }
    /**
     * 判断是否我utf-8编码的字符串
     * @param type $string
     * @return boolean
     */
    private function is_utf8( $string ) {
        if ( preg_match( "/^([" . chr( 228 ) . "-" . chr( 233 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}){1}/", $string ) == true || preg_match( "/([" . chr( 228 ) . "-" . chr( 233 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}){1}$/", $string ) == true || preg_match( "/([" . chr( 228 ) . "-" . chr( 233 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}[" . chr( 128 ) . "-" . chr( 191 ) . "]{1}){2,}/", $string ) == true ) {
            return true;
        } else {
            return false;
        }
    }
}

QQWry.Dat文件下载地址:http://xiazai.3water.com/201311/yuanma/qqwry.dat(3water.com).zip

使用演示:

include FCPATH . 'plugin/ipLocation/ipCity.class.php';
$city = new ipCity();
$addr = $city->getCity( '172.0.0.1' );
echo $addr; // echo 本地地址
PHP 相关文章推荐
配置最新的PHP加MYSQL服务器
Oct 09 PHP
玩转虚拟域名◎+ .
Oct 09 PHP
解析php中heredoc的使用方法
Jun 17 PHP
php制作中间带自己定义图片二维码的方法
Jan 27 PHP
Laravel框架学习笔记(二)项目实战之模型(Models)
Oct 15 PHP
PHP页面实现定时跳转的方法
Oct 31 PHP
php 数组元素快速去重
May 05 PHP
php实现生成带二维码图片并强制下载功能
Feb 24 PHP
在Laravel5.6中使用Swoole的协程数据库查询
Jun 15 PHP
PHP图像处理 imagestring添加图片水印与文字水印操作示例
Feb 06 PHP
php7 list()、session及其他模块的修改实例分析
May 25 PHP
tp5.1 框架路由操作-URL生成实例分析
May 26 PHP
php编写的简单页面跳转功能实现代码
Nov 27 #PHP
关于JSON以及JSON在PHP中的应用技巧
Nov 27 #PHP
XAMPP安装与使用方法详细解析
Nov 27 #PHP
浅析echo(),print(),print_r(),return之间的区别
Nov 27 #PHP
PHP echo,print,printf,sprintf函数之间的区别与用法详解
Nov 27 #PHP
php strnatcmp()函数的用法总结
Nov 27 #PHP
PHP 正则判断中文UTF-8或GBK的思路及具体实现
Nov 26 #PHP
You might like
用PHP制作静态网站的模板框架(三)
2006/10/09 PHP
php自动获取目录下的模板的代码
2010/08/08 PHP
php实现在服务器上创建目录的方法
2015/03/16 PHP
Laravel框架下载,安装及路由操作图文详解
2019/12/04 PHP
PHP中的异常处理机制深入讲解
2020/11/10 PHP
js类的静态属性和实例属性的理解
2009/10/01 Javascript
JavaScript DOM学习第四章 getElementByTagNames
2010/02/19 Javascript
javascript跑马灯悬停放大效果实现代码
2012/12/12 Javascript
Javascript控制页面链接在新窗口打开具体方法
2013/08/16 Javascript
Node.js中安全调用系统命令的方法(避免注入安全漏洞)
2014/12/05 Javascript
javascript中获取class的简单实现
2016/07/12 Javascript
基于Marquee.js插件实现的跑马灯效果示例
2017/01/25 Javascript
layui扩展上传组件模拟进度条的方法
2019/09/23 Javascript
jQuery实现中奖播报功能(让文本滚动起来) 简单设置数值即可
2020/03/20 jQuery
Python的gevent框架的入门教程
2015/04/29 Python
利用python模拟实现POST请求提交图片的方法
2017/07/25 Python
Python搜索引擎实现原理和方法
2017/11/27 Python
django 2.0更新的10条注意事项总结
2018/01/05 Python
python如何统计序列中元素
2020/07/31 Python
Python实现的knn算法示例
2018/06/14 Python
python3中的eval和exec的区别与联系
2019/10/10 Python
python sorted方法和列表使用解析
2019/11/18 Python
python 实现矩阵按对角线打印
2019/11/29 Python
在tensorflow中实现屏蔽输出的log信息
2020/02/04 Python
python图形开发GUI库pyqt5的详细使用方法及各控件的属性与方法
2020/02/14 Python
NUK奶瓶美国官网:NUK美国
2016/09/26 全球购物
玩具反斗城天猫官方旗舰店:享誉全球的玩具店
2017/10/10 全球购物
2014年社区学雷锋活动总结
2014/03/09 职场文书
大学生毕业求职信
2014/06/12 职场文书
学习退步检讨书
2014/09/28 职场文书
2015年度党风廉政建设工作情况汇报
2015/01/02 职场文书
综治目标管理责任书
2015/05/11 职场文书
在人间读书笔记
2015/06/30 职场文书
Python爬取某拍短视频
2021/06/11 Python
gateway网关接口请求的校验方式
2021/07/15 Java/Android
Android Rxjava3 使用场景详解
2022/04/07 Java/Android