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 相关文章推荐
浅析Yii中使用RBAC的完全指南(用户角色权限控制)
Jun 20 PHP
PHP动态生成javascript文件的2个例子
Apr 11 PHP
ThinkPHP3.1查询语言详解
Jun 19 PHP
php自定义urlencode,urldecode函数实例
Mar 24 PHP
php使用GD创建保持宽高比缩略图的方法
Apr 17 PHP
如何使用php脚本给html中引用的js和css路径打上版本号
Nov 18 PHP
php实现的xml操作类
Jan 15 PHP
Zend Framework框架教程之Zend_Db_Table_Rowset用法实例分析
Mar 21 PHP
php使用pclzip类实现文件压缩的方法(附pclzip类下载地址)
Apr 30 PHP
Laravel框架分页实现方法分析
Jun 12 PHP
Swoole实现异步投递task任务案例详解
Apr 02 PHP
Laravel 数据库加密及数据库表前缀配置方法
Oct 10 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中使用gettext来支持多语言的方法
2011/05/02 PHP
php实现多城市切换特效
2015/08/09 PHP
php简单统计中文个数的方法
2016/09/30 PHP
laravel migrate初学常见错误的解决方法
2017/10/11 PHP
php扩展开发入门demo示例
2019/09/23 PHP
Avengerls vs KG BO3 第一场2.18
2021/03/10 DOTA
JavaScript高级程序设计 读书笔记之九 本地对象Array
2012/02/27 Javascript
JavaScript 学习笔记之一jQuery写法图片等比缩放以及预加载
2012/06/28 Javascript
jquery解决图片路径不存在执行替换路径
2013/02/06 Javascript
javascript获取checkbox复选框获取选中的选项
2014/08/12 Javascript
JS运动相关知识点小结(附弹性运动示例)
2016/01/08 Javascript
JavaScript学习笔记之ES6数组方法
2016/03/25 Javascript
vue.js学习笔记:如何加载本地json文件
2017/01/17 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
bootstrap响应式导航条模板使用详解(含下拉菜单,弹出框)
2017/11/17 Javascript
js 索引下标之li集合绑定点击事件
2018/01/12 Javascript
详解Vue 多级组件透传新方法provide/inject
2018/05/09 Javascript
微信小程序6位或多位验证码密码输入框功能的实现代码
2018/05/29 Javascript
微信小程序实现留言板
2018/10/31 Javascript
小程序简单两栏瀑布流效果的实现
2019/12/18 Javascript
全局安装 Vue cli3 和 继续使用 Vue-cli2.x操作
2020/09/08 Javascript
[02:23]2018DOTA2亚洲邀请赛趣味视频——反应测试
2018/04/04 DOTA
介绍Python中内置的itertools模块
2015/04/29 Python
浅谈flask中的before_request与after_request
2018/01/20 Python
详解Python中的正斜杠与反斜杠
2019/08/09 Python
python 字典访问的三种方法小结
2019/12/05 Python
Python3 requests模块如何模仿浏览器及代理
2020/06/15 Python
Python实现http接口自动化测试的示例代码
2020/10/09 Python
matplotlib bar()实现百分比堆积柱状图
2021/02/24 Python
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
2021/03/05 HTML / CSS
乡村卫生服务一体化管理实施方案
2014/03/30 职场文书
美术专业自荐信
2014/07/07 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
就业指导讲座心得体会
2016/01/15 职场文书
2019数学教师下学期工作总结
2019/06/27 职场文书
MySQL之MyISAM存储引擎的非聚簇索引详解
2022/03/03 MySQL