Мониторинг активности пользователей через front controller index.php
Варианты отслеживания действий через index.php
Как организовать централизованное логирование всех запросов к сайту?
Наиболее эффективным решением является создание единого класса-логгера, который вызывается в самом начале файла index.php. Этот подход позволяет фиксировать каждый запрос, включая параметры, IP-адрес, время и User-Agent. Ниже представлен пример реализации.
<?php
// index.php
require_once 'Logger.php';
$logger = new Logger(__DIR__ . '/logs/requests.log');
$logger->logRequest($_SERVER);
// Далее обработка маршрута
?>Index php tracking (отслеживание действий пользователей через index.php)
<?php
// Logger.php
class Logger {
private $logFile;
private $handle;
public function __construct($file) {
$this->logFile = $file;
$this->handle = fopen($file, 'a');
if (!$this->handle) {
throw new Exception('Cannot open log file');
}
}
public function logRequest($server) {
$data = [
date('Y-m-d H:i:s'),
$server['REMOTE_ADDR'] ?? 'unknown',
$server['REQUEST_URI'] ?? '/',
$server['HTTP_USER_AGENT'] ?? '',
$server['REQUEST_METHOD'] ?? 'GET'
];
$line = implode('|', $data) . PHP_EOL;
fwrite($this->handle, $line);
}
public function __destruct() {
fclose($this->handle);
}
}
?>Типичные проблемы и решения:
- Высокая нагрузка при записи в файл - при большом количестве запросов файл может блокироваться. Решение: использовать асинхронную запись через очередь (например, Redis) или буферизацию.
- Права доступа - файл лога может быть недоступен для записи. Решение: установить права 0644 или 0666 на директорию logs.
- Конфиденциальность - логи могут содержать персональные данные. Решение: анонимизировать IP (сохранять только первые три октета) или не логировать чувствительные поля.
Как сохранять данные о действиях в базу данных для детального анализа?
Вместо файла можно использовать СУБД, например SQLite или MySQL. Это упрощает фильтрацию и агрегацию. Пример записи в таблицу user_actions.
<?php
$pdo = new PDO('sqlite:' . __DIR__ . '/tracking.db');
$pdo->exec('CREATE TABLE IF NOT EXISTS user_actions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
ip TEXT,
uri TEXT,
user_agent TEXT,
method TEXT
)');
$stmt = $pdo->prepare('INSERT INTO user_actions (timestamp, ip, uri, user_agent, method) VALUES (?, ?, ?, ?, ?)');
$stmt->execute([
date('Y-m-d H:i:s'),
$_SERVER['REMOTE_ADDR'] ?? '',
$_SERVER['REQUEST_URI'] ?? '',
$_SERVER['HTTP_USER_AGENT'] ?? '',
$_SERVER['REQUEST_METHOD'] ?? ''
]);
?>Возможные проблемы:
- Производительность - каждое вставка создает транзакцию. Решение: группировать запросы или использовать буферизованные вставки.
- Переполнение таблицы - старые записи необходимо архивировать или удалять через CRON.
Как отправлять события в Google Analytics с серверной стороны?
Используется Measurement Protocol. В index.php формируется HTTP-запрос к Google с параметрами события. Это позволяет отслеживать действия без клиентского JavaScript.
<?php
$trackingId = 'UA-XXXXX-Y'; // заменить на реальный ID
$clientId = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
$data = [
'v' => 1,
'tid' => $trackingId,
'cid' => $clientId,
't' => 'event',
'ec' => 'page_view',
'ea' => $_SERVER['REQUEST_URI'],
'ua' => $_SERVER['HTTP_USER_AGENT'],
'uip' => $_SERVER['REMOTE_ADDR']
];
$ch = curl_init('https://www.google-analytics.com/collect');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
?>Ошибки:
- Блокировка curl - если сайт использует устаревшие DNS или прокси, синхронный запрос может замедлить ответ. Решение: использовать неблокирующий curl_multi_exec или асинхронный вызов через fsockopen.
- Достижение лимитов Google Analytics - бесплатный аккаунт имеет ограничение 10 млн событий в месяц. Необходимо контролировать объем.
Как логировать только определённые действия (например, отправку форм)?
Вместо логирования всех запросов можно отслеживать лишь POST-запросы к определённым URL. В index.php добавляется условие.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && strpos($_SERVER['REQUEST_URI'], '/contact') !== false) {
// Логирование отправки контактной формы
$log = [
date('Y-m-d H:i:s'),
$_SERVER['REMOTE_ADDR'],
$_SERVER['REQUEST_URI'],
$_POST['email'] ?? '',
$_POST['message'] ?? ''
];
file_put_contents(__DIR__ . '/logs/form_submissions.log', implode('|', $log) . PHP_EOL, FILE_APPEND | LOCK_EX);
}
?>Проблемы:
- Получение только важных данных - необходимо чётко определить, какие действия считать целевыми. Излишняя фильтрация может привести к потере данных.
- Безопасность - логирование POST-данных может включать пароли. Следует исключать sensitive поля.
Расширенные примеры программного кода
Пример 1: Класс Logger с возможностью ротации логов
<?php
class AdvancedLogger {
private $directory;
private $maxSize = 10485760; // 10 MB
public function __construct($dir) {
$this->directory = rtrim($dir, '/') . '/';
if (!is_dir($this->directory)) {
mkdir($this->directory, 0755, true);
}
}
public function log($message, $level = 'INFO') {
$date = date('Y-m-d');
$file = $this->directory . 'app_' . $date . '.log';
if (file_exists($file) && filesize($file) >= $this->maxSize) {
$new = $this->directory . 'app_' . $date . '_' . time() . '.old.log';
rename($file, $new);
}
$line = '[' . date('Y-m-d H:i:s') . '] [' . $level . '] ' . $message . PHP_EOL;
file_put_contents($file, $line, FILE_APPEND | LOCK_EX);
}
}
// Использование в index.php
$logger = new AdvancedLogger(__DIR__ . '/logs');
$logger->log('Запрос: ' . $_SERVER['REQUEST_URI']);
?>В директории logs будут создаваться файлы вида app_2025-03-15.log. При превышении 10 МБ файл переименовывается с меткой времени.
Пример 2: Интеграция с Monolog
<?php
require 'vendor/autoload.php';
use Monolog\Logger as MonologLogger;
use Monolog\Handler\StreamHandler;
use Monolog\Processor\WebProcessor;
$log = new MonologLogger('tracking');
$log->pushHandler(new StreamHandler(__DIR__ . '/logs/requests.log', MonologLogger::INFO));
$log->pushProcessor(new WebProcessor());
// В index.php
$log->info('Page view', [
'uri' => $_SERVER['REQUEST_URI'],
'ip' => $_SERVER['REMOTE_ADDR'],
'method' => $_SERVER['REQUEST_METHOD']
]);
?>Monolog автоматически добавляет информацию о пользователе, времени и т.д. Формат вывода по умолчанию: [2025-03-15 12:00:00] tracking.INFO: Page view {"uri":"/page","ip":"192.168.1.1","method":"GET"} []Пример 3: Отправка данных в Google Analytics через Measurement Protocol с использованием неблокирующего сокета
<?php
function sendGaAsync($tid, $cid, $eventCategory, $eventAction) {
$data = [
'v' => 1,
'tid' => $tid,
'cid' => $cid,
't' => 'event',
'ec' => $eventCategory,
'ea' => $eventAction
];
$query = http_build_query($data);
$host = 'www.google-analytics.com';
$path = '/collect';
$header = "POST $path HTTP/1.1\r\n";
$header .= "Host: $host\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($query) . "\r\n";
$header .= "Connection: Close\r\n\r\n";
$socket = fsockopen($host, 80, $errno, $errstr, 1);
if ($socket) {
fwrite($socket, $header . $query);
fclose($socket);
}
}
// В index.php
sendGaAsync('UA-XXXXX-Y', md5($_SERVER['REMOTE_ADDR']), 'page_view', $_SERVER['REQUEST_URI']);
?>Скрипт не ожидает ответа от Google, что ускоряет выполнение index.php. Однако возможны потери событий при сбоях сети.
Пример 4: Логирование с определением страны по IP через GeoIP
<?php
// Предполагается, что установлен модуль geoip или используется база MaxMind
if (function_exists('geoip_country_code_by_name')) {
$country = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']);
} else {
$country = 'unknown';
}
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'],
'country' => $country,
'uri' => $_SERVER['REQUEST_URI']
];
file_put_contents(__DIR__ . '/logs/geo_requests.log', json_encode($logData) . PHP_EOL, FILE_APPEND | LOCK_EX);
?>Каждая строка лога - JSON-объект с дополнительным полем country. Пример: {"timestamp":"2025-03-15 12:00:00","ip":"8.8.8.8","country":"US","uri":"/"}