ipv6解析地理位置

  • 背景
  • 设计思路
  • 代码实现

背景

在不借助第三方工具的前提下,实现IP高效定位地理位置(这里以ipv6为例子)

设计思路

  • 需要将IP转换成一个整数类型
  • 根据IP文件(ipv6.txt)生成一个索引文件
    • head:存储IP索引的起始偏移量和结束偏移量:起始偏移量和结束偏移量各占4个字节,共8个字节
    • data:存储IP的详细信息,长度根据ipv6的具体数据大小决定,结束时用\x00提示
    • index:索引信息,起始IP的值(38个字节)和详细信息的位置偏移量(4个字节),共42个字节
  • 使用二分查找法对比查找IP和IP文件中的IP范围
    • 首先获取head中内容,得到起始和结束索引的位置偏移量
    • 然后根据这个偏移量获取到IP的索引位置,加上二分法通过与起始IP对比
    • 找到后通过位置偏移量获取到最终地理位置

代码实现

<?php
class Ug_Util_Ipsss {private $forceReForm        = false; // 是否强制重新生成索引文件private $filename           = "/colombo_ipv6lib.txt"; //保存IP地址的文件private $head               = array(); // 0起始IP的文件开始位置,1起始IP的文件结束位置private $index              = array();private $data               = array(); //数据信息的位置private $start_data_offset  = 8; // 起始偏移量private $index_len          = 0; // 索引长度CONST  READ_64bit_OFFSET    = 9;CONST  READ_32bit_OFFSET    = 5;CONST  EVERY_INDEX_OFFSET   = 42;/*** @description 初始化文件* @param $filename* @param $forceReForm*/public function __construct($filename = "", $forceReForm = false){//变量赋值$this->filename = empty($filename) ? $this->filename : $filename;$this->forceReForm = $forceReForm;$this->formatFile = "/ipv6";//若强制重新生成索引标志为真或者不存在索引文件,则重新生成if ($this->forceReForm || !file_exists($this->formatFile)) {$this->ipv6FormatFile();}}/*** @description 用txt文件生成索引文件**/private function ipv6FormatFile(){//读源文件,写入到新的索引文件$readfd = fopen($this->filename, 'rb');$writefd = fopen($this->formatFile.'_tmp', 'wb+');if ($readfd === false || $writefd === false) {return false;}while (!feof($readfd)) {$line = fgets($readfd);if (empty($line)) {continue;}$line_items = explode("|", $line);//将起始IP转换为数字if(filter_var($line_items[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {$start_ip = $this->ipv6ToInt($line_items[0]);} else {$start_ip = intval($line_items[0]);}//将结束IP转换为数字if(filter_var($line_items[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {$line_items[1] = pack("A38", $this->ipv6ToInt($line_items[1]));} else {$line_items[1] = pack("A38", intval($line_items[1]));}//删除起始IPunset($line_items[0]);//1. 构造索引内容ip+该ip对应数据所存储的偏移量//2. 头索引:索引内容 的偏移量,所以每次起始的数据偏移量要增加数据的长度$tmp_index_offset = pack("A38L",$start_ip,$this->start_data_offset);array_push($this->index, $tmp_index_offset);$tmp_data = implode("|", $line_items) . '\x00';array_push($this->data, $tmp_data);$this->index_len = $this->index_len + strlen($tmp_index_offset);$this->start_data_offset = $this->start_data_offset + strlen($tmp_data);}array_push($this->head, pack("L", $this->start_data_offset));array_push($this->head, pack("L", $this->index_len + $this->start_data_offset - 8));//将数据写到临时文件中$this->write_array($writefd, $this->head);$this->write_array($writefd, $this->data);$this->write_array($writefd, $this->index);fclose($readfd);fclose($writefd);rename($this->formatFile.'_tmp', $this->formatFile);return true;}public function searchIpv6($ip = ""){$output = array("valid"=>false, "info"=>array(), "error_msg"=>"");$fd = fopen($this->formatFile, "rb");if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {$search_int_ip = $this->ipv6ToInt($ip);} else {return false;}//1. 读取head里面的偏移量信息$head = unpack("Lleft/Lright", fgets($fd, 9));$left = $head['left'];$right = $head['right'];while ($left <= $right) {//计算索引个数$index_count = ($right-$left+self::EVERY_INDEX_OFFSET)/self::EVERY_INDEX_OFFSET;$index_middle = intval($index_count/2) < 1 ? 1 : intval($index_count/2);$offset_middle = $left + ($index_middle - 1) * self::EVERY_INDEX_OFFSET ;fseek($fd, $offset_middle, SEEK_SET);//获取起始IP和详细信息的偏移量//在这里读取的时候要用fread,fget读取会出错$info = unpack("A38tmp_ip/Ltmp_offset", fread($fd, 43));$start_ip = $info['tmp_ip'];//读取结束IP的值fseek($fd, $info['tmp_offset'], SEEK_SET);$end_ip = unpack("A38ip", fread($fd, 39))['ip'];if (bcsub($search_int_ip,$start_ip,0) < 0) {$right = $offset_middle - self::EVERY_INDEX_OFFSET_IPV6;} elseif (bcsub($search_int_ip,$end_ip,0) > 0){$left = $offset_middle + self::EVERY_INDEX_OFFSET_IPV6;} else {$info_detail= fgets($fd);$output['valid'] = true;$output['info'] = explode("|", $info_detail);$output['info'][count($output['info']) - 1] =trim($output['info'][count($output['info']) - 1], PHP_EOL);unset($output['info'][0]);goto final_out;}}fclose($fd);$output['valid'] = false;$output['info'] = "NO IP FOUND";final_out:return $output;}/*** @description 将IPv4地址转换为整型* @param string $ip* @return int*/private function ip2int($ip){return sprintf("%u", ip2long($ip));}/*** @description 将IPv6地址转换为string (int会溢出)* @param string $ip* @return int*/public function ipv6ToInt($ip) {$str = '';foreach (unpack('C*', inet_pton($ip)) as $byte) {$str .= str_pad(decbin($byte), 8, '0', STR_PAD_LEFT);}$str = ltrim($str, '0');if (function_exists('bcadd')) {$numeric = 0;for ($i = 0; $i < strlen($str); $i++) {$right = base_convert($str[$i], 2, 10);$numeric = bcadd(bcmul($numeric, 2), $right);}$str = $numeric;} else {$str = base_convert($str, 2, 10);}return $str;}}

ipv6解析地理位置相关推荐

  1. hive UDF 根据ip解析地理位置信息

    hive UDF 根据ip查询对应地理位置信息 hive UDF 根据ip查询对应地理位置信息 具体实现 源码 hive UDF 根据ip查询对应地理位置信息 最终效果 具体可返回信息:洲,国家,省, ...

  2. java通过IP解析地理位置

    java通过IP解析地理位置 文章目录 java通过IP解析地理位置 一.获取IP地址 二.百度普通IP定位API获取地理位置 在项目开发中,需要在登录日志或者操作日志中记录客户端ip所在的地理位置. ...

  3. 伪装浏览器根据经纬度解析地理位置

    #!/usr/bin/env python # -*- coding: utf-8 -*-""" 作者:昨夜星辰 脚本作用:伪装浏览器根据经纬度解析地理位置 创建时间:2 ...

  4. 小米AX9000 docker ddns-go腾讯云 实现ipv6解析 注意事项

    第一次安装ddns-go后,解析时始终无法解析ipv6,经研究在网络设置有注意事项如下: 一.根据作者的使用说明,在docker中运行选择host模式即可实现ipv4/ipv6解析. 二.docker ...

  5. 域名通过ipv6解析SSL协议无法访问

    最近出现一个很奇怪的现象,服务器系统是winodws2008R2 ,nginx1.19版本,端口7001, 因为是二级域名使用,443端口改成7001了,配置好所有配置,启动服务,测试一切正常, 在同 ...

  6. linux ipv6动态解析,家庭宽带ipv6搭建外网访问方案,ddns动态解析ipv6,ipv6建站等

    注意:ipv6和ipv4之间不可互相访问!!! 如题: 1.先确认我们本地是否有公网ipv6地址 Windows查看方法:打开cmd.输入ipconfig 看到有2开头的就是公网ipv6了 linux ...

  7. nginx 反向代理 解析域名变成ipv6

    今天碰到一个问题,反向代理的域名解析成ipv6了,然后主机不通ipv6,就导致有时候能访问有时候链接超时的诡异情况 解决方法1:通过关闭主机的ipv6来实现 图解centos7如何关闭ipv6仅使用i ...

  8. 开启 Cloudflare CDN 代理,实现 IPv4 to IPv6 转换

    开启 Cloudflare CDN 代理,实现 IPv4 to IPv6 转换 通过公网IPv6地址实现远程访问专栏系列文章: <使用公网IPv6远程访问内网设备> <DDNS动态域 ...

  9. 走向IPv6,阿里巴巴IPv6规模化部署实践

    作者:IPv6项目组 IPv6是互联网升级演进的必然趋势,我国主流APP也正式进入到IPv4和IPv6的双栈时代.本文将从APP及云产品的角度,和大家分享一下我们在这个过程中的经验积累,为进一步推动I ...

  10. 记录一次nginx升级,支持ipv4和ipv6访问https

    项目要求,需要让现有网站项目支持https,并同时支持ipv6访问,经过分析,现在nginx版本较老,所以决定升级nignx,并且同步配置https和ipv6. 升级准备 服务器网络环境需要支持ipv ...

最新文章

  1. 机器学习与高维信息检索 - Note 4 - 主成分分析及其现代解释(Principal Component Analysis, PCA)及相关实例
  2. Python开发【第三篇】:Python基本数据类型
  3. Android-应用性能测试
  4. 《深度学习的数学》笔记【各种概念】
  5. 几种添加系统环境变量方法和区别
  6. 用官方2012版本131兆,一共有四个自带软件
  7. MyBatis 架构分层与模块划分
  8. DNS DHCP 路由 FTP
  9. java 接口 安全加密_Java中的安全加密
  10. 门槛回归模型_stata15:门槛模型
  11. 普通循环和numpy速率对比
  12. android切图双数,UI切图与命名规范
  13. 全国计算机等级考试怎么卸载,教你三种方法卸载Windows7SP1Beta
  14. 7-11 机工士姆斯塔迪奥(PTA程序设计)
  15. C#VS工程报错:CS0234 命名空间“Microsoft.VisualStudio”中不存在类型或命名空间名“VCProjectEngine(是否缺少程序集引用)
  16. 速看——揭秘“微商”的盈利模式
  17. 最近经常看到网上程序员被抓,如何避免面向监狱编程!?
  18. 这些食物让人越吃越聪明!
  19. 【表白神器】Python超火隐藏表白图 你能看出来吗?【附源码】
  20. 路由算法之——ECMP算法

热门文章

  1. indesign安装包.exe 自动简繁互转for_InDesign 简繁互换插件
  2. 【c++11并不遥远】使xcode工程支持c++11特性
  3. 在SQL Sever中使用form membership认证
  4. c语言编程中句柄无效怎么解决,句柄无效,小编教你句柄无效怎么解决
  5. 笔记本电脑热点手机无法连接解决方案
  6. 以计算机网络为中介的人际传播,人际传播在传媒中的运用
  7. 二层交换机与路由器的区别
  8. java POST接口报错417
  9. 改进YOLOv7系列:24.添加SimAM注意力机制
  10. 基于java的超市会员积分管理系统