Создание stats.php для отслеживания активности пользователей
Файл stats.php: сбор и отображение статистики
Файл stats.php предназначен для сбора, хранения и отображения данных о посещаемости сайта. В зависимости от требований проекта, возможны различные реализации – от простейшего счетчика до интеграции с профессиональными системами аналитики. Ниже рассмотрены основные подходы с примерами кода и указанием типичных проблем.
Как создать простой счетчик посещений с хранением в текстовом файле?
Цель: минимальная статистика без базы данных. Подходит для низконагруженных проектов или временных решений.
<?php
$counterFile = 'counter.txt';
$count = file_exists($counterFile) ? (int)file_get_contents($counterFile) : 0;
$count++;
file_put_contents($counterFile, $count);
echo 'Просмотров: ' . $count;
?>
Пояснение: файл открывается, читается текущее значение, увеличивается на единицу и записывается обратно. Проблема: при одновременных запросах возможна потеря данных (race condition). Решение – использовать блокировку flock() или перейти к БД.
Типичные ошибки:
- Ошибка прав доступа к файлу – проверьте права на запись.
- Отсутствие атомарности – используйте
flock()для исключения одновременной записи. - Большой размер файла при вставке детальных логов – лучше применять БД.
Как организовать сбор подробной статистики с помощью MySQL?
Цель: хранение данных о каждом визите: IP, User-Agent, время, страница. Используется для построения отчетов по посещаемости, уникальным посетителям и т.д.
-- Создание таблицы
CREATE TABLE visits (
id INT AUTO_INCREMENT PRIMARY KEY,
page VARCHAR(255),
ip VARCHAR(45),
user_agent TEXT,
visited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO visits (page, ip, user_agent) VALUES (?, ?, ?)');
$stmt->execute([$_SERVER['REQUEST_URI'], $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']]);
?>
Пояснение: использование подготовленных запросов защищает от SQL-инъекций. Для вывода статистики – SELECT с группировкой по дате.
Типичные ошибки:
- Забыли экранировать данные – используйте prepared statements.
- Нет индексов по полям
visited_atиpage– замедление запросов. - Избыточная запись при парсинге ботов – добавьте фильтр по User-Agent.
Как реализовать асинхронный сбор статистики через AJAX (наиболее эффективное решение)?
Цель: отправка данных о поведении пользователя без перезагрузки страницы. Эффективно для SPA, где традиционный PHP-вызов невозможен.
// JavaScript на странице (например, с помощью fetch)
fetch('stats.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
action: 'pageview',
url: window.location.href,
referrer: document.referrer
})
});
<?php
// stats.php
$input = json_decode(file_get_contents('php://input'), true);
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO ajax_stats (action, url, referrer, ip, visited_at) VALUES (?, ?, ?, ?, NOW())');
$stmt->execute([$input['action'], $input['url'], $input['referrer'], $_SERVER['REMOTE_ADDR']]);
?>
Пояснение: AJAX-запрос отправляет только необходимые поля. В PHP файл принимает JSON, валидирует и сохраняет. Проблема: боты могут игнорировать JavaScript, поэтому для базовой статистики лучше использовать серверный сбор.
Типичные ошибки:
- Необработка CORS – если stats.php расположен на другом домене.
- Отсутствие проверки входных данных – потенциальная инъекция.
- Слишком частые запросы – стоит добавить троттлинг на стороне клиента.
Как использовать файл stats.php в качестве прокси для отправки данных в систему аналитики (Matomo)?
Цель: передача данных в стороннюю систему без установки их JavaScript-кода на всех страницах. Полезно, если код аналитики нельзя разместить напрямую.
<?php
$url = 'https://your-matomo-domain.example.com/matomo.php?';
$params = http_build_query([
'idsite' => 1,
'rec' => 1,
'url' => $_POST['url'] ?? $_SERVER['REQUEST_URI'],
'uid' => $_SERVER['REMOTE_ADDR']
]);
$ch = curl_init($url . $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
?>
Пояснение: скрипт принимает данные от клиента (например, через AJAX) и пересылает их в Matomo. Это решает проблему блокировки скриптов аналитики в некоторых браузерах.
Типичные ошибки:
- Задержка ответа клиенту – используйте асинхронный вызов CURL.
- Утечка конфиденциальных данных – не передавайте лишнюю информацию.
- Зависимость от внешнего сервиса – добавьте обработку таймаутов.
Расширенные примеры реализации stats.php
Ниже приведены более сложные сценарии, которые редко встречаются в базовых туториалах, но полезны в реальных проектах.
1. Группировка статистики по дням с кэшированием результатов
<?php
// stats.php – вывод отчета за последние 7 дней
$cacheFile = 'cache/stats_' . date('Ymd') . '.txt';
$cacheLifetime = 3600; // 1 час
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheLifetime) {
echo file_get_contents($cacheFile);
exit;
}
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->query('
SELECT DATE(visited_at) AS day, COUNT(*) AS visits, COUNT(DISTINCT ip) AS uniques
FROM visits
WHERE visited_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY day
ORDER BY day DESC
');
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$html = '<table><tr><th>День</th><th>Визиты</th><th>Уникальные</th></tr>';
foreach ($data as $row) {
$html .= '<tr><td>' . $row['day'] . '</td><td>' . $row['visits'] . '</td><td>' . $row['uniques'] . '</td></tr>';
}
$html .= '</table>';
file_put_contents($cacheFile, $html);
echo $html;
?>
Результат: таблица с данными за последние 7 дней. При повторном обращении в течение часа данные берутся из кэша, что снижает нагрузку на БД.
2. Определение страны посетителя по IP через API (геолокация)
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$apiKey = 'YOUR_API_KEY';
$response = file_get_contents("https://api.ipgeolocation.io/ipgeo?apiKey={$apiKey}&ip={$ip}");
$geo = json_decode($response, true);
$country = $geo['country_name'] ?? 'Unknown';
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO geo_visits (ip, country, visited_at) VALUES (?, ?, NOW())');
$stmt->execute([$ip, $country]);
?>
Результат: в таблице geo_visits сохраняется страна для каждого визита. Можно построить карту посещений. Важно: API может взимать плату, для production используйте локальную базу GeoIP.
3. Отслеживание переходов по UTM-меткам
<?php
// stats.php
$utm = [
'source' => $_GET['utm_source'] ?? '',
'medium' => $_GET['utm_medium'] ?? '',
'campaign' => $_GET['utm_campaign'] ?? ''
];
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO utm_stats (source, medium, campaign, visited_at) VALUES (?, ?, ?, NOW())');
$stmt->execute([$utm['source'], $utm['medium'], $utm['campaign']]);
// Перенаправление на целевую страницу (если нужно)
header('Location: ' . ($_GET['redirect'] ?? '/'));
?>
Результат: в базу записываются UTM-параметры. Это позволяет анализировать эффективность рекламных кампаний. Проблема: если ссылка уже содержит UTM, то PHP принимает их через $_GET.
4. Использование файла stats.php как REST API для вывода статистики в формате JSON
<?php
header('Content-Type: application/json');
$action = $_GET['action'] ?? 'summary';
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
switch ($action) {
case 'summary':
$stmt = $pdo->query('SELECT COUNT(*) AS total, COUNT(DISTINCT ip) AS uniques FROM visits');
echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
break;
case 'pages':
$stmt = $pdo->query('SELECT page, COUNT(*) AS hits FROM visits GROUP BY page ORDER BY hits DESC LIMIT 10');
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unknown action']);
}
?>
Пример вызова: /stats.php?action=pages вернет JSON со списком популярных страниц. Это удобно для AJAX-виджетов на панели администрирования.