解决Sakurairo主题无法获取评论IP的问题

橘子 发布于 22 天前 92 次阅读


Sakurairo主题提供了一个有趣的小功能,就是显示评论者的IP地址~(这个功能的介绍可以戳这个文档

但是这就尴尬了,这个功能就没成功展示过("▔□▔)/全部都显示的是“来自: Reserved Address”

翻了一下文档,文档里面是这么写的:

显示Reserved Address,表示获取到的用户地址是一个私有地址。如果启用了反向代理,你需要进行额外的操作才能获取到用户的真实IP地址,请查阅其他资料以获得支持。

Σ(゚д゚;)我确实使用了反向代理啊!老习惯了,毕竟这样可以用ngnix管理流量,让同一个域名下挂不同服务,还能解析套娃(什么自己造的奇怪名词

( ̄□ ̄||)这就难办了,得想办法解决这个问题。既然文档已经提示了这个问题,我估摸着用这个主题的好朋友们应该主要是挂网页博客,也就不需要做流量转发之类的操作,这些可能也没处理。所以打算自己翻翻代码看看能不能找到什么解决办法,说不定还能提一个PR嘿嘿(=・ω・=)

Sakurairo主题中是如何获取评论IP的

这个问题很重要,Sakurairo主题中是如何获取评论IP的呢?先不管这个问题,直接去读代码,大概会读到functions.php里面的这段代码(啊,源代码注释就是这样的哦):

// 显示访客当前 IP
function get_the_user_ip()
{
    // if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    //     //check ip from share internet
    //     $ip = $_SERVER['HTTP_CLIENT_IP'];
    // } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    //     //to check ip is pass from proxy
    //     $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    // } else {
    //     $ip = $_SERVER['REMOTE_ADDR'];
    // }
    // 简略版
    // $ip = $_SERVER['HTTP_CLIENT_IP'] ?: ($_SERVER['HTTP_X_FORWARDED_FOR'] ?: $_SERVER['REMOTE_ADDR']);
    $ip = $_SERVER['HTTP_CLIENT_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
    return apply_filters('wpb_get_ip', $ip);
}

( σ'ω')σ某个笨蛋橘子先入为主的认为,这段代码就是获取用户IP的嘛(毕竟注释就是这么写的),那肯定评论IP肯定也用的这个了!但其实不是,这个函数应该是处理其他内容的(我猜,可能是挂在页面某个位置显示访问者的ip什么的)〒▽〒

真正的处理评论者IP的是IpLocation.php文件里面的下面这个函数:

/**
     * 通过评论ID获取IP地理位置信息,当数据库里不存在IP地理位置信息时会自动请求接口获取
     *
     * @param int $comment_id 评论ID
     * @return string 成功时返回IP地理位置信息:“国家 地区(省份) 城市”;失败时返回“Unknown”或“Reserved Address”或“Empty Address”
     */
    public static function getIpLocationByCommentId(int $commentId)
    {
        $ipLocation = get_comment_meta($commentId, 'iro_ip_location', true);
        if ($ipLocation) {
            $location = new IpLocationParse($ipLocation);
            return $location->getLocationConcision();
        } else {
            // 解析IP地址地理位置
            $commentIp = get_comment_author_IP($commentId);
            if (!empty($commentIp)) {
                if (IPLocation::checkIpValid($commentIp)) {
                    $ipLocation = new IPLocation($commentIp);
                    $location = $ipLocation->getLocation();
                    // 记录IP地理位置信息
                    if ($location) {
                        if (iro_opt('save_location')) add_comment_meta($commentId, 'iro_ip_location', $location);
                        $locationParse = new IpLocationParse($location);
                        return $locationParse->getLocationConcision();
                    } else {
                        return __('Unknown');
                    }
                } else {
                    return __('Reserved Address');
                }
            } else {
                return __('Empty Address');
            }
        }
    }

哎呀,看到这个'Reserved Address'关键字那橘子可是两眼放光Σ(っ °Д °;)っ这不正是我遇到的问题吗,其中的关键,正在于这句:$commentIp = get_comment_author_IP($commentId);这意味着,Sakurairo主题是直接从底层框架提供的API中,直接读取存储的IP信息。具体的api位于这个文件中:/wp-includes/comment.php,其中涉及到的记录代码很容易就能搜索到,如下:

if ( ! isset( $commentdata['comment_author_IP'] ) ) {
	$commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
}

修改Wordpress代码解决问题

这就是问题所在了!!!w(゚Д゚)w 他没有关心任何代理,直接读取的REMOTE_ADDR!!!所以才会出毛病啊啊啊,由于Sakurairo主题总是从该接口获取对应的已经存储的IP地址,因此无法进一步分析用户的真实IP!!!

(つд⊂)这下好了,本以为可以给Sakurairo项目提PR了,没想到是Wordpress本身的锅。(其实我之前直接忽略了这层,因为我用到的其他插件,是能正确获取挂了反向代理的IP的,所以我就首先怀疑是主题这边的问题)

给这段代码稍作修改,如下:

if ( ! isset( $commentdata['comment_author_IP'] ) ) {
	if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
		$ip_addresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
		$client_ip = trim($ip_addresses[0]);
	} else {
		$client_ip = $_SERVER['REMOTE_ADDR'];
	}
	$commentdata['comment_author_IP'] = $client_ip;
	// $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
}

然后就成功啦!!!ヾ(≧▽≦*)o现在能正确获取到评论者的IP信息啦!

此外,某些帖子可能会给出这种解决方法,那就是在wp-config.php中添加下面这段代码:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip_addresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $client_ip = trim($ip_addresses[0]);
} else {
    $client_ip = $_SERVER['REMOTE_ADDR'];
}

( _ _)ノ|但是,没用的。这是推测这是因为在 wp-config.php 中修改的 $client_ip 变量是在全局作用域中的,但它的作用域仅限于 wp-config.php 文件以及加载 wp-config.php 的过程。当 WordPress 加载完毕时,wp-config.php 中设置的变量可能已经失效或无法直接在 WordPress 的其他文件中访问,除非你显式地将它们传递给其他部分。如果一定到这么用,或许可以这样做(吉皮特老师这么说的):

// 在需要使用 $client_ip 的地方,使用 global 关键字
add_action('init', function() {
    global $client_ip;
    // 使用 $client_ip 进行处理
});

至此,问题解决![]~( ̄▽ ̄)~*