之前的一篇文章《解决Sakurairo主题无法获取评论IP的问题》提到了显示评论者IP地址的功能无法正常使用~然后使用了直接修改WordPress代码的方法来解决。但是这种方法不太稳定也不太推荐——因为一旦WordPress更新,这些修改很有可能被覆盖。所以,这篇文章的重点就在于:使用WP插件来实现同样的功能,这样在WP更新之后,这些功能依然会被保留。
WP插件原理
WP插件的原理很简单:WP项目会扫描一个文件夹,该文件夹的php文件会被加载。
在加载的文件夹内,如果自己编写一个函数,并且链接合适的钩子,那么当某个行为(例如用户发送评论)发生时,会处理钩子勾住的函数(自己添加的修正IP函数),这样就能在自己写的函数内实现对应的功能(修正评论内的IP)。
换句话说,插件的编写者不需要过多考虑自己编写的函数应该插入在流程的哪个具体位置,而更需要知道应该把自己的函数放在哪个回调中(也即和哪个钩子绑定)。这实在是很方便。
IP修正功能实现
IP修正的原理十分简单。原本的IP记录非常简单粗暴,直接是读取$_SERVER['REMOTE_ADDR']
的值。而用户的数据包可能经过层层转发,例如使用了CDN或者反向代理,此时'REMOTE_ADDR'
字段指向的值实际上是上一个转发节点的IP,而非客户端的IP;而$_SERVER
中其实会记录下转发的整个流程,于是就能得知(尽可能真实的)用户IP。这个转发的流程存储在$_SERVER['HTTP_X_FORWARDED_FOR']
中,它是一个以逗号分隔IP的字符串。因此,只需要拿到这个串,根据逗号划分为一个数组,获得头部(数组第一位)的IP,就能作为(尽可能真实的)用户IP了。
其实上述原理在前文以及说的比较清楚了。知道修正功能的原理,接下来就是如何具体实现这个插件了。
IP修正函数
知道了原理,就来实现这个函数。很简单:
function modify_comment_data($comment_id, $comment_approved) {
// 查询评论数据
$commentdata = get_comment($comment_id);
// 修改评论的ip信息,注意这里的逻辑要更改为覆盖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'];
}
// 更新评论的 IP 地址
wp_update_comment(array(
'comment_ID' => $comment_id,
'comment_author_IP' => $client_ip
));
}
add_filter('comment_post', 'modify_comment_data', 9, 2);
这里有几个要点。
- 应该假定数据已经入库,换句话说用户写下的评论以及相关不正确的IP信息以及存储到数据库,此时应该读取数据、修改、更新数据,而不是修改内存中的缓存。所以,需要配合
get_comment
以及wp_update_comment
。 - 不再判断
isset($commentdata['comment_author_IP'])
。因为数据已经入库了,IP自然已经设置了——或者说无论是否设置都不应该影响修正后的IP是否覆盖原先记录的IP。 - 函数的参数和具体需要挂钩的钩子(需要回调的函数)有关。这里的回调函数是
'comment_post'
,它的函数要求有$comment_id, $comment_approved
两个,而此处仅用到了第一个。 - 需要注意优先级。会有诸多函数挂住这个钩子。此处
9, 2
两个参数,9表示优先级为9,而2表示传入两个参数。优先级数字越小,该函数越早执行;默认优先级为10.所以这里设定优先级高于默认优先级,相对更早执行。
插件头
为了让wordpress知道这个php文件是一个插件,还需要一些特定的标识。wordpress是通过解读代码注释来识别的,换句话说不要乱写注释。文件头部应该有这些注释:
<?php
/*
Plugin Name: Comment IP Fix
Description: 橘子的评论修复补丁,能够确保评论获取正确的ip地址,尤其是使用了反向代理或者CDN的情况。
Version: 1.0
Author: citrusreticulata
*/
这些注释标识了插件名称、简介、版本号、作者。有了这些内容,才能在后台正确显示插件的信息。
激活插件
激活插件非常简单!去到管理后台,就能看到插件了!像激活其他插件一样激活它就行。如下图:
Comments NOTHING