MAX_ROOM_AGE) { $shouldDelete = true; } elseif (isset($content['hangup']) && time() - $content['timestamp'] > 10) { $shouldDelete = true; } if ($shouldDelete) { @unlink($filename); logEvent('room_cleaned', basename($filename, '.txt'), $_SERVER['REMOTE_ADDR'] ?? 'unknown'); } } } } } // Функция проверки IP для повторного входа function canIPRejoin($roomData, $ip) { if (!isset($roomData['hangup_ip']) || !isset($roomData['hangup_time'])) { return true; } // Если IP совпадает с IP того, кто завершил звонок if ($roomData['hangup_ip'] === $ip) { // Проверяем время блокировки if (time() - $roomData['hangup_time'] < IP_BAN_TIME) { return false; } } return true; } // Создаем папку для комнат $videoroomsDir = __DIR__ . '/videorooms'; if (!file_exists($videoroomsDir)) { mkdir($videoroomsDir, 0755, true); } // Обработка POST-запросов if ($_SERVER['REQUEST_METHOD'] === 'POST') { $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; $data = json_decode(file_get_contents('php://input'), true); // Проверка CSRF токена if (!isset($data['csrf_token']) || $data['csrf_token'] !== $_SESSION['csrf_token']) { http_response_code(403); echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']); logEvent('csrf_failed', '', $ip); exit; } // Валидация и очистка имени комнаты $room_raw = isset($data['room']) ? trim($data['room']) : ''; $room_safe = preg_replace('/[^\p{L}\p{N}_\-]/u', '', $room_raw); $room_safe = mb_substr($room_safe, 0, MAX_ROOM_NAME_LENGTH); $room_safe = $room_safe ?: 'default_' . bin2hex(random_bytes(4)); $file = $videoroomsDir . '/room_' . $room_safe . '.txt'; // Автоматическая очистка старых комнат cleanupOldRooms($videoroomsDir); // Получение списка комнат if (isset($data['get_rooms'])) { $rooms = []; $files = glob($videoroomsDir . '/room_*.txt'); foreach ($files as $filename) { if (!file_exists($filename)) continue; $content = @json_decode(file_get_contents($filename), true); if (!$content) continue; // Пропускаем комнаты с hangup if (isset($content['hangup'])) { // Проверяем, можно ли удалить комнату с hangup if (time() - $content['timestamp'] > 10) { @unlink($filename); } continue; } // Проверяем возраст комнаты if (time() - $content['timestamp'] < 30) { // 30 секунд - активная комната $room_name = str_replace(['room_', '.txt'], '', basename($filename)); $participants = 0; if (isset($content['offer'])) $participants++; if (isset($content['answer'])) $participants++; $rooms[] = [ 'name' => $room_name, 'participants' => $participants, 'full' => ($participants >= MAX_PARTICIPANTS), 'age' => time() - $content['timestamp'] ]; } else { // Удаляем старую комнату @unlink($filename); } } echo json_encode(['rooms' => $rooms, 'csrf_token' => $_SESSION['csrf_token']]); logEvent('rooms_listed', '', $ip); exit; } // Обработка offer (первый участник) if (isset($data['offer'])) { if (file_exists($file)) { $content = @json_decode(file_get_contents($file), true); if ($content) { // Проверяем, не был ли hangup от этого IP if (isset($content['hangup']) && isset($content['hangup_ip']) && $content['hangup_ip'] === $ip) { // Проверяем время блокировки if (isset($content['hangup_time']) && time() - $content['hangup_time'] < IP_BAN_TIME) { echo json_encode([ 'status' => 'error', 'message' => 'Пожалуйста, подождите ' . (IP_BAN_TIME - (time() - $content['hangup_time'])) . ' секунд перед повторным подключением', 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('ip_blocked', $room_safe, $ip); exit; } } $participants = 0; if (isset($content['offer'])) $participants++; if (isset($content['answer'])) $participants++; if ($participants >= MAX_PARTICIPANTS) { echo json_encode([ 'status' => 'error', 'message' => 'Комната заполнена (максимум ' . MAX_PARTICIPANTS . ' участника)', 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('room_full', $room_safe, $ip); exit; } } } $room_data = [ 'offer' => $data['offer'], 'timestamp' => time(), 'creator_ip' => $ip, 'creator_joined' => time() ]; // Удаляем hangup флаг если был if (isset($room_data['hangup'])) { unset($room_data['hangup']); } if (isset($room_data['hangup_ip'])) { unset($room_data['hangup_ip']); } if (isset($room_data['hangup_time'])) { unset($room_data['hangup_time']); } file_put_contents($file, json_encode($room_data)); echo json_encode([ 'status' => 'offer saved', 'room' => $room_safe, 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('offer_saved', $room_safe, $ip); exit; } // Обработка answer (второй участник) if (isset($data['answer'])) { if (!file_exists($file)) { echo json_encode([ 'status' => 'error', 'message' => 'Комната не найдена', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } $content = @json_decode(file_get_contents($file), true); if (!$content) { echo json_encode([ 'status' => 'error', 'message' => 'Ошибка чтения данных комнаты', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } // Проверяем, не был ли hangup от этого IP if (isset($content['hangup']) && isset($content['hangup_ip']) && $content['hangup_ip'] === $ip) { // Проверяем время блокировки if (isset($content['hangup_time']) && time() - $content['hangup_time'] < IP_BAN_TIME) { echo json_encode([ 'status' => 'error', 'message' => 'Пожалуйста, подождите ' . (IP_BAN_TIME - (time() - $content['hangup_time'])) . ' секунд перед повторным подключением', 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('ip_blocked_on_answer', $room_safe, $ip); exit; } } $participants = 0; if (isset($content['offer'])) $participants++; if (isset($content['answer'])) $participants++; if ($participants >= MAX_PARTICIPANTS) { echo json_encode([ 'status' => 'error', 'message' => 'Комната заполнена (максимум ' . MAX_PARTICIPANTS . ' участника)', 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('room_full_on_answer', $room_safe, $ip); exit; } $content['answer'] = $data['answer']; $content['timestamp'] = time(); $content['joiner_ip'] = $ip; $content['joiner_joined'] = time(); // Удаляем hangup флаг если был if (isset($content['hangup'])) { unset($content['hangup']); } if (isset($content['hangup_ip'])) { unset($content['hangup_ip']); } if (isset($content['hangup_time'])) { unset($content['hangup_time']); } file_put_contents($file, json_encode($content)); echo json_encode([ 'status' => 'answer saved', 'csrf_token' => $_SESSION['csrf_token'] ]); logEvent('answer_saved', $room_safe, $ip); exit; } // Обработка ICE candidates if (isset($data['candidate'])) { if (!file_exists($file)) { echo json_encode([ 'status' => 'error', 'message' => 'Комната не найдена', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } $content = @json_decode(file_get_contents($file), true); if (!$content) { $content = []; } if (!isset($content['candidates'])) { $content['candidates'] = []; } $content['candidates'][] = $data['candidate']; $content['timestamp'] = time(); file_put_contents($file, json_encode($content)); echo json_encode([ 'status' => 'candidate saved', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } // Обработка завершения звонка if (isset($data['hangup'])) { if (file_exists($file)) { $content = @json_decode(file_get_contents($file), true); if ($content) { $content['hangup'] = true; $content['hangup_ip'] = $ip; $content['hangup_time'] = time(); $content['timestamp'] = time(); file_put_contents($file, json_encode($content)); logEvent('hangup', $room_safe, $ip); } } echo json_encode([ 'status' => 'hangup saved', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } // Получение данных комнаты if (isset($data['get'])) { if (file_exists($file)) { $content = @json_decode(file_get_contents($file), true); if ($content) { // Обновляем timestamp при каждом запросе $content['timestamp'] = time(); file_put_contents($file, json_encode($content)); // Подсчитываем участников $participants = 0; if (isset($content['offer'])) $participants++; if (isset($content['answer'])) $participants++; $content['full'] = ($participants >= MAX_PARTICIPANTS); $content['participants'] = $participants; // Проверяем, можно ли IP повторно присоединиться $content['can_rejoin'] = canIPRejoin($content, $ip); echo json_encode($content); logEvent('room_data_fetched', $room_safe, $ip); } else { echo json_encode(['status' => 'no data', 'csrf_token' => $_SESSION['csrf_token']]); } } else { echo json_encode(['status' => 'room not found', 'csrf_token' => $_SESSION['csrf_token']]); } exit; } // Неизвестный запрос echo json_encode([ 'status' => 'error', 'message' => 'Invalid request', 'csrf_token' => $_SESSION['csrf_token'] ]); exit; } ?>
Загрузка комнат...