В этой статье мы подробно разберём, как создать собственный плагин для ведения журнала попыток входа пользователей в WordPress. Такой плагин поможет отслеживать успешные и неудачные входы, анализировать подозрительную активность и повысить безопасность вашего сайта.
Почему нужен кастомный плагин для журналов входов
Стандартный WordPress не ведёт полноценный лог входов пользователей. Хотя существуют популярные плагины, например, Clearfy Pro с расширенными возможностями безопасности, иногда требуется лёгкое и гибкое решение под конкретные задачи без избыточного функционала.
Создание своего плагина позволит:
- Записывать только нужные события;
- Добавлять кастомные поля и метаданные;
- Интегрировать запись в существующий функционал сайта;
- Оптимизировать производительность и не загромождать базу данных.
Основные задачи плагина для журналов входов
Плагин должен выполнять следующие функции:
- Логировать успешные входы пользователей с указанием ID, IP, времени;
- Логировать неудачные попытки входа с причиной отказа;
- Предоставлять администратору простой интерфейс для просмотра журнала;
- Обеспечивать возможность фильтрации и экспорта данных.
Рассмотрим этапы создания такого плагина и приведём примеры кода.
Создание плагина: структура и регистрация хуков
Начнём с создания папки в wp-content/plugins/wpauth-login-log и файла wpauth-login-log.php с базовым описанием плагина:
<?php
/*
Plugin Name: WPAUTH Login Log
Description: Журнал попыток входа пользователей
Version: 1.0
Author: WPAUTH Team
*/
// Защита от прямого доступа
if (!defined('ABSPATH')) exit;
Далее подключим хуки для логирования успешных и неудачных входов:
add_action('wp_login', 'wpauth_login_log_success', 10, 2);
add_action('wp_login_failed', 'wpauth_login_log_failed');
function wpauth_login_log_success($user_login, $user) {
global $wpdb;
$table = $wpdb->prefix . 'wpauth_login_log';
$wpdb->insert($table, [
'user_id' => $user->ID,
'login' => $user_login,
'ip_address' => wpauth_get_user_ip(),
'status' => 'success',
'date' => current_time('mysql')
]);
}
function wpauth_login_log_failed($user_login) {
global $wpdb;
$table = $wpdb->prefix . 'wpauth_login_log';
$wpdb->insert($table, [
'user_id' => 0,
'login' => $user_login,
'ip_address' => wpauth_get_user_ip(),
'status' => 'failed',
'date' => current_time('mysql')
]);
}
function wpauth_get_user_ip() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
Создание таблицы для хранения логов
Для хранения данных используем отдельную таблицу. Добавим функцию активации, которая создаст таблицу при активации плагина:
register_activation_hook(__FILE__, 'wpauth_create_login_log_table');
function wpauth_create_login_log_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'wpauth_login_log';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned NOT NULL,
login varchar(60) NOT NULL,
ip_address varchar(100) NOT NULL,
status varchar(10) NOT NULL,
date datetime NOT NULL,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY status (status),
KEY date (date)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
Создание административного интерфейса
Чтобы удобно просматривать логи, добавим страницу в админ-панель. Для этого используем хук admin_menu:
add_action('admin_menu', 'wpauth_login_log_admin_menu');
function wpauth_login_log_admin_menu() {
add_menu_page(
'Журнал входов',
'Журнал входов',
'manage_options',
'wpauth-login-log',
'wpauth_login_log_admin_page',
'dashicons-list-view',
80
);
}
function wpauth_login_log_admin_page() {
global $wpdb;
$table = $wpdb->prefix . 'wpauth_login_log';
// Параметры фильтрации
$status_filter = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
$query = "SELECT * FROM $table";
$where = [];
if ($status_filter === 'success' || $status_filter === 'failed') {
$where[] = $wpdb->prepare("status = %s", $status_filter);
}
if (!empty($where)) {
$query .= ' WHERE ' . implode(' AND ', $where);
}
$query .= ' ORDER BY date DESC LIMIT 100';
$logs = $wpdb->get_results($query);
echo '<h1>Журнал входов пользователей</h1>';
echo '<form method="get">';
echo '<input type="hidden" name="page" value="wpauth-login-log" />';
echo '<label>Фильтр по статусу: </label>';
echo '<select name="status" onchange="this.form.submit()">';
echo '<option value="">Все</option>';
echo '<option value="success"' . selected($status_filter, 'success', false) . '>Успешные</option>';
echo '<option value="failed"' . selected($status_filter, 'failed', false) . '>Неудачные</option>';
echo '</select>';
echo '</form>';
echo '<table class="wp-list-table widefat fixed striped">';
echo '<thead><tr><th>ID</th><th>Пользователь</th><th>Логин</th><th>IP адрес</th><th>Статус</th><th>Дата</th></tr></thead>';
echo '<tbody>';
if ($logs) {
foreach ($logs as $log) {
$user_display = $log->user_id ? get_userdata($log->user_id)->user_login : 'Гость';
echo "<tr>";
echo "<td>{$log->id}</td>";
echo "<td>" . esc_html($user_display) . "</td>";
echo "<td>" . esc_html($log->login) . "</td>";
echo "<td>" . esc_html($log->ip_address) . "</td>";
echo "<td>" . esc_html($log->status) . "</td>";
echo "<td>" . esc_html($log->date) . "</td>";
echo "</tr>";
}
} else {
echo "<tr><td colspan='6'>Записей не найдено</td></tr>";
}
echo '</tbody></table>';
}
Расширение функционала: уведомления и экспорт
Для повышения безопасности можно добавить уведомления администратору о подозрительных входах. Например, отправлять email при нескольких неудачных попытках подряд с одного IP.
Также полезна функция экспорта логов в CSV для последующего анализа. Это можно сделать, добавив кнопку экспорта и обработчик, который формирует CSV-файл с выбранными записями.
Для примера реализации экспорта можно использовать следующий код:
add_action('admin_post_wpauth_export_logs', 'wpauth_export_logs_csv');
function wpauth_export_logs_csv() {
if (!current_user_can('manage_options')) {
wp_die('Доступ запрещён');
}
global $wpdb;
$table = $wpdb->prefix . 'wpauth_login_log';
$logs = $wpdb->get_results("SELECT * FROM $table ORDER BY date DESC");
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=wpauth_login_logs.csv');
$output = fopen('php://output', 'w');
fputcsv($output, ['ID', 'User ID', 'Login', 'IP Address', 'Status', 'Date']);
foreach ($logs as $log) {
fputcsv($output, [(int)$log->id, (int)$log->user_id, $log->login, $log->ip_address, $log->status, $log->date]);
}
fclose($output);
exit;
}
Добавьте кнопку на страницу администратора с формой:
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<input type="hidden" name="action" value="wpauth_export_logs" />
<button type="submit" class="button button-primary">Экспортировать логи в CSV</button>
</form>
Оптимизация и безопасность
При работе с журналами важно учитывать производительность сайта. Рекомендуется очищать старые записи периодически, например, с помощью WP-Cron:
add_action('wpauth_cleanup_old_logs', 'wpauth_delete_old_logs');
function wpauth_delete_old_logs() {
global $wpdb;
$table = $wpdb->prefix . 'wpauth_login_log';
$wpdb->query($wpdb->prepare("DELETE FROM $table WHERE date < %s", date('Y-m-d H:i:s', strtotime('-90 days'))));
}
if (!wp_next_scheduled('wpauth_cleanup_old_logs')) {
wp_schedule_event(time(), 'daily', 'wpauth_cleanup_old_logs');
}
Также обязательно проверяйте права доступа к административным страницам и обрабатывайте пользовательский ввод через функции санитизации.
Заключение
Создание кастомного плагина для журналов входов в WordPress — отличное решение для контроля безопасности и мониторинга активности пользователей. В статье мы рассмотрели основные моменты: создание таблицы, регистрацию хуков для логирования, разработку админ-интерфейса, а также расширения в виде экспорта и очистки данных.
Если хотите более продвинутые функции, обратите внимание на плагины из каталога WPShop, например Clearfy Pro, который содержит готовые решения для безопасности и мониторинга.