File size: 3.98Kb
<?php
/**
* CMS: LaiCMS (v1.0 Edition 2026)
* File: system/functions.php
* Description: Вспомогательные функции с усиленной безопасностью и мультиязычностью.
*/
declare(strict_types=1);
/**
* 1. БЕЗОПАСНОЕ ФОРМАТИРОВАНИЕ ВРЕМЕНИ
*/
if (!function_exists('time_ago')) {
function time_ago(?string $datetime): string {
if (!$datetime) return __t('time_never'); // "Никогда"
$time = strtotime($datetime);
if (!$time) return __t('time_invalid'); // "Дата некорректна"
$diff = time() - $time;
if ($diff < 0) return __t('time_future'); // "В будущем"
if ($diff < 60) return __t('time_now'); // "Только что"
if ($diff < 3600) return floor($diff / 60) . " " . __t('time_min_ago'); // "мин. назад"
if ($diff < 86400) return floor($diff / 3600) . " " . __t('time_hour_ago'); // "час. назад"
return date("d.m.Y", $time);
}
}
/**
* 2. УМНОЕ СОКРАЩЕНИЕ ТЕКСТА (XSS Safe)
*/
if (!function_exists('cut_text')) {
function cut_text(string $text, int $limit = 100): string {
$text = strip_tags($text); // Принудительная очистка от HTML
if (mb_strlen($text) <= $limit) return $text;
return mb_substr($text, 0, $limit) . '...';
}
}
/**
* 3. ПОДСВЕТКА МЕНЮ (Safe Path Check)
*/
if (!function_exists('is_active')) {
function is_active(string $path): string {
$current = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
return (strpos($current, $path) !== false) ? 'active' : '';
}
}
/**
* 4. УЛЬТРА-БЕЗОПАСНЫЙ МОНИТОРИНГ ОНЛАЙН
* Защита от SQL-инъекций через заголовки и спуфинга IP.
*/
if (!function_exists('track_online_status')) {
function track_online_status(): void {
global $mysqli;
if (empty($_SESSION['user_id']) || !isset($mysqli)) return;
$user_id = (int)$_SESSION['user_id'];
// Получаем реальный IP с защитой от подмены
$ip = $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
$ip = filter_var($ip, FILTER_VALIDATE_IP) ?: '0.0.0.0';
// Очищаем User-Agent от скрытых символов
$ua = mb_strimwidth(strip_tags($_SERVER['HTTP_USER_AGENT'] ?? 'Unknown'), 0, 255);
try {
$stmt = $mysqli->prepare("UPDATE users SET last_seen = NOW(), last_ip = ?, last_ua = ? WHERE id = ?");
$stmt->bind_param("ssi", $ip, $ua, $user_id);
$stmt->execute();
} catch (Exception $e) {
error_log("Security Monitor Error: " . $e->getMessage());
}
}
}
/**
* 5. ОПТИМИЗИРОВАННЫЙ СЧЕТЧИК СООБЩЕНИЙ
*/
if (!function_exists('get_unread_count')) {
function get_unread_count(int $user_id): int {
global $mysqli;
if (!isset($mysqli)) return 0;
try {
$stmt = $mysqli->prepare("SELECT COUNT(id) FROM messages WHERE receiver_id = ? AND is_read = 0");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$res = $stmt->get_result()->fetch_row();
return (int)($res[0] ?? 0);
} catch (Exception $e) {
return 0;
}
}
}
/**
* 6. ПРЕДПРОСМОТР (XSS & Buffer Overflow protection)
*/
if (!function_exists('preview_text')) {
function preview_text(?string $text, int $limit = 50): string {
if (!$text) return "";
// Убираем теги, лишние пробелы и ограничиваем ширину
$clean = preg_replace('/\s+/', ' ', strip_tags($text));
return mb_strimwidth(trim($clean), 0, $limit, "...");
}
}
// Прямой запуск мониторинга
track_online_status();