'User not authenticated']); exit; } require_once 'db/config.php'; header('Content-Type: application/json'); $action = isset($_POST['action']) ? $_POST['action'] : ($_GET['action'] ?? ''); $current_user_id = $_SESSION['user_id']; try { switch ($action) { case 'get_new_messages': getNewMessages(); break; case 'send_message': sendMessage(); break; case 'create_room': createRoom(); break; case 'start_private_chat': startPrivateChat(); break; default: throw new Exception("Invalid action."); } } catch (Exception $e) { http_response_code(400); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } function sendMessage() { global $current_user_id; $message = trim($_POST['message'] ?? ''); $room_id = $_POST['room_id'] ?? null; if (empty($message) && empty($_FILES['attachment']['name'])) { throw new Exception("Message or attachment cannot be empty."); } if (!$room_id) { throw new Exception("Invalid room."); } $pdo = db(); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $has_attachment = false; $file_data = null; // Handle file upload if (isset($_FILES['attachment']) && $_FILES['attachment']['error'] == UPLOAD_ERR_OK) { $file = $_FILES['attachment']; if ($file['size'] > 100 * 1024 * 1024) { // 100MB limit throw new Exception("File size exceeds the 100MB limit."); } $upload_dir = 'uploads/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0775, true); } $file_name = uniqid() . '-' . basename($file['name']); $file_path = $upload_dir . $file_name; if (move_uploaded_file($file['tmp_name'], $file_path)) { $has_attachment = true; $file_data = [ 'name' => $file['name'], 'path' => $file_path, 'size' => $file['size'], 'type' => $file['type'] ]; } else { throw new Exception("Failed to upload file."); } } $pdo->beginTransaction(); $stmt = $pdo->prepare("INSERT INTO messages (user_id, room_id, message) VALUES (?, ?, ?)"); $stmt->execute([$current_user_id, $room_id, $message]); $message_id = $pdo->lastInsertId(); if ($has_attachment && $file_data) { $stmt = $pdo->prepare("INSERT INTO files (message_id, original_name, file_path, file_size, mime_type) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$message_id, $file_data['name'], $file_data['path'], $file_data['size'], $file_data['type']]); } $pdo->commit(); echo json_encode(['success' => true]); } function getNewMessages() { global $current_user_id; $roomId = $_GET['room_id'] ?? 0; $lastMessageId = $_GET['last_message_id'] ?? 0; if (empty($roomId)) { echo json_encode([]); exit; } $pdo = db(); // Check if user is a member of the room $stmt = $pdo->prepare("SELECT 1 FROM room_members WHERE room_id = ? AND user_id = ?"); $stmt->execute([$roomId, $current_user_id]); if ($stmt->fetchColumn() === false) { // If not a member, check if it's a public room (no members defined) $stmt = $pdo->prepare("SELECT COUNT(*) FROM room_members WHERE room_id = ?"); $stmt->execute([$roomId]); if ($stmt->fetchColumn() > 0) { http_response_code(403); throw new Exception("Access denied to room"); } } // Poll for new messages $startTime = time(); $timeout = 25; // 25 seconds timeout for long polling while (time() - $startTime < $timeout) { $stmt = $pdo->prepare(" SELECT m.id, m.message, m.created_at, u.username, f.original_name as file_name, f.file_path, f.file_size, f.mime_type as file_type FROM messages m JOIN users u ON m.user_id = u.id LEFT JOIN files f ON m.id = f.message_id WHERE m.room_id = ? AND m.id > ? ORDER BY m.id ASC "); $stmt->execute([$roomId, $lastMessageId]); $messages = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!empty($messages)) { echo json_encode($messages); exit; } // Wait for a short period before polling again sleep(1); } // If no new messages after timeout, return empty array echo json_encode([]); } function createRoom() { global $current_user_id; $room_name = trim($_POST['room_name'] ?? ''); if (empty($room_name)) { throw new Exception("Room name cannot be empty."); } $pdo = db(); $stmt = $pdo->prepare("INSERT INTO rooms (name, created_by) VALUES (?, ?)"); $stmt->execute([$room_name, $current_user_id]); $new_room_id = $pdo->lastInsertId(); $stmt = $pdo->prepare("INSERT INTO room_members (room_id, user_id) VALUES (?, ?)"); $stmt->execute([$new_room_id, $current_user_id]); echo json_encode(['success' => true, 'room_id' => $new_room_id]); } function startPrivateChat() { global $current_user_id; $other_user_id = $_POST['user_id'] ?? null; if (!$other_user_id || $other_user_id == $current_user_id) { throw new Exception("Invalid user ID."); } $pdo = db(); // Check if a private room already exists between the two users $stmt = $pdo->prepare(" SELECT r.id FROM rooms r JOIN room_members rm1 ON r.id = rm1.room_id JOIN room_members rm2 ON r.id = rm2.room_id WHERE r.is_private = 1 AND rm1.user_id = ? AND rm2.user_id = ? "); $stmt->execute([$current_user_id, $other_user_id]); $room = $stmt->fetch(); if ($room) { echo json_encode(['success' => true, 'room_id' => $room['id']]); } else { // Create a new private room $stmt = $pdo->prepare("INSERT INTO rooms (name, created_by, is_private) VALUES (?, ?, 1)"); $stmt->execute(["Private Chat", $current_user_id]); $new_room_id = $pdo->lastInsertId(); // Add both users to the new room $stmt = $pdo->prepare("INSERT INTO room_members (room_id, user_id) VALUES (?, ?), (?, ?)"); $stmt->execute([$new_room_id, $current_user_id, $new_room_id, $other_user_id]); echo json_encode(['success' => true, 'room_id' => $new_room_id]); } }