AI 智能摘要
为了有效解决这一问题,我们可以为WordPress的搜索功能添加一个频率限制机制。以下代码提供了一个完善的解决方案,它允许您设置在特定时间窗口内允许的最大搜索次数,并在超过限制时自动封禁该IP一段时间。这里主题铺分享一下无插件限制WordPress搜索频率图文教程,保护服务器免受恶意刷搜攻击。
WordPress的搜索功能虽然方便用户查找内容,但如果被恶意用户或机器人频繁刷搜,可能会导致服务器CPU使用率和负载状态瞬间飙升至100%爆满,严重影响网站的正常运行和用户体验。尤其是在共享主机环境下,这种资源耗尽的情况更为常见。
为了有效解决这一问题,我们可以为WordPress的搜索功能添加一个频率限制机制。以下代码提供了一个完善的解决方案,它允许您设置在特定时间窗口内允许的最大搜索次数,并在超过限制时自动封禁该IP一段时间。这里主题铺分享一下无插件限制WordPress搜索频率图文教程,保护服务器免受恶意刷搜攻击。
函数功能说明
这段PHP代码通过WordPress的pre_get_posts钩子来拦截搜索请求,并利用WordPress的缓存机制(wp_cache)来记录用户的搜索行为和封禁状态。
主要功能点:
- 自定义配置: 您可以根据网站的实际需求,灵活调整以下参数:
$search_limit_count:在指定时间窗口内,允许的最大搜索次数。$time_window_in_minutes:时间窗口的长度,以分钟为单位(您可以修改代码将其改为秒)。$block_time_in_seconds:当用户超过搜索限制后,该IP将被封禁的时间,以秒为单位。$block_message:当IP被封禁时,向用户显示的提示信息。
- IP识别: 准确获取访问者的IP地址,支持通过
HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR或REMOTE_ADDR获取,以应对CDN或代理服务。 - 搜索请求拦截: 在执行搜索查询之前,检查访问IP是否已被封禁或是否达到搜索频率限制。
- 友好的封禁提示: 如果IP被封禁,会向用户显示一个包含剩余封禁时间的提示页面(HTTP状态码429 Too Many Requests),告知其稍后再试。
- 全站提示(可选): 即使在非搜索页面,如果IP仍处于封禁状态,也会在页面顶部显示一个轻量级的提示条,告知用户其搜索功能受限。
- 缓存机制: 利用
wp_cache_set和wp_cache_get来存储IP的搜索记录和封禁状态,高效且不依赖数据库,减少服务器负担。
如何将代码部署到WordPress子比主题(或其他WordPress主题)
将以下PHP代码添加到您的WordPress主题的functions.php文件中。如果您使用的是WordPress子比主题,通常建议将其添加到子主题的functions.php中,或者WordPress子比主题提供的func.php文件中,以避免主题更新时代码被覆盖。
<?php
// 主题铺提醒:如果您的主题已定义了<?php标签,请勿重复添加
class WXS_SearchFrequencyLimit {
// 配置参数可根据需要修改
private $search_limit_count = 3; // 允许的最大搜索次数
private $time_window_in_minutes = 1; // 时间窗口(分钟),可根据需求修改为秒
private $block_time_in_seconds = 60; // 超过限制后封禁时间(秒),建议与时间窗口时长一致
private $block_message = '您的搜索频率过高,请在 %d 秒后再试。'; // 封禁提示消息
public function __construct() {
// 注册钩子,在WordPress加载主查询之前检查搜索频率
add_filter( 'pre_get_posts', array( $this, 'check_search_limit' ) );
// 如果不是在后台,则在任何页面加载时检查IP的封禁状态
if ( ! is_admin() ) {
add_action( 'wp_loaded', array( $this, 'check_block_status_on_any_page' ) );
}
}
/**
* 获取访问者的IP地址
* @return string 访问者IP
*/
private function get_visitor_ip() {
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
// 处理HTTP_X_FORWARDED_FOR可能包含多个IP的情况
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return sanitize_text_field( $ip );
}
/**
* 设置IP的封禁缓存
* @param string $key 缓存键
* @param int $expiration 缓存过期时间(秒)
*/
private function set_block_cache($key, $expiration) {
$expire_time = time() + $expiration;
// 使用'search_limit'组,方便管理和清除
wp_cache_set($key, $expire_time, 'search_limit', $expiration);
}
/**
* 获取IP剩余的封禁时间
* @param string $key 缓存键
* @return int 剩余封禁时间(秒),如果未被封禁则返回0
*/
private function get_remaining_block_time($key) {
$expire_time = wp_cache_get($key, 'search_limit');
if ($expire_time === false) {
return 0; // 未被封禁
}
$remaining = $expire_time - time();
return $remaining > 0 ? $remaining : 0; // 确保返回非负数
}
/**
* 在非搜索页面检查IP的封禁状态并显示提示
*/
public function check_block_status_on_any_page() {
$visitor_ip = $this->get_visitor_ip();
$cache_key = 'search_block_' . $visitor_ip;
$remaining_time = $this->get_remaining_block_time($cache_key);
// 如果IP仍在封禁期内且当前页面不是搜索结果页,则显示提示
if ($remaining_time > 0 && !is_search()) {
$message = sprintf($this->block_message, $remaining_time);
// 使用wp_body_open钩子在<body>标签之后插入提示
add_action('wp_body_open', function() use ($message) {
echo '<div style="background-color: #fff3cd; color: #856404; padding: 15px; text-align: center; border: 1px solid #ffeeba; margin-bottom: 20px;">';
echo esc_html($message); // 安全输出提示消息
echo '</div>';
});
}
}
/**
* 检查搜索频率限制并处理
* @param WP_Query $query WordPress查询对象
* @return WP_Query
*/
public function check_search_limit($query) {
// 确保只在前端、主查询且是搜索请求时执行
if (!is_admin() && $query->is_search && $query->is_main_query()) {
$visitor_ip = $this->get_visitor_ip();
$limit = $this->search_limit_count;
$window_seconds = $this->time_window_in_minutes * 60; // 将分钟转换为秒
$block_time = $this->block_time_in_seconds;
$cache_key = 'search_block_' . $visitor_ip; // IP封禁状态的缓存键
$records_key = 'search_records_' . $visitor_ip; // IP搜索记录的缓存键
// 1. 检查IP是否正在被封禁
$remaining_time = $this->get_remaining_block_time($cache_key);
if ($remaining_time > 0) {
wp_die(
sprintf($this->block_message, $remaining_time),
'搜索频率限制', // 页面标题
array('response' => 429) // HTTP 429 Too Many Requests
);
}
// 2. 获取IP的搜索记录
$search_records = wp_cache_get($records_key, 'search_limit', false, $found);
if (!$found) {
$search_records = array(); // 如果没有找到记录,则初始化为空数组
}
$current_time = time();
// 3. 过滤掉时间窗口外的旧记录
$search_records = array_filter($search_records, function($timestamp) use ($current_time, $window_seconds) {
return ($current_time - $timestamp) < $window_seconds;
});
// 4. 检查是否达到搜索频率限制
if (count($search_records) >= $limit) {
// 达到限制,封禁IP
$this->set_block_cache($cache_key, $block_time);
// 清除旧的搜索记录,避免重复累积
wp_cache_delete($records_key, 'search_limit');
wp_die(
sprintf($this->block_message, $block_time),
'搜索频率限制',
array('response' => 429)
);
} else {
// 未达到限制,添加当前搜索时间戳到记录
$search_records[] = $current_time;
// 更新缓存,设置缓存过期时间与时间窗口一致,确保记录自动清理
wp_cache_set($records_key, $search_records, 'search_limit', $window_seconds);
}
}
return $query; // 返回修改后的查询对象
}
}
// 实例化类以激活功能
new WXS_SearchFrequencyLimit();
?>配置参数说明(可自行修改):
private $search_limit_count = 3;- 含义: 在
$time_window_in_minutes设定的时间内,允许同一个IP进行的最大搜索次数。 - 建议: 根据网站流量和用户行为习惯调整。对于一般博客,3-5次可能比较合理。
- 含义: 在
private $time_window_in_minutes = 1;- 含义: 统计搜索次数的时间窗口长度,以分钟为单位。
- 建议: 1-5分钟是常见的选择。如果您希望更严格,可以设置为1分钟。
private $block_time_in_seconds = 60;- 含义: 当IP达到搜索次数限制后,将被封禁的时间,以秒为单位。
- 建议: 为了用户体验和有效拦截,通常建议将封禁时间设置得与时间窗口长度一致或略长,例如这里设置为60秒(1分钟)。
private $block_message = '您的搜索频率过高,请在 %d 秒后再试。';- 含义: 当IP被封禁时,向用户显示的提示信息。
%d会自动替换为剩余的封禁秒数。
- 含义: 当IP被封禁时,向用户显示的提示信息。
最后总结
这段代码提供了一个非常实用的WordPress搜索功能保护机制。通过限制搜索频率,它能有效防止恶意刷搜行为,从而避免服务器CPU使用率和负载状态的异常升高。对于任何运行WordPress网站的管理员来说,尤其是在服务器资源有限的共享主机环境下,实施这样的防护措施是至关重要且高效的。这段代码的模块化设计和对WordPress缓存的利用,使其成为一个优雅而强大的解决方案。
© 版权声明
THE END
















暂无评论内容