百度、微博、抖音、知乎、小红书都上线了评论IP属地功能,国内显示到省份/地区,国外显示到国家,且用户无法关闭该功能。

跟风一下,本站已经添加上了这个IP归属地功能。下面将代码分享给有需要的朋友


第一步

将下方代码放入主题的 functions.php 文件中

/** 获取评论者地址 */
function convertip($ip){
  $ip1num = 0;
  $ip2num = 0;
  $ipAddr1 ="";
  $ipAddr2 ="";
  $dat_path = './qqwry.dat';
  if(!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip)) {
    return 'IP 数据库路径不对';
  }
  if(!$fd = @fopen($dat_path, 'rb')){
    return 'IP 数据库路径不正确';
  }
  $ip = explode('.', $ip);
  $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
  $DataBegin = fread($fd, 4);
  $DataEnd = fread($fd, 4);
  $ipbegin = implode('', unpack('L', $DataBegin));
  if($ipbegin < 0) $ipbegin += pow(2, 32);
    $ipend = implode('', unpack('L', $DataEnd));
  if($ipend < 0) $ipend += pow(2, 32);
    $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
  $BeginNum = 0;
  $EndNum = $ipAllNum;
  while($ip1num>$ipNum || $ip2num<$ipNum) {
    $Middle= intval(($EndNum + $BeginNum) / 2);
    fseek($fd, $ipbegin + 7 * $Middle);
    $ipData1 = fread($fd, 4);
    if(strlen($ipData1) < 4) {
      fclose($fd);
      return 'System Error';
    }
    $ip1num = implode('', unpack('L', $ipData1));
    if($ip1num < 0) $ip1num += pow(2, 32);

    if($ip1num > $ipNum) {
      $EndNum = $Middle;
      continue;
    }
    $DataSeek = fread($fd, 3);
    if(strlen($DataSeek) < 3) {
      fclose($fd);
      return 'System Error';
    }
    $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
    fseek($fd, $DataSeek);
    $ipData2 = fread($fd, 4);
    if(strlen($ipData2) < 4) {
      fclose($fd);
      return 'System Error';
    }
    $ip2num = implode('', unpack('L', $ipData2));
    if($ip2num < 0) $ip2num += pow(2, 32);
      if($ip2num < $ipNum) {
        if($Middle == $BeginNum) {
          fclose($fd);
          return 'Unknown';
        }
        $BeginNum = $Middle;
      }
    }
    $ipFlag = fread($fd, 1);
    if($ipFlag == chr(1)) {
      $ipSeek = fread($fd, 3);
      if(strlen($ipSeek) < 3) {
        fclose($fd);
        return 'System Error';
      }
      $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
      fseek($fd, $ipSeek);
      $ipFlag = fread($fd, 1);
    }
    if($ipFlag == chr(2)) {
      $AddrSeek = fread($fd, 3);
      if(strlen($AddrSeek) < 3) {
      fclose($fd);
      return 'System Error';
    }
    $ipFlag = fread($fd, 1);
    if($ipFlag == 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))
    $ipAddr2 .= $char;
    $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
    fseek($fd, $AddrSeek);
    while(($char = fread($fd, 1)) != chr(0))
    $ipAddr1 .= $char;
  } else {
    fseek($fd, -1, SEEK_CUR);
    while(($char = fread($fd, 1)) != chr(0))
    $ipAddr1 .= $char;
    $ipFlag = fread($fd, 1);
    if($ipFlag == 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)){
      $ipAddr2 .= $char;
    }
  }
  fclose($fd);
  if(preg_match('/http/i', $ipAddr2)) {
    $ipAddr2 = '';
  }
  $ipaddr = "$ipAddr1 $ipAddr2";
  $ipaddr = preg_replace('/CZ88.NET/is', '', $ipaddr);
  $ipaddr = preg_replace('/^s*/is', '', $ipaddr);
  $ipaddr = preg_replace('/s*$/is', '', $ipaddr);
  if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
    $ipaddr = '可能来自火星';
  }
  $ipaddr = iconv('gbk', 'utf-8//IGNORE', $ipaddr);
  return $ipaddr;
}

PS:只显示地区,不显示后面的网络,请把 $ipaddr = "$ipAddr1 $ipAddr2"; 改为 $ipaddr = "$ipAddr1"; 即可。


第二步

下载 QQWry.Dat 放在网站根目录,注意是网站根目录!!!不是主题目录。

下载地址:QQwry.Dat


第三步

添加完成后,再次打开主题评论模板 comments.php 文件,在您想显示的位置加上如下代码。

<?php echo convertip($comments->ip); ?>

第四步

Typecho配置CDN后获取访客真实IP地址可能会受到影响,请在Typecho站点根目录里的 config.inc.php 添加下面这段代码即可。有的虚拟主机会自带CDN,所以哪怕没有配置CDN,只要不能正常显示,也可以尝试插入以下代码。

//绕过 CDN 代理IP获取客户真实IP地址
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $list[0];
}

第五步

效果图:

效果图
效果图

至此,所有教程完毕。