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 5昨天隆重推出--PHP 5/Zend Engine 2.0新特性
Oct 09 PHP
PHP 危险函数解释 分析
Apr 22 PHP
PHP 身份证号验证函数
May 07 PHP
PHP中的函数嵌套层数限制分析
Jun 13 PHP
PHP5权威编程阅读学习笔记 附电子书下载
Jul 05 PHP
php查看请求头信息获取远程图片大小的方法分享
Dec 25 PHP
php实现TCP端口检测的方法
Apr 01 PHP
学习php设计模式 php实现桥梁模式(bridge)
Dec 07 PHP
WordPress中用于更新伪静态规则的PHP代码实例讲解
Dec 18 PHP
PHP调试及性能分析工具Xdebug详解
Feb 09 PHP
php单元测试phpunit入门实例教程
Nov 17 PHP
PHP封装curl的调用接口及常用函数详解
May 31 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
提取HTML标签
2006/10/09 PHP
php使用smtp发送支持附件的邮件示例
2014/04/13 PHP
PHP中实现crontab代码分享
2015/03/26 PHP
PHP实现的简单缓存类
2015/07/29 PHP
IE6下focus与blur错乱的解决方案
2011/07/31 Javascript
JS中批量给元素绑定事件过程中的相关问题使用闭包解决
2013/04/15 Javascript
分享一个自己写的简单的javascript分页组件
2015/02/15 Javascript
基于BootStrap栅格栏系统完成网站底部版权信息区
2016/12/23 Javascript
前端分页功能的实现以及原理(jQuery)
2017/01/22 Javascript
axios进阶实践之利用最优雅的方式写ajax请求
2017/12/20 Javascript
Vue2.0子同级组件之间数据交互方法
2018/02/28 Javascript
vue 设置proxyTable参数进行代理跨域
2018/04/09 Javascript
QRCode.js二维码生成并能长按识别
2018/10/16 Javascript
vue+element搭建后台小总结 el-dropdown下拉功能
2020/04/10 Javascript
微信小程序报错: thirdScriptError的错误问题
2020/06/19 Javascript
[00:37]DOTA2上海特级锦标赛 Secert 战队宣传片
2016/03/03 DOTA
Python的lambda匿名函数的简单介绍
2013/04/25 Python
探究数组排序提升Python程序的循环的运行效率的原因
2015/04/01 Python
利用Python获取操作系统信息实例
2016/09/02 Python
JSON Web Tokens的实现原理
2017/04/02 Python
python单向链表的基本实现与使用方法【定义、遍历、添加、删除、查找等】
2019/10/24 Python
终于搞懂了Keras中multiloss的对应关系介绍
2020/06/22 Python
利用Python将图片中扭曲矩形的复原
2020/09/07 Python
python3排序的实例方法
2020/10/20 Python
HTML5实现签到 功能
2018/10/09 HTML / CSS
爱尔兰领先的在线体育用品零售商:theGAAstore
2018/04/16 全球购物
几道PHP的面试题
2012/05/19 面试题
大学生志愿者感言
2014/01/15 职场文书
办公室主任先进事迹
2014/01/18 职场文书
产品质量承诺书
2014/03/27 职场文书
党的群众路线教育实践活动公开承诺书
2014/03/28 职场文书
设备管理实施方案
2014/05/31 职场文书
合作协议书格式
2014/08/19 职场文书
校园会短篇的广播稿
2014/10/21 职场文书
毕业生党员个人总结
2015/02/14 职场文书
三星 3nm 芯片将于第二季度开始量产
2022/04/29 数码科技