WordPress 处理一条评论的流程是:
访客提交 → 打包成 $comment 数组 → 【preprocess_comment 钩子】→ 入库 → 前台显示
preprocess_comment 是入库之前的最后一个拦截点。想拦垃圾评论,就挂这里。
(我之前写过一篇讲具体实战的,这里只讲写法要点。)
caogenbj 原来的过滤是这样的:
function wpb_preprocess_comment($comment) {
$txt = strstr($comment['comment_content'],"http");
if ( strlen( $comment['comment_content'] ) > 350 ) {
wp_die('你的字数太长了……');
}
elseif($txt != false){
wp_die('包含了非法字符:http');
}
return $comment;
}
它只查了评论正文里有没有 http。但垃圾评论会把链接填在“网址”那一栏,正文只写“555”。
结果:全部放行。
完整的过滤应该查五处:
function wpb_preprocess_comment( $comment ) {
// 管理员自己评论不受限制
if ( is_user_logged_in() && current_user_can( 'manage_options' ) ) {
return $comment;
}
$content = $comment['comment_content'];
$url = trim( $comment['comment_author_url'] );
$email = $comment['comment_author_email'];
// 1. 网址栏不允许填
if ( '' !== $url && 'http://' !== $url && 'https://' !== $url ) {
wp_die( '请不要在“网址”一栏填写链接。' );
}
// 2. 正文不允许出现网址
if ( preg_match( '/https?:\/\/|www\./i', $content ) ) {
wp_die( '评论内容中不能包含网址链接。' );
}
// 3. 正文太短
if ( mb_strlen( trim( wp_strip_all_tags( $content ) ), 'UTF-8' ) < 5 ) {
wp_die( '内容太短,请至少写 5 个字。' );
}
// 4. 正文过长
if ( strlen( $content ) > 350 ) {
wp_die( '内容过长,请精简。' );
}
// 5. 测试邮箱
if ( '' !== $email && preg_match( '/@(example|test|localhost)\./i', $email ) ) {
wp_die( '请填写真实的邮箱地址。' );
}
return $comment;
}
浏览器的表单自动填充,会在网址栏预塞一个 http://。访客其实什么都没填,但值是 http://。
如果只判“非空”,会误伤大量正常访客。所以这三个都算“没填”:空字符串、http://、https://。
一个汉字在 UTF-8 里占 3 个字节。strlen('你好') 是 6,mb_strlen 是 2。
判断“少于 5 个字”,必须用 mb_strlen,否则两个汉字就被当成“合格”了。
你自己回复读者时可能要贴链接。如果管理员也被拦,就没法正常回复了。
current_user_can('manage_options') 判断的是“管理员权限”,不是“已登录”。这样普通注册用户还是会被拦。
过滤只是“减少垃圾”,不是“消灭垃圾”。真正省事的做法是:
过滤是防线,审核是兜底。两个一起用才稳。
一句话记住:preprocess_comment 是入库前最后的拦截点;要查网址栏、正文链接、长度上下限、测试邮箱,管理员放行。
下一篇讲安全:转义。