<?php
require_once 'config.php';
// Проверка, авторизован ли пользователь
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
// Проверка, является ли пользователь администратором
function isAdmin() {
return isLoggedIn() && isset($_SESSION['role']) && $_SESSION['role'] === 'admin';
}
// Перенаправление
function redirect($url) {
header("Location: $url");
exit();
}
// Экранирование данных для защиты от XSS
function escape($data) {
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
// Генерация капчи (4 цифры)
function generateCaptcha() {
$captcha = rand(1000, 9999);
$_SESSION['captcha'] = $captcha;
return $captcha;
}
// Проверка капчи
function verifyCaptcha($input) {
return isset($_SESSION['captcha']) && $_SESSION['captcha'] == $input;
}
// Функция для генерации скриншота (теперь в основном используется для заглушки или других целей)
// При загрузке пользователем в add_site.php эта функция НЕ вызывается.
function generateScreenshot($url, $site_id) {
// В реальном проекте используй API, например, ScreenshotLayer или аналогичный сервис
// Или эту функцию можно использовать, если нужно генерировать скриншоты для старых сайтов
// или из админки.
$placeholder = 'placeholder.png'; // Убедитесь, что placeholder.png есть в папке screenshots
if (!is_dir(SCREENSHOT_PATH)) {
mkdir(SCREENSHOT_PATH, 0755, true);
}
if (!file_exists(SCREENSHOT_PATH . $placeholder)) {
// Загружаем заглушку, если её нет
$placeholder_url = 'https://via.placeholder.com/150x150?text=No+Screenshot'; // Обновленный URL заглушки
$placeholder_content = @file_get_contents($placeholder_url);
if ($placeholder_content !== false) {
file_put_contents(SCREENSHOT_PATH . $placeholder, $placeholder_content);
} else {
// Если даже заглушку не удалось загрузить, создаем пустой файл
file_put_contents(SCREENSHOT_PATH . $placeholder, '');
}
}
// Копируем заглушку с именем ID сайта
copy(SCREENSHOT_PATH . $placeholder, SCREENSHOT_PATH . $site_id . '.png');
error_log("INFO: Placeholder screenshot generated for site ID {$site_id}"); // Логируем использование заглушки
}
// Обновление статистики сайта (хиты и просмотры) с счетчика
// Эта функция вызывается из counter-image.php
function updateCounterStats($conn, $site_id) {
$today = date('Y-m-d');
$visitor_ip = $_SERVER['REMOTE_ADDR'];
// $session_key = "visited_site_counter_$site_id"; // Этот ключ используется в counter-image.php для ограничения уникальных за сессию
// Проверяем, есть ли запись статистики на сегодня для этого сайта
$result_stats = $conn->query("SELECT id FROM stats WHERE site_id = $site_id AND date = '$today'");
$stats_row = $result_stats->fetch_assoc();
if ($stats_row) {
$stats_id = $stats_row['id'];
// Увеличиваем хиты за сегодня
$conn->query("UPDATE stats SET hits = hits + 1 WHERE id = $stats_id");
// Проверяем, уникальный ли посетитель за сегодня по IP
// Используем 'ip_address' как имя столбца
$result_visitor = $conn->query("SELECT id FROM stats_visitors WHERE stat_id = $stats_id AND ip_address = '$visitor_ip'");
if ($result_visitor->num_rows === 0) {
// Если IP уникален за сегодня, добавляем его и увеличиваем unique_visitors
// Добавляем IP с текущим временем
$stmt = $conn->prepare("INSERT INTO stats_visitors (stat_id, ip_address, visit_time) VALUES (?, ?, NOW())");
$stmt->bind_param("is", $stats_id, $visitor_ip);
$stmt->execute();
$stmt->close();
$conn->query("UPDATE stats SET unique_visitors = unique_visitors + 1 WHERE id = $stats_id");
} else {
// Если IP не уникален за сегодня, просто записываем хит с новой меткой времени в stats_visitors
// (это нужно для подсчета хитов и уникальных за час)
$stmt = $conn->prepare("INSERT INTO stats_visitors (stat_id, ip_address, visit_time) VALUES (?, ?, NOW())");
$stmt->bind_param("is", $stats_id, $visitor_ip);
$stmt->execute();
$stmt->close();
}
} else {
// Если записи на сегодня нет, создаем новую запись в stats
// При первом хите за день views, hits, unique_visitors равны 1
$conn->query("INSERT INTO stats (site_id, date, views, hits, unique_visitors) VALUES ($site_id, '$today', 1, 1, 1)");
$stats_id = $conn->insert_id;
// Добавляем IP первого посетителя за сегодня с текущим временем в stats_visitors
$stmt = $conn->prepare("INSERT INTO stats_visitors (stat_id, ip_address, visit_time) VALUES (?, ?, NOW())");
$stmt->bind_param("is", $stats_id, $visitor_ip);
$stmt->execute();
$stmt->close();
}
// Увеличиваем общее количество просмотров сайта (sites.views)
// Это должно происходить при каждом показе счетчика, если views в stats и sites - это просмотры счетчика
$conn->query("UPDATE sites SET views = views + 1 WHERE id = $site_id");
}
// Функция для обновления статистики просмотров страницы site.php
function updateSitePageViews($conn, $site_id) {
$stmt = $conn->prepare("UPDATE sites SET site_page_views = site_page_views + 1 WHERE id = ?");
$stmt->bind_param("i", $site_id);
$stmt->execute();
$stmt->close();
}
// Функция для подсчета общей репутации сайта
function calculateOverallReputation($conn, $site_id) {
$stmt = $conn->prepare("SELECT SUM(rating) AS total_reputation FROM reviews WHERE site_id = ? AND parent_id IS NULL"); // Считаем только корневые отзывы
$stmt->bind_param("i", $site_id);
$stmt->execute();
$result = $stmt->get_result()->fetch_assoc();
$stmt->close();
return (int)$result['total_reputation'];
}
// Функция для обновления репутации сайта в базе
function updateSiteReputation($conn, $site_id) {
$reputation = calculateOverallReputation($conn, $site_id);
$stmt = $conn->prepare("UPDATE sites SET reputation = ? WHERE id = ?");
$stmt->bind_param("ii", $reputation, $site_id);
$stmt->execute();
$stmt->close();
}
// Функция для получения статистики счетчика за определенный период (для текстового отображения)
function getCounterStats($conn, $site_id, $period = 'day') {
$stats = [
'views' => 0, // Views счетчика
'unique_visitors' => 0, // Уникальные посетители счетчика
'hits' => 0 // Хиты счетчика
];
switch ($period) {
case 'day':
$today = date('Y-m-d');
$stmt = $conn->prepare("SELECT views, unique_visitors, hits FROM stats WHERE site_id = ? AND date = ?");
$stmt->bind_param("is", $site_id, $today);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
$stats['views'] = (int)$row['views'];
$stats['unique_visitors'] = (int)$row['unique_visitors'];
$stats['hits'] = (int)$row['hits'];
}
$stmt->close();
break;
case 'month':
// Получаем сумму за последние 30 дней из таблицы stats
$month_start = date('Y-m-d', strtotime('-30 days'));
$stmt = $conn->prepare("SELECT SUM(views) AS total_views, SUM(unique_visitors) AS total_unique, SUM(hits) AS total_hits
FROM stats
WHERE site_id = ? AND date >= ?");
$stmt->bind_param("is", $site_id, $month_start);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
$stats['views'] = (int)$row['total_views'];
$stats['unique_visitors'] = (int)$row['total_unique'];
$stats['hits'] = (int)$row['total_hits'];
}
$stmt->close();
break;
case 'hour':
// Получение хитов и уникальных посетителей за последний час из stats_visitors
$one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour'));
$today = date('Y-m-d');
// Находим stat_id для сегодняшнего дня, т.к. stats_visitors привязаны к stats по date
$stmt_stat_id = $conn->prepare("SELECT id FROM stats WHERE site_id = ? AND date = ?");
$stmt_stat_id->bind_param("is", $site_id, $today);
$stmt_stat_id->execute();
$stat_row = $stmt_stat_id->get_result()->fetch_assoc();
$stmt_stat_id->close();
if ($stat_row) {
$stats_id = $stat_row['id'];
// Подсчитываем хиты за последний час из stats_visitors
$stmt_hits = $conn->prepare("SELECT COUNT(*) AS hourly_hits FROM stats_visitors WHERE stat_id = ? AND visit_time >= ?");
$stmt_hits->bind_param("is", $stats_id, $one_hour_ago);
$stmt_hits->execute();
$hits_row = $stmt_hits->get_result()->fetch_assoc();
$stats['hits'] = (int)$hits_row['hourly_hits'];
$stmt_hits->close();
// Подсчитываем уникальных посетителей за последний час (по IP в рамках stat_id за сегодня и времени)
$stmt_unique = $conn->prepare("SELECT COUNT(DISTINCT ip_address) AS hourly_unique FROM stats_visitors WHERE stat_id = ? AND visit_time >= ?");
$stmt_unique->bind_param("is", $stats_id, $one_hour_ago);
$stmt_unique->execute();
$unique_row = $stmt_unique->get_result()->fetch_assoc();
$stats['unique_visitors'] = (int)$unique_row['hourly_unique'];
$stmt_unique->close();
// Views счетчика за час приравниваем к хитам за час
$stats['views'] = $stats['hits'];
} else {
// Если нет записи stats за сегодня, статистики за час тоже нет.
}
break;
}
return $stats;
}
// Функция для получения ежедневной статистики для графика (за последние N дней)
function getDailyStatsForGraph($conn, $site_id, $days = 30) {
$data = [];
$start_date = date('Y-m-d', strtotime("-{$days} days"));
$stmt = $conn->prepare("SELECT date, views, unique_visitors, hits FROM stats WHERE site_id = ? AND date >= ? ORDER BY date ASC");
$stmt->bind_param("is", $site_id, $start_date);
$stmt->execute();
$result = $stmt->get_result();
$period = new DatePeriod(
new DateTime($start_date),
new DateInterval('P1D'),
new DateTime('tomorrow') // Включаем сегодняшний день
);
$stats_by_date = [];
while($row = $result->fetch_assoc()){
$stats_by_date[$row['date']] = $row;
}
$stmt->close();
foreach ($period as $date) {
$date_str = $date->format('Y-m-d');
$data[] = [
'date' => $date->format('d.m'), // Формат для оси X
'views' => isset($stats_by_date[$date_str]) ? (int)$stats_by_date[$date_str]['views'] : 0,
'unique_visitors' => isset($stats_by_date[$date_str]) ? (int)$stats_by_date[$date_str]['unique_visitors'] : 0,
'hits' => isset($stats_by_date[$date_str]) ? (int)$stats_by_date[$date_str]['hits'] : 0,
];
}
return $data;
}
// Функция для получения почасовой статистики для графика (за последние 24 часа)
function getHourlyStatsForGraph($conn, $site_id) {
$data = [];
$now = new DateTime();
$start_time = (clone $now)->modify('-24 hours');
// Находим stat_id для каждого дня за последние 24 часа
// Это нужно, потому что stats_visitors связаны со stats по stat_id и date
// Могут быть записи из двух разных дней, если 24 часа пересекают полночь
$today = date('Y-m-d');
$yesterday = date('Y-m-d', strtotime('-1 day'));
$stmt_stat_ids = $conn->prepare("SELECT id, date FROM stats WHERE site_id = ? AND (date = ? OR date = ?)");
$stmt_stat_ids->bind_param("iss", $site_id, $today, $yesterday);
$stmt_stat_ids->execute();
$stat_ids = [];
$result_stat_ids = $stmt_stat_ids->get_result();
while($row = $result_stat_ids->fetch_assoc()) {
$stat_ids[$row['date']] = $row['id'];
}
$stmt_stat_ids->close();
// Если нет статистики за последние 2 дня, возвращаем пустой массив
if (empty($stat_ids)) {
return [];
}
// Получаем хиты и уникальных посетителей из stats_visitors за последние 24 часа
// Группируем по полному часу (YYYY-MM-DD HH:00:00)
$stmt_hourly_stats = $conn->prepare("SELECT
DATE_FORMAT(visit_time, '%Y-%m-%d %H:00:00') as hour,
COUNT(*) as hourly_hits,
COUNT(DISTINCT ip_address) as hourly_unique
FROM stats_visitors
WHERE stat_id IN (" . implode(',', array_values($stat_ids)) . ")
AND visit_time >= ?
GROUP BY hour
ORDER BY hour ASC");
$start_time_str = $start_time->format('Y-m-d H:i:s');
$stmt_hourly_stats->bind_param("s", $start_time_str);
$stmt_hourly_stats->execute();
$hourly_results = $stmt_hourly_stats->get_result();
$stats_by_hour = [];
while ($row = $hourly_results->fetch_assoc()) {
$stats_by_hour[$row['hour']] = $row;
}
$stmt_hourly_stats->close();
// Формируем данные для графика, включая часы без статистики с нулевыми значениями
$interval = new DateInterval('PT1H'); // Интервал в 1 час
// Создаем период от start_time до текущего часа + 1 час, чтобы убедиться, что последний час включен
$period = new DatePeriod($start_time, $interval, (clone $now)->modify('+1 hour'));
foreach ($period as $hour_date) {
$hour_str = $hour_date->format('Y-m-d H:00:00');
$display_label = $hour_date->format('H:00'); // Формат для оси X (например, 14:00)
$data[] = [
'hour' => $display_label,
'views' => isset($stats_by_hour[$hour_str]) ? (int)$stats_by_hour[$hour_str]['hourly_hits'] : 0, // Views счетчика = хитам
'unique_visitors' => isset($stats_by_hour[$hour_str]) ? (int)$stats_by_hour[$hour_str]['hourly_unique'] : 0,
'hits' => isset($stats_by_hour[$hour_str]) ? (int)$stats_by_hour[$hour_str]['hourly_hits'] : 0, // Хиты
];
}
return $data;
}
// Функция для проверки, заблокирован ли пользователь
function isUserBlocked($conn, $user_id) {
$stmt = $conn->prepare("SELECT is_blocked FROM users WHERE id = ?");
if ($stmt) {
$stmt->bind_param("i", $user_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$user = $result->fetch_assoc();
$stmt->close();
return (bool)$user['is_blocked']; // Возвращает true, если заблокирован, иначе false
}
$stmt->close();
} else {
error_log("Failed to prepare statement for isUserBlocked: " . $conn->error);
}
return false; // По умолчанию считаем пользователя не заблокированным при ошибке
}
// Функция для переключения статуса блокировки пользователя
function toggleUserBlockStatus($conn, $user_id, $block_status) {
// Убедимся, что $block_status является булевым значением
$block_status = (bool)$block_status;
$stmt = $conn->prepare("UPDATE users SET is_blocked = ? WHERE id = ?");
if ($stmt) {
// Используем 'i' для integer (block_status преобразуется к 0 или 1) и 'i' для user_id
$stmt->bind_param("ii", $block_status, $user_id);
if ($stmt->execute()) {
$stmt->close();
return true; // Успешно обновлено
} else {
error_log("Failed to execute statement for toggleUserBlockStatus: " . $stmt->error);
$stmt->close();
return false; // Ошибка выполнения
}
} else {
error_log("Failed to prepare statement for toggleUserBlockStatus: " . $conn->error);
return false; // Ошибка подготовки
}
}
?>