-
{$title}
-
{$message}
";
-
- if (Config::isEnvironment('development') && isset($error['file'])) {
- echo "
- File: {$error['file']}
- Line: {$error['line']}
- Type: " . ($error['error_type'] ?? $error['type'] ?? 'unknown') . "
-
";
- }
-
- echo "
-
-";
- }
-
- /**
- * Perform cleanup tasks on shutdown
- */
- private static function performCleanup()
- {
- // Clean up expired sessions or temporary files if needed
- // This could be expanded based on application needs
-
- // Example: Clean up old temp files
- $tempDir = sys_get_temp_dir();
- $pattern = $tempDir . '/dodgers_*';
-
- foreach (glob($pattern) as $file) {
- // Remove files older than 1 hour
- if (filemtime($file) < time() - 3600) {
- @unlink($file);
- }
- }
- }
-
- /**
- * Handle API errors with JSON response
- */
- public static function apiError($message, $code = 500, $details = null)
- {
- $error = [
- 'success' => false,
- 'error' => $message,
- 'code' => $code,
- 'timestamp' => time()
- ];
-
- if (Config::isEnvironment('development') && $details) {
- $error['details'] = $details;
- }
-
- http_response_code($code);
- header('Content-Type: application/json');
- echo json_encode($error);
- }
-
- /**
- * Log security events
- */
- public static function logSecurityEvent($event, $details = [])
- {
- $logEntry = [
- 'type' => 'security_event',
- 'event' => $event,
- 'details' => $details,
- 'timestamp' => date('Y-m-d H:i:s'),
- 'remote_ip' => Security::getClientIP(),
- 'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
- 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
- 'session_id' => session_id()
- ];
-
- self::logError($logEntry);
- }
-
- /**
- * Log performance metrics
- */
- public static function logPerformance($operation, $duration, $details = [])
- {
- $logEntry = [
- 'type' => 'performance',
- 'operation' => $operation,
- 'duration' => $duration,
- 'details' => $details,
- 'timestamp' => date('Y-m-d H:i:s'),
- 'remote_ip' => Security::getClientIP(),
- 'session_id' => session_id()
- ];
-
- self::logError($logEntry);
- }
-}
diff --git a/includes/autoloader.php b/includes/autoloader.php
deleted file mode 100644
index 566d2f8..0000000
--- a/includes/autoloader.php
+++ /dev/null
@@ -1,103 +0,0 @@
- __DIR__ . '/../app/',
- 'Models\\' => __DIR__ . '/../models/',
- 'Controllers\\' => __DIR__ . '/../controllers/',
- 'Utils\\' => __DIR__ . '/../utils/',
- 'Services\\' => __DIR__ . '/../services/',
- 'Middleware\\' => __DIR__ . '/../middleware/'
- ];
-
- // Check for exact class match first (for legacy classes)
- $legacyMappings = [
- 'Config' => __DIR__ . '/Config.php',
- 'Security' => __DIR__ . '/../utils/Security.php',
- 'Validation' => __DIR__ . '/../utils/Validation.php',
- 'Database' => __DIR__ . '/Database.php',
- 'UserModel' => __DIR__ . '/../models/UserModel.php',
- 'ChatMessageModel' => __DIR__ . '/../models/ChatMessageModel.php',
- 'ActiveViewerModel' => __DIR__ . '/../models/ActiveViewerModel.php'
- ];
-
- // First check legacy mappings
- if (isset($legacyMappings[$className])) {
- $file = $legacyMappings[$className];
- if (file_exists($file)) {
- require_once $file;
- return;
- }
- }
-
- // Check PSR-4 mappings
- foreach ($prefixes as $prefix => $baseDir) {
- $len = strlen($prefix);
- if (strncmp($prefix, $className, $len) !== 0) {
- continue;
- }
-
- $relativeClass = substr($className, $len);
- $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
-
- if (file_exists($file)) {
- require_once $file;
- if (Config::isDebug()) {
- error_log("Autoloaded: {$className} from {$file}");
- }
- return;
- }
- }
-
- // Class not found - this will throw an exception from spl_autoload_register
- if (Config::isDebug()) {
- error_log("Autoloader: Class {$className} not found in any mapping");
- }
-});
-
-/**
- * Optional: Load additional helper functions
- */
-if (file_exists(__DIR__ . '/helpers.php')) {
- require_once __DIR__ . '/helpers.php';
-}
-
-/**
- * Optional: Load composer autoloader if it exists (for future dependencies)
- */
-$composerAutoloader = __DIR__ . '/../vendor/autoload.php';
-if (file_exists($composerAutoloader)) {
- require_once $composerAutoloader;
-}
-
-// Verify critical classes are loaded
-$criticalClasses = [
- 'Config',
- 'Security',
- 'Validation',
- 'Database'
-];
-
-foreach ($criticalClasses as $class) {
- if (!class_exists($class, false)) {
- // Try to load manually
- $legacyPaths = [
- 'Config' => 'includes/Config.php',
- 'Security' => 'utils/Security.php',
- 'Validation' => 'utils/Validation.php',
- 'Database' => 'includes/Database.php'
- ];
-
- if (isset($legacyPaths[$class])) {
- $path = __DIR__ . '/../' . $legacyPaths[$class];
- if (file_exists($path)) {
- require_once $path;
- }
- }
- }
-}
diff --git a/index.php b/index.php
index 208a903..35104f0 100644
--- a/index.php
+++ b/index.php
@@ -1,35 +1,26 @@
handleSSE($_GET['user_id']);
- exit;
-}
+$maxMessages = 100; // Keep last 100 messages
// Clean up old viewers (inactive for more than 10 seconds)
function cleanupViewers() {
@@ -51,38 +42,26 @@ function cleanupViewers() {
// Handle API requests for stream status
if (isset($_GET['api']) && $_GET['api'] === 'stream_status') {
header('Content-Type: application/json');
- header('Cache-Control: no-cache, no-store, must-revalidate');
- header('Pragma: no-cache');
- header('Expires: 0');
+ header('Access-Control-Allow-Origin: *');
- $corsOrigins = Config::get('cors.allowed_origins', []);
- if (in_array($_SERVER['HTTP_ORIGIN'] ?? '', $corsOrigins)) {
- header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
- }
-
- $streamUrl = $streamBaseUrl . '/stream.m3u8';
+ $streamUrl = 'http://38.64.28.91:23456/stream.m3u8';
$online = false;
- if (Security::checkRateLimit(Security::getClientIP(), 'stream_status', 10, 60)) {
- $context = stream_context_create([
- 'http' => [
- 'method' => 'GET',
- 'header' => "User-Agent: Mozilla/5.0\r\n",
- 'timeout' => 5 // Quick check
- ]
- ]);
+ $context = stream_context_create([
+ 'http' => [
+ 'method' => 'GET',
+ 'header' => "User-Agent: Mozilla/5.0\r\n",
+ 'timeout' => 5 // Quick check
+ ]
+ ]);
- $content = @file_get_contents($streamUrl, false, $context);
- Security::logSecurityEvent('stream_status_check', ['online' => $online]);
+ $content = @file_get_contents($streamUrl, false, $context);
- if ($content !== false && !empty($content)) {
- // Check if it looks like a valid m3u8
- if (str_starts_with($content, '#EXTM3U')) {
- $online = true;
- }
+ if ($content !== false && !empty($content)) {
+ // Check if it looks like a valid m3u8
+ if (str_starts_with($content, '#EXTM3U')) {
+ $online = true;
}
- } else {
- Security::logSecurityEvent('stream_status_rate_limited');
}
echo json_encode(['online' => $online]);
@@ -91,29 +70,14 @@ if (isset($_GET['api']) && $_GET['api'] === 'stream_status') {
// Handle proxy requests for the stream
if (isset($_GET['proxy']) && $_GET['proxy'] === 'stream') {
- // Check rate limiting
- if (!Security::checkRateLimit(Security::getClientIP(), 'proxy_stream')) {
- Security::logSecurityEvent('proxy_stream_rate_limited');
- http_response_code(429);
- echo json_encode(['error' => 'Too many requests. Please try again later.']);
- exit;
- }
-
- $streamUrl = $streamBaseUrl . '/stream.m3u8';
-
+ $streamUrl = 'http://38.64.28.91:23456/stream.m3u8';
+
// Set appropriate headers for m3u8 content
header('Content-Type: application/vnd.apple.mpegurl');
- header('Cache-Control: no-cache, no-store, must-revalidate');
- header('Pragma: no-cache');
- header('Expires: 0');
-
- $corsOrigins = Config::get('cors.allowed_origins', []);
- if (in_array($_SERVER['HTTP_ORIGIN'] ?? '', $corsOrigins)) {
- header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
- header('Access-Control-Allow-Methods: GET, OPTIONS');
- header('Access-Control-Allow-Headers: Range');
- }
-
+ header('Access-Control-Allow-Origin: *');
+ header('Access-Control-Allow-Methods: GET, OPTIONS');
+ header('Access-Control-Allow-Headers: Range');
+
// Fetch and output the m3u8 content
$context = stream_context_create([
'http' => [
@@ -122,39 +86,33 @@ if (isset($_GET['proxy']) && $_GET['proxy'] === 'stream') {
'timeout' => 10
]
]);
-
+
$content = @file_get_contents($streamUrl, false, $context);
-
+
if ($content !== false) {
// Parse and update the m3u8 content to use our proxy for .ts segments
$lines = explode("\n", $content);
$updatedContent = [];
-
+
foreach ($lines as $line) {
$line = trim($line);
if (!empty($line) && !str_starts_with($line, '#')) {
// This is a .ts segment URL
if (strpos($line, 'http') === 0) {
- // Absolute URL - validate it first
- if (Security::isValidStreamUrl($line)) {
- $updatedContent[] = '?proxy=segment&url=' . urlencode($line);
- }
+ // Absolute URL
+ $updatedContent[] = '?proxy=segment&url=' . urlencode($line);
} else {
// Relative URL
- $segmentUrl = $streamBaseUrl . '/' . $line;
- if (Security::isValidStreamUrl($segmentUrl)) {
- $updatedContent[] = '?proxy=segment&url=' . urlencode($segmentUrl);
- }
+ $baseUrl = 'http://38.64.28.91:23456/';
+ $updatedContent[] = '?proxy=segment&url=' . urlencode($baseUrl . $line);
}
} else {
$updatedContent[] = $line;
}
}
-
- Security::logSecurityEvent('proxy_stream_success');
+
echo implode("\n", $updatedContent);
} else {
- Security::logSecurityEvent('proxy_stream_failed', ['url' => $streamUrl]);
http_response_code(500);
echo "Failed to fetch stream";
}
@@ -163,31 +121,17 @@ if (isset($_GET['proxy']) && $_GET['proxy'] === 'stream') {
// Handle proxy requests for .ts segments
if (isset($_GET['proxy']) && $_GET['proxy'] === 'segment' && isset($_GET['url'])) {
- // Check rate limiting
- if (!Security::checkRateLimit(Security::getClientIP(), 'proxy_segment')) {
- Security::logSecurityEvent('proxy_segment_rate_limited');
- http_response_code(429);
- exit;
- }
-
- $segmentUrl = Security::sanitizeInput($_GET['url'], 'url');
-
- // Validate URL to prevent SSRF attacks
- if (!$segmentUrl || !Security::isValidStreamUrl($segmentUrl)) {
- Security::logSecurityEvent('proxy_segment_invalid_url', ['url' => $_GET['url'] ?? '']);
+ $segmentUrl = urldecode($_GET['url']);
+
+ // Validate URL to prevent abuse
+ if (strpos($segmentUrl, 'http://38.64.28.91:23456/') !== 0) {
http_response_code(403);
- echo "Invalid segment URL";
exit;
}
-
+
header('Content-Type: video/mp2t');
- header('Cache-Control: public, max-age=3600'); // Cache segments for 1 hour
-
- $corsOrigins = Config::get('cors.allowed_origins', []);
- if (in_array($_SERVER['HTTP_ORIGIN'] ?? '', $corsOrigins)) {
- header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
- }
-
+ header('Access-Control-Allow-Origin: *');
+
$context = stream_context_create([
'http' => [
'method' => 'GET',
@@ -195,16 +139,13 @@ if (isset($_GET['proxy']) && $_GET['proxy'] === 'segment' && isset($_GET['url'])
'timeout' => 10
]
]);
-
+
$content = @file_get_contents($segmentUrl, false, $context);
-
+
if ($content !== false) {
- Security::logSecurityEvent('proxy_segment_success');
echo $content;
} else {
- Security::logSecurityEvent('proxy_segment_failed', ['url' => $segmentUrl]);
http_response_code(500);
- echo "Failed to fetch segment";
}
exit;
}
@@ -212,223 +153,151 @@ if (isset($_GET['proxy']) && $_GET['proxy'] === 'segment' && isset($_GET['url'])
// Handle chat actions
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
header('Content-Type: application/json');
-
- $action = $_POST['action'];
-
- // Validate the action parameter
- if (!preg_match('/^[a-z_]+$/', $action)) {
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'Invalid action parameter']);
- Security::logSecurityEvent('invalid_chat_action', ['action' => $action]);
+
+ // Admin actions
+ if ($_POST['action'] === 'delete_message' && $isAdmin && isset($_POST['message_id'])) {
+ $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
+ $messages = array_filter($messages, function($msg) {
+ return $msg['id'] !== $_POST['message_id'];
+ });
+ $messages = array_values($messages); // Re-index array
+ file_put_contents($chatFile, json_encode($messages));
+ echo json_encode(['success' => true]);
exit;
}
-
- // Admin-only actions
- if (in_array($action, ['delete_message', 'clear_chat', 'ban_user'])) {
- if (!$isAdmin) {
- http_response_code(403);
- echo json_encode(['success' => false, 'error' => 'Admin access required']);
- Security::logSecurityEvent('unauthorized_admin_action', ['action' => $action, 'ip' => Security::getClientIP()]);
- exit;
- }
-
- // Rate limiting for admin actions
- if (!Security::checkRateLimit(Security::getClientIP(), 'admin_actions', 10, 60)) {
- http_response_code(429);
- echo json_encode(['success' => false, 'error' => 'Too many admin actions. Please wait.']);
- Security::logSecurityEvent('admin_rate_limited');
- exit;
- }
+
+ if ($_POST['action'] === 'clear_chat' && $isAdmin) {
+ file_put_contents($chatFile, json_encode([]));
+ echo json_encode(['success' => true]);
+ exit;
}
-
- // Handle different actions
- switch ($action) {
- case 'delete_message':
- if (!isset($_POST['message_id']) || !preg_match('/^[a-zA-Z0-9]+$/', $_POST['message_id'])) {
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'Invalid message ID']);
- exit;
+
+ if ($_POST['action'] === 'ban_user' && $isAdmin && isset($_POST['user_id'])) {
+ $banned = file_exists($bannedFile) ? json_decode(file_get_contents($bannedFile), true) : [];
+ if (!in_array($_POST['user_id'], $banned)) {
+ $banned[] = $_POST['user_id'];
+ file_put_contents($bannedFile, json_encode($banned));
+ }
+ echo json_encode(['success' => true]);
+ exit;
+ }
+
+ if ($_POST['action'] === 'heartbeat') {
+ $userId = $_SESSION['user_id'];
+ $nickname = isset($_POST['nickname']) ? htmlspecialchars(substr($_POST['nickname'], 0, 20)) : 'Anonymous';
+
+ $viewers = file_exists($viewersFile) ? json_decode(file_get_contents($viewersFile), true) : [];
+
+ // Update or add viewer
+ $found = false;
+ foreach ($viewers as &$viewer) {
+ if ($viewer['user_id'] === $userId) {
+ $viewer['last_seen'] = time();
+ $viewer['nickname'] = $nickname;
+ $viewer['is_admin'] = $isAdmin;
+ $found = true;
+ break;
}
-
- $messageIdToDelete = $_POST['message_id'];
- $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
- $filteredMessages = array_filter($messages, function($msg) use ($messageIdToDelete) {
- return $msg['id'] !== $messageIdToDelete;
- });
- $filteredMessages = array_values($filteredMessages);
- file_put_contents($chatFile, json_encode($filteredMessages));
-
- Security::logSecurityEvent('message_deleted', ['message_id' => $messageIdToDelete]);
- echo json_encode(['success' => true]);
- exit;
-
- case 'clear_chat':
- file_put_contents($chatFile, json_encode([]));
- Security::logSecurityEvent('chat_cleared');
- echo json_encode(['success' => true]);
- exit;
-
- case 'ban_user':
- if (!isset($_POST['user_id'])) {
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'User ID required']);
- exit;
- }
-
- $bannedUsers = file_exists($bannedFile) ? json_decode(file_get_contents($bannedFile), true) : [];
- if (!in_array($_POST['user_id'], $bannedUsers)) {
- $bannedUsers[] = $_POST['user_id'];
- file_put_contents($bannedFile, json_encode($bannedUsers));
- }
-
- Security::logSecurityEvent('user_banned', ['user_id' => $_POST['user_id']]);
- echo json_encode(['success' => true]);
- exit;
-
- case 'heartbeat':
- // Validate heartbeat data
- $heartbeatValidation = Validation::validateHeartbeat($_POST);
- if (!$heartbeatValidation['valid']) {
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'Invalid heartbeat data']);
- exit;
- }
-
- $userId = $_SESSION['user_id'];
- $nickname = $heartbeatValidation['validated']['nickname'] ?? 'Anonymous';
-
- $viewers = file_exists($viewersFile) ? json_decode(file_get_contents($viewersFile), true) : [];
-
- // Update or add viewer
- $found = false;
- foreach ($viewers as &$viewer) {
- if ($viewer['user_id'] === $userId) {
- $viewer['last_seen'] = time();
- $viewer['nickname'] = $nickname;
- $viewer['is_admin'] = $isAdmin;
- $found = true;
- break;
- }
- }
-
- if (!$found) {
- $viewers[] = [
- 'user_id' => $userId,
- 'nickname' => $nickname,
- 'last_seen' => time(),
- 'is_admin' => $isAdmin
- ];
- }
-
- file_put_contents($viewersFile, json_encode($viewers));
- $viewerCount = cleanupViewers();
-
- echo json_encode(['success' => true, 'viewer_count' => $viewerCount]);
- exit;
-
- case 'send':
- if (!isset($_POST['message']) || !isset($_POST['nickname'])) {
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'Message and nickname required']);
- exit;
- }
-
- // Rate limiting for message sending
- if (!Security::checkRateLimit($_SESSION['user_id'], 'send_message', 5, 60)) {
- echo json_encode(['success' => false, 'error' => 'Too many messages. Please wait before sending another.']);
- exit;
- }
-
- // Validate message data
- $messageValidation = Validation::validateMessageSend($_POST);
- if (!$messageValidation['valid']) {
- echo json_encode(['success' => false, 'error' => 'Validation failed: ' . implode(', ', array_values($messageValidation['errors']))]);
- exit;
- }
-
- $userId = $_SESSION['user_id'];
- $nickname = $messageValidation['validated']['nickname'];
- $message = $messageValidation['validated']['message'];
-
- // Check if user is banned
- $bannedUsers = file_exists($bannedFile) ? json_decode(file_get_contents($bannedFile), true) : [];
- if (in_array($userId, $bannedUsers)) {
- echo json_encode(['success' => false, 'error' => 'You are banned from chat']);
- exit;
- }
-
- $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
-
- $newMessage = [
- 'id' => Security::generateSecureToken(8), // More secure than uniqid()
+ }
+
+ if (!$found) {
+ $viewers[] = [
'user_id' => $userId,
- 'nickname' => htmlspecialchars($nickname, ENT_QUOTES, 'UTF-8'),
- 'message' => htmlspecialchars($message, ENT_QUOTES, 'UTF-8'),
+ 'nickname' => $nickname,
+ 'last_seen' => time(),
+ 'is_admin' => $isAdmin
+ ];
+ }
+
+ file_put_contents($viewersFile, json_encode($viewers));
+ $viewerCount = cleanupViewers();
+
+ echo json_encode(['success' => true, 'viewer_count' => $viewerCount]);
+ exit;
+ }
+
+ if ($_POST['action'] === 'send' && isset($_POST['message']) && isset($_POST['nickname'])) {
+ $nickname = htmlspecialchars(substr($_POST['nickname'], 0, 20));
+ $message = htmlspecialchars(substr($_POST['message'], 0, 1000));
+ $userId = $_SESSION['user_id'];
+
+ // Check if user is banned
+ $banned = file_exists($bannedFile) ? json_decode(file_get_contents($bannedFile), true) : [];
+ if (in_array($userId, $banned)) {
+ echo json_encode(['success' => false, 'error' => 'You are banned from chat']);
+ exit;
+ }
+
+ if (!empty($nickname) && !empty($message)) {
+ $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
+
+ $newMessage = [
+ 'id' => uniqid(),
+ 'user_id' => $userId,
+ 'nickname' => $nickname,
+ 'message' => $message,
'timestamp' => time(),
'time' => date('M j, H:i'),
'is_admin' => $isAdmin
];
-
- $messages[] = $newMessage;
-
+
+ array_push($messages, $newMessage);
+
// Keep only last N messages
if (count($messages) > $maxMessages) {
$messages = array_slice($messages, -$maxMessages);
}
-
+
file_put_contents($chatFile, json_encode($messages));
-
- Security::logSecurityEvent('message_sent', ['message_id' => $newMessage['id']]);
echo json_encode(['success' => true, 'message' => $newMessage]);
- exit;
-
- case 'fetch':
- $lastId = isset($_POST['last_id']) ? trim($_POST['last_id']) : '';
- $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
-
- // Find new messages only
- $newMessages = [];
- $foundLast = empty($lastId);
-
- foreach ($messages as $msg) {
- if ($foundLast) {
- $newMessages[] = $msg;
- }
- if ($msg['id'] === $lastId) {
- $foundLast = true;
- }
+ } else {
+ echo json_encode(['success' => false, 'error' => 'Invalid input']);
+ }
+ exit;
+ }
+
+ if ($_POST['action'] === 'fetch') {
+ $lastId = isset($_POST['last_id']) ? $_POST['last_id'] : '';
+ $messages = file_exists($chatFile) ? json_decode(file_get_contents($chatFile), true) : [];
+
+ // Find new messages only
+ $newMessages = [];
+ $foundLast = empty($lastId);
+
+ foreach ($messages as $msg) {
+ if ($foundLast) {
+ $newMessages[] = $msg;
}
-
- // If lastId wasn't found, return all messages (initial load or refresh)
- if (!$foundLast && !empty($lastId)) {
- $newMessages = $messages;
+ if ($msg['id'] === $lastId) {
+ $foundLast = true;
}
-
- // Get viewer count
- $viewerCount = cleanupViewers();
-
- // Determine if we should send all messages (for initial load or after admin actions)
- $sendAllMessages = empty($lastId) || !$foundLast;
-
- echo json_encode([
- 'success' => true,
- 'messages' => $newMessages,
- 'all_messages' => $sendAllMessages ? $messages : null,
- 'message_count' => count($messages),
- 'viewer_count' => $viewerCount,
- 'is_admin' => $isAdmin
- ]);
- exit;
-
- case 'get_user_id':
- echo json_encode(['success' => true, 'user_id' => $_SESSION['user_id'], 'is_admin' => $isAdmin]);
- exit;
-
- default:
- http_response_code(400);
- echo json_encode(['success' => false, 'error' => 'Unknown action']);
- Security::logSecurityEvent('unknown_chat_action', ['action' => $action]);
- exit;
+ }
+
+ // If lastId wasn't found, return all messages (initial load or refresh)
+ if (!$foundLast && !empty($lastId)) {
+ $newMessages = $messages;
+ }
+
+ // Get viewer count
+ $viewerCount = cleanupViewers();
+
+ // Determine if we should send all messages (for initial load or after admin actions)
+ $sendAllMessages = empty($lastId) || !$foundLast;
+
+ echo json_encode([
+ 'success' => true,
+ 'messages' => $newMessages,
+ 'all_messages' => $sendAllMessages ? $messages : null,
+ 'message_count' => count($messages),
+ 'viewer_count' => $viewerCount,
+ 'is_admin' => $isAdmin
+ ]);
+ exit;
+ }
+
+ if ($_POST['action'] === 'get_user_id') {
+ echo json_encode(['success' => true, 'user_id' => $_SESSION['user_id'], 'is_admin' => $isAdmin]);
+ exit;
}
}
?>
@@ -438,7 +307,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {