评论区显示用户IP归属地(写数据库)

前言

前段时间给评论区增加了一个显示评论用户IP归属地的功能,实现的方式是获取评论用户的IP后,通过腾讯的API获得到IP归属地后展现出来。

https://www.rsecc.cn/753.html

https://www.rsecc.cn/760.html

利用这种方式虽然可以实现功能,但有一些小问题:

  1. 每次访问文章评论页面,都会调用腾讯的API进行一次查询,如果文章页的留言特别多,会导致页面加载变慢;
  2. 腾讯API给个人认证用户的并发量额度只有5次/秒,文章留言一多,只能查询到前几条评论的IP归属地,后面的所有评论都查询不到归属地。

于是在原有的基础上进行了一下改进,这里记录一下。

改进思路

通过查询wordpress文档,wordpress的评论有两张数据库表wp_commentwp_commentmeta

  • wp_comment表:用户存储评论信息,如评论内容、评论所属文章、评论人昵称、邮箱、URL 等
  • wp_commentmeta表:用户存储评论元数据等信息

那么这里就可以用上wp_commentmeta数据库表,在用户提交评论的时候,基于用户的IP查询到归属地后,将归属地写入到数据库表中。

写数据库表

使用wordpress自带的开发函数add_comment_meta(),该函数可以向评论添加元数据字段。

add_comment_meta( int $comment_id, string $meta_key, mixed $meta_value, bool $unique = false )

源码:

function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
    return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
}

来源:https://www.wp2.cn/functions/get_comment_meta/

前端调用

前端需要显示就直接使用评论ID查询数据就可以得知归属地,这样一来就可以解决之前的两个问题了。

get_comment_meta( int $comment_id, string $key = ”, bool $single = false )


源码:

function get_comment_meta($comment_id, $key = '', $single = false) {
    return get_metadata('comment', $comment_id, $key, $single);
}

来源:https://www.wp2.cn/functions/get_comment_meta/

小问题

但随之而来的问题就是,只有新评论才会显示归属地,旧的评论无法显示,这里提供一个解决思路:

  1. 将旧评论的IP查询到归属地手工新增到数据库中(比较麻烦);
  2. 旧评论还使用之前的方式显示归属地(我是这么做的);
  3. 删掉所得旧评论(不建议)。

实现代码

只针对CorePress-pro主题,其他主题自行测试。

第一步:开启CorePress-pro主题子主题功能,在子主题的functions.php文件中插入如下代码,原有内容不变,如果已经在使用之前的方法的,将include("get_user_address.php");删除。

//调用腾讯API基于IP获取IP归属地
function province($user_ip) {
    if (filter_var($user_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_IPV4)) {
        if (filter_var($user_ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            $url = "https://apis.map.qq.com/ws/location/v1/ip?key=【腾讯API Key,不要方括号】&ip=" . $user_ip;
            $UserAgent = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)';
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($curl, CURLOPT_ENCODING, '');
            curl_setopt($curl, CURLOPT_USERAGENT, $UserAgent);
            curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
            $data = curl_exec($curl);
            $data = json_decode($data, true);
            $result = array_column($data, 'ad_info');
            $nation = array_column($result, 'nation'); // 获取国家
            $nation = array_shift($nation); // 获取国家
            $province = array_column($result, 'province'); // 获取省份
            $province = array_shift($province); // 获取省份
            $ad_info = $nation == "中国" ? $province : $nation; // 判断,如果国家为中国,则显示省,否则显示国家
            $ad_info = isset($ad_info) ? $ad_info : "未知IP";
            return $ad_info;
        } else {
            return "私网用户";
        }
    } else {
        return "未知IP";
    }
}

//获取归属地并写入数据库
function add_comment_ipterritory($comment_id) {
        $ipterritory = province($_SERVER['REMOTE_ADDR']);
        $ipterritory = isset($ipterritory) ? wp_filter_nohtml_kses($ipterritory) : "未知IP";
        add_comment_meta($comment_id, '_ipterritory', $ipterritory);
}
add_action ('comment_post', 'add_comment_ipterritory');

//后台增加归属地字段
function my_comments_columns( $columns ){
    $columns[ '_ipterritory' ] = __( 'IP归属地' );        
    return $columns;
}
function  output_my_comments_columns( $column_name, $comment_id ){
    switch( $column_name ){
    case '_ipterritory';
    echo get_comment_meta( $comment_id, '_ipterritory', true );
    break;
}}
add_filter( 'manage_edit-comments_columns', 'my_comments_columns' );
add_action( 'manage_comments_custom_column', 'output_my_comments_columns', 10, 2 );

第二步:在主题下的 geekframe/comment-pro.php 文件中合适位置加入如下代码。

· <a style='color:#07C160'><?php $ipterritory = get_comment_meta($comment->comment_ID,'_ipterritory',true);echo empty($ipterritory)? province(get_comment_author_ip()) : $ipterritory ;?></a>

最后

抛砖引入,有不同的想法的欢迎留言评论交流。


THE END