使用CF的CDN后,发现ip地址清一色的美国,后来才想起来访客ip这回事。
实际上服务器会得到访客的真实ip,只不过typecho获取ip的方法会默认先得到cdn的ip。
按网络的方法:
https://kotori.love/archives/typecho-plugin-access.html
在typecho的config.inc.php中配置define('__TYPECHO_IP_SOURCE__', 'HTTP_CF_CONNECTING_IP');
完全OK...
如果是其他cdn,可以在主页根目录下新建info.php
内容是<?php phpinfo(); ?>
然后访问你的网址/info.php
就能看到详细信息,在PHP Variables
这个部分有访问的记录
我用的是CF,有$_SERVER['HTTP_CF_CONNECTING_IP']这样的字段,同时$_SERVER['HTTP_X_FORWARDED_FOR']这个字段也是真实ip,那么就可以按前面说的那样在config.inc.php添加配置,优先通过这个地方获取ip,那么就可以正常显示访客ip了。
不过数据库中Access插件的ip对于ipv6全部为0。
看了下源代码,作者使用的是ip2long和long2ip来处理ip,这对于ipv6没法正确处理。
在Access_Core.php中可以看到如下代码:
public function long2ip($long) {
if ($long < 0 || $long > 4294967295) return false;
$ip = "";
for ($i=3;$i>=0;$i--) {
$ip .= (int)($long / pow(256,$i));
$long -= (int)($long / pow(256,$i))*pow(256,$i);
if ($i>0) $ip .= ".";
}
return $ip;
}
long传入是ip转换后的十进制数,ipv6转换后大于4294967295,然后一系列的值就置0了。
根据官方文档,对于ipv6有人给出ip2bin和bin2ip的函数,如下:
function ip2bin($ip)
{
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false)
return base_convert(ip2long($ip),10,2);
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false)
return false;
if(($ip_n = inet_pton($ip)) === false) return false;
$bits = 15; // 16 x 8 bit = 128bit (ipv6)
while ($bits >= 0)
{
$bin = sprintf("%08b",(ord($ip_n[$bits])));
$ipbin = $bin.$ipbin;
$bits--;
}
return $ipbin;
}
function bin2ip($bin)
{
if(strlen($bin) <= 32) // 32bits (ipv4)
return long2ip(base_convert($bin,2,10));
if(strlen($bin) != 128)
return false;
$pad = 128 - strlen($bin);
for ($i = 1; $i <= $pad; $i++)
{
$bin = "0".$bin;
}
$bits = 0;
while ($bits <= 7)
{
$bin_part = substr($bin,($bits*16),16);
$ipv6 .= dechex(bindec($bin_part)).":";
$bits++;
}
return inet_ntop(inet_pton(substr($ipv6,0,-1)));
}
动手尝试更改了源代码,但是有些小问题,本身不懂php也不敢多折腾,暂时先不改...
tip:数据库ip的类型也需要更改。
在github的issue里面有ipv6显示正常的图,不过那里的ip的类型是varchar,目前的新版本又是int(32)。
相关链接:
https://kotori.love/archives/typecho-plugin-access.html?c
http://blog.lanyus.com/archives/323.html
https://github.com/kokororin/typecho-plugin-Access
http://php.net/manual/zh/function.ip2long.php