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模拟HTTP认证
Oct 09 PHP
PHP正则的Unknown Modifier错误解决方法
Mar 02 PHP
PHP读取数据库并按照中文名称进行排序实现代码
Jan 29 PHP
win7+apache+php+mysql环境配置操作详解
Jun 10 PHP
php技术实现加载字体并保存成图片
Jul 27 PHP
yii去掉必填项中星号的方法
Dec 28 PHP
CI框架数据库查询缓存优化的方法
Nov 21 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
Aug 01 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
Sep 16 PHP
Laravel框架实现多数据库连接操作详解
Jul 12 PHP
laravel 根据不同组织加载不同视图的实现
Oct 14 PHP
tp5框架基于ajax实现异步删除图片的方法示例
Feb 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数组相加 array(“a”)+array(“b”)结果还是array(“a”)
2012/09/19 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
php+javascript实现的动态显示服务器运行程序进度条功能示例
2017/08/07 PHP
调试php程序的简单步骤
2019/10/04 PHP
php查看一个变量的占用内存的实例代码
2020/03/29 PHP
BOOM vs RR BO3 第二场2.13
2021/03/10 DOTA
javascript之对系统的toFixed()方法的修正
2007/05/08 Javascript
javaScript 页面自动加载事件详解
2014/02/10 Javascript
不到30行JS代码实现Excel表格的方法
2014/11/15 Javascript
JS实现自动固定顶部的悬浮菜单栏效果
2015/09/16 Javascript
javascript HTML5文件上传FileReader API
2020/03/27 Javascript
jQuery添加options点击事件并传值实例代码
2016/05/18 Javascript
Html中 IFrame的用法及注意点
2016/12/22 Javascript
Angular在一个页面中使用两个ng-app的方法
2017/02/20 Javascript
在小程序Canvas中使用measureText的方法示例
2018/10/19 Javascript
element-ui中Table表格省市区合并单元格的方法实现
2019/08/07 Javascript
如何使用proxy实现一个简单完整的MVVM库的示例代码
2019/09/17 Javascript
微信小程序实现注册登录功能(表单校验、错误提示)
2019/12/10 Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
2020/09/09 Javascript
node.js如何根据URL返回指定的图片详解
2020/10/21 Javascript
浅谈vue在html中出现{{}}的原因及解决方式
2020/11/16 Javascript
python进阶教程之动态类型详解
2014/08/30 Python
利用Python-iGraph如何绘制贴吧/微博的好友关系图详解
2017/11/02 Python
Python 硬币兑换问题
2019/07/29 Python
Sony C++笔试题
2013/03/10 面试题
法学毕业生自荐信
2013/11/13 职场文书
廉政教育心得体会
2014/01/01 职场文书
项目开发计划书
2014/01/09 职场文书
院领导写的就业推荐信
2014/03/09 职场文书
国庆宣传标语
2014/06/30 职场文书
刑事上诉状(量刑过重)
2015/05/23 职场文书
2016年春季运动会广播稿
2015/08/19 职场文书
高中生物教学反思
2016/02/20 职场文书
2016年小学党支部创先争优活动总结
2016/04/05 职场文书
劳务派遣管理制度(样本)
2019/08/23 职场文书
MySQL官方导出工具mysqlpump的使用
2021/05/21 MySQL