Создание stats.php для отслеживания активности пользователей

Раздел: Администрирование PHP -> Статистика в 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-виджетов на панели администрирования.

Файл stats.php (статистика) - comments

En
Stats php (php)