闲着写了一个插件监控Wordpress HTTP 请求,保存以下代码为wp-request-monitor.php,放到wp-content/plugins/目录下即可
可以看插件或者主题等有没有偷偷摸摸的发送一些请求,泄露信息
<?php
/*
Plugin Name: WP Request Monitor & Blocker
Description: 监控 HTTP 请求(含耗时、Header、Body),支持正则拦截,过滤 Cron/Ajax,卸载时自动清理。
Version: 1.0
Author: Huilang
Author URI: https://huilang.me
*/
if (!defined('ABSPATH')) exit;
/**
* 1. 数据库表初始化
*/
register_activation_hook(__FILE__, 'wrm_install');
function wrm_install() {
global $wpdb;
$table_name = $wpdb->prefix . 'wrm_logs';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
time datetime DEFAULT CURRENT_TIMESTAMP,
duration float DEFAULT 0,
method varchar(10),
url text,
request_headers longtext,
request_body longtext,
response_code varchar(50),
response_headers longtext,
response_body longtext,
is_blocked tinyint(1) DEFAULT 0,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
add_option('wrm_blocked_rules', []);
}
/**
* 2. 卸载清理逻辑
*/
register_uninstall_hook(__FILE__, 'wrm_uninstall');
function wrm_uninstall() {
global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS " . $wpdb->prefix . 'wrm_logs');
delete_option('wrm_blocked_rules');
}
/**
* 3. 核心拦截与计时逻辑
*/
global $wrm_request_meta;
$wrm_request_meta = [];
add_filter('pre_http_request', 'wrm_core_interceptor', 1, 3);
function wrm_core_interceptor($pre, $args, $url) {
global $wpdb, $wrm_request_meta;
// 过滤高频无关请求
if (isset($_POST['wrm_clear']) || isset($_POST['save_rules'])) return $pre;
if (strpos($url, 'wp-cron.php') !== false || strpos($url, 'admin-ajax.php') !== false) return $pre;
$request_id = md5($url . serialize($args));
$wrm_request_meta[$request_id] = [
'start_time' => microtime(true),
'is_blocked' => false
];
$rules = get_option('wrm_blocked_rules', []);
foreach ($rules as $rule) {
$rule = trim($rule);
if (empty($rule)) continue;
$is_hit = (strpos($rule, '/') === 0) ? @preg_match($rule, $url) : (strpos($url, $rule) !== false);
if ($is_hit) {
$wrm_request_meta[$request_id]['is_blocked'] = true;
$wpdb->insert($wpdb->prefix . 'wrm_logs', [
'time' => current_time('mysql'),
'duration' => 0,
'method' => $args['method'],
'url' => $url,
'request_headers' => maybe_serialize($args['headers']),
'request_body' => maybe_serialize($args['body']),
'response_code' => 'BLOCKED',
'response_body' => '该请求已被拦截规则匹配: ' . esc_html($rule),
'is_blocked' => 1
]);
return new WP_Error('http_request_blocked', 'Monitor Blocked');
}
}
return $pre;
}
/**
* 4. 正常请求记录
*/
add_action('http_api_debug', 'wrm_core_logger', 10, 5);
function wrm_core_logger($response, $context, $class, $args, $url) {
global $wpdb, $wrm_request_meta;
$request_id = md5($url . serialize($args));
if (!isset($wrm_request_meta[$request_id]) || $wrm_request_meta[$request_id]['is_blocked']) {
unset($wrm_request_meta[$request_id]);
return;
}
$duration = round(microtime(true) - $wrm_request_meta[$request_id]['start_time'], 4);
unset($wrm_request_meta[$request_id]);
$is_error = is_wp_error($response);
$res_code = $is_error ? $response->get_error_code() : wp_remote_retrieve_response_code($response);
$res_body = $is_error ? $response->get_error_message() : wp_remote_retrieve_body($response);
$res_headers = $is_error ? [] : wp_remote_retrieve_headers($response);
$wpdb->insert($wpdb->prefix . 'wrm_logs', [
'time' => current_time('mysql'),
'duration' => $duration,
'method' => $args['method'],
'url' => $url,
'request_headers' => maybe_serialize($args['headers']),
'request_body' => maybe_serialize($args['body']),
'response_code' => $res_code,
'response_headers' => maybe_serialize($res_headers),
'response_body' => mb_strimwidth($res_body, 0, 10000, '... [Truncated]'),
'is_blocked' => 0
]);
}
/**
* 5. 后台界面
*/
add_action('admin_menu', function() {
add_menu_page('请求监控', '请求监控', 'manage_options', 'wrm', 'wrm_render', 'dashicons-rest-api');
});
function wrm_render() {
global $wpdb;
$table_name = $wpdb->prefix . 'wrm_logs';
if (isset($_POST['save_rules']) && check_admin_referer('wrm_save_rules')) {
$rules = explode("\n", str_replace("\r", "", $_POST['rules_text']));
update_option('wrm_blocked_rules', array_filter(array_map('trim', $rules)));
echo '<div class="updated"><p>拦截规则更新成功。</p></div>';
}
if (isset($_POST['wrm_clear']) && check_admin_referer('wrm_clear_logs')) {
$wpdb->query("TRUNCATE TABLE $table_name");
echo '<div class="updated"><p>日志已清空。</p></div>';
}
$per_page = 20;
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
$offset = ($current_page - 1) * $per_page;
$total_items = (int) $wpdb->get_var("SELECT COUNT(id) FROM $table_name");
$total_pages = ceil($total_items / $per_page);
$logs = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name ORDER BY id DESC LIMIT %d OFFSET %d", $per_page, $offset));
$rules_text = implode("\n", get_option('wrm_blocked_rules', []));
?>
<style>
.wrm-badge { padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: bold; }
.wrm-blocked { background: #333; color: #fff; }
.wrm-ok { background: #00a32a; color: #fff; }
.wrm-error { background: #d63638; color: #fff; }
pre.code-view { background: #f6f7f7; padding: 10px; border: 1px solid #c3c4c7; overflow: auto; max-height: 150px; font-size: 12px; }
.detail-box { padding:15px; background:#fff; border:1px solid #ccd0d4; margin-top: 5px; }
.detail-label { display: block; margin: 10px 0 5px; font-weight: bold; color: #222; border-left: 4px solid #2271b1; padding-left: 8px; }
</style>
<div class="wrap">
<h1>网络请求监控 & 拦截</h1>
<div class="postbox" style="margin-top:20px; padding:15px;">
<h3>拦截配置 (每行一个关键词或正则)</h3>
<form method="post">
<?php wp_nonce_field('wrm_save_rules'); ?>
<textarea name="rules_text" style="width:100%; height:80px; font-family:monospace;" placeholder="example.com /^https:\/\/api\.*/i"><?php echo esc_textarea($rules_text); ?></textarea>
<p><input type="submit" name="save_rules" class="button button-primary" value="保存拦截规则"></p>
</form>
</div>
<div class="tablenav top">
<div class="alignleft actions">
<form method="post">
<?php wp_nonce_field('wrm_clear_logs'); ?>
<input type="submit" name="wrm_clear" class="button" value="清空日志 (<?php echo $total_items; ?>)">
</form>
</div>
<div class="tablenav-pages">
<?php echo paginate_links(['total' => $total_pages, 'current' => $current_page, 'base' => add_query_arg('paged', '%#%')]); ?>
</div>
</div>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th width="140">时间</th><th width="70">耗时</th><th width="80">状态</th><th width="70">方法</th><th>URL</th><th width="80">操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($logs as $log):
$status_class = $log->is_blocked ? 'wrm-blocked' : (intval($log->response_code) < 400 ? 'wrm-ok' : 'wrm-error');
?>
<tr>
<td><?php echo $log->time; ?></td>
<td><?php echo $log->duration; ?>s</td>
<td><span class="wrm-badge <?php echo $status_class; ?>"><?php echo esc_html($log->response_code); ?></span></td>
<td><code><?php echo esc_html($log->method); ?></code></td>
<td style="word-break: break-all;"><?php echo esc_html($log->url); ?></td>
<td><button class="button button-small" onclick="jQuery('#details-<?php echo $log->id; ?>').toggle()">详情</button></td>
</tr>
<tr id="details-<?php echo $log->id; ?>" style="display:none;">
<td colspan="6">
<div class="detail-box">
<span class="detail-label">[Request Headers]</span>
<pre class="code-view"><?php print_r(maybe_unserialize($log->request_headers)); ?></pre>
<span class="detail-label">[Request Body]</span>
<textarea style="width:100%; height:100px; font-family:monospace; background:#f9f9f9;" readonly><?php
$req_body = maybe_unserialize($log->request_body);
echo esc_html(is_array($req_body) || is_object($req_body) ? json_encode($req_body, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : $req_body);
?></textarea>
<span class="detail-label">[Response Body]</span>
<textarea style="width:100%; height:150px; font-family:monospace; background:#f9f9f9;" readonly><?php echo esc_html($log->response_body); ?></textarea>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
}
/**
* 6. 在插件列表页添加“设置”链接
*/
add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'wrm_plugin_action_links');
function wrm_plugin_action_links($links) {
// 创建一个指向监控页面的链接
$settings_link = '<a href="' . admin_url('admin.php?page=wrm') . '">' . __('Settings') . '</a>';
// 将链接放入数组的最前面
array_unshift($links, $settings_link);
return $links;
}
不错,学到了
真是随手就一个插件
现在有想法就行了 做出来的效果比自己想象的还好
牛?
兄弟,这么晚的