';
} elseif ($isFa) {
return '';
} elseif ($isCustomEmote) {
// Fetch emote path
static $ce_icons_cache;
if ($ce_icons_cache === null) {
try { $ce_icons_cache = db()->query("SELECT code, path FROM custom_emotes")->fetchAll(PDO::FETCH_KEY_PAIR); } catch (Exception $e) { $ce_icons_cache = []; }
}
if (isset($ce_icons_cache[$icon])) {
return '';
}
return '' . htmlspecialchars($icon) . '';
} else {
return '' . htmlspecialchars($icon) . '';
}
}
// Helper to parse markdown in content
function parse_markdown($text) {
if (empty($text)) return "";
// First escape HTML
$html = htmlspecialchars($text);
// Code blocks: ```language\ncontent```
$code_blocks = [];
$html = preg_replace_callback('/```(?:(\w+)\n)?([\s\S]*?)```/', function($matches) use (&$code_blocks) {
$lang = $matches[1] ?? 'text';
$content = $matches[2];
$placeholder = "__CODE_BLOCK_" . count($code_blocks) . "__";
$code_blocks[] = '
' . $content . '';
return $placeholder;
}, $html);
// Inline code: `content`
$inline_codes = [];
$html = preg_replace_callback('/`([^`\n]+)`/', function($matches) use (&$inline_codes) {
$content = $matches[1];
$placeholder = "__INLINE_CODE_" . count($inline_codes) . "__";
$inline_codes[] = '' . $content . '';
return $placeholder;
}, $html);
// Bold: **text**
$html = preg_replace('/\*\*([^*]+)\*\*/', '$1', $html);
// Italics: *text* or _text_
$html = preg_replace('/\*([^*]+)\*/', '$1', $html);
$html = preg_replace('/_([^_]+)_/', '$1', $html);
// Underline: __text__
$html = preg_replace('/__([^_]+)__/', '$1', $html);
// Strikethrough: ~~text~~
$html = preg_replace('/~~([^~]+)~~/', '$1', $html); $html = preg_replace('/^>>> ([\s\S]*$)/', '
$1', $html); // Hyperlinks: [text](url) $html = preg_replace('/\[([^\]]+)\]\(([^)]+)\)/', '$1', $html); // Pure links:
)/i', '$2', $html); $html = preg_replace('/(<\/h[1-3]>|<\/blockquote>)\s*(
\s*)/i', '$1', $html); // Re-insert inline code foreach ($inline_codes as $i => $code) { $html = str_replace("__INLINE_CODE_$i" . "__", $code, $html); } // Re-insert code blocks foreach ($code_blocks as $i => $block) { $html = str_replace("__CODE_BLOCK_$i" . "__", $block, $html); } return $html; } // Helper to parse emotes in content function parse_emotes($content, $username_to_mention = null) { static $custom_emotes_cache; if ($custom_emotes_cache === null) { try { $custom_emotes_cache = db()->query("SELECT name, path, code FROM custom_emotes")->fetchAll(); } catch (Exception $e) { $custom_emotes_cache = []; } } $result = parse_markdown($content); // Parse mentions if username provided if ($username_to_mention) { $mention_pattern = '/@' . preg_quote($username_to_mention, '/') . '\b/'; $result = preg_replace($mention_pattern, '@' . htmlspecialchars($username_to_mention) . '', $result); } foreach ($custom_emotes_cache as $ce) { $emote_html = ''; $result = str_replace($ce['code'], $emote_html, $result); } return $result; } requireLogin(); $user = getCurrentUser(); $current_user_id = $user['id']; // Fetch servers user is member of $stmt = db()->prepare(" SELECT s.* FROM servers s JOIN server_members sm ON s.id = sm.server_id WHERE sm.user_id = ? LIMIT 20 "); $stmt->execute([$current_user_id]); $servers = $stmt->fetchAll(); $is_dm_view = (isset($_GET['server_id']) && $_GET['server_id'] == 'dms') || !isset($_GET['server_id']) && empty($servers); if ($is_dm_view) { $active_server_id = 'dms'; // Fetch DM channels $stmt = db()->prepare(" SELECT c.id, u.display_name as other_user, u.avatar_url, u.status, u.id as other_user_id FROM channels c JOIN channel_members cm1 ON c.id = cm1.channel_id JOIN channel_members cm2 ON c.id = cm2.channel_id JOIN users u ON cm2.user_id = u.id WHERE c.type = 'dm' AND cm1.user_id = ? AND cm2.user_id != ? "); $stmt->execute([$current_user_id, $current_user_id]); $dm_channels = $stmt->fetchAll(); $active_channel_id = $_GET['channel_id'] ?? ($dm_channels[0]['id'] ?? 0); $channel_theme = null; // DMs don't have custom themes for now if ($active_channel_id) { // Fetch DM messages $stmt = db()->prepare(" SELECT m.*, u.display_name as username, u.username as login_name, u.avatar_url FROM messages m JOIN users u ON m.user_id = u.id WHERE m.channel_id = ? ORDER BY m.created_at ASC LIMIT 50 "); $stmt->execute([$active_channel_id]); $messages = $stmt->fetchAll(); $current_channel_name = 'Direct Message'; foreach($dm_channels as $dm) { if ($dm['id'] == $active_channel_id) { $current_channel_name = $dm['other_user']; break; } } } else { $messages = []; $current_channel_name = 'Direct Messages'; } $channels = []; $members = []; // Members list is different for DMs or hidden } else { $active_server_id = $_GET['server_id'] ?? ($servers[0]['id'] ?? 1); // Fetch channels $stmt = db()->prepare("SELECT * FROM channels WHERE server_id = ? ORDER BY position ASC, id ASC"); $stmt->execute([$active_server_id]); $all_channels = $stmt->fetchAll(); require_once 'includes/permissions.php'; $channels = []; foreach($all_channels as $c) { if (Permissions::canViewChannel($current_user_id, $c['id'])) { $channels[] = $c; } } $active_channel_id = $_GET['channel_id'] ?? ($channels[0]['id'] ?? 0); // Fetch active channel details for theme $active_channel = null; foreach($channels as $c) { if($c['id'] == $active_channel_id) { $active_channel = $c; break; } } $is_owner = false; $can_manage_channels = false; $can_manage_server = false; $active_server = null; foreach($servers as $s) { if($s['id'] == $active_server_id) { $active_server = $s; $is_owner = ($s['owner_id'] == $current_user_id); $can_manage_channels = Permissions::hasPermission($current_user_id, $active_server_id, Permissions::MANAGE_CHANNELS) || $is_owner; $can_manage_server = Permissions::hasPermission($current_user_id, $active_server_id, Permissions::MANAGE_SERVER) || Permissions::hasPermission($current_user_id, $active_server_id, Permissions::ADMINISTRATOR) || $is_owner; break; } } $channel_theme = $active_server['theme_color'] ?? null; $channel_type = $active_channel['type'] ?? 'chat'; $active_thread_id = $_GET['thread_id'] ?? null; $active_thread = null; if ($active_thread_id) { $stmt = db()->prepare("SELECT t.*, u.display_name as username, u.username as login_name FROM forum_threads t JOIN users u ON t.user_id = u.id WHERE t.id = ?"); $stmt->execute([$active_thread_id]); $active_thread = $stmt->fetch(); if ($active_thread) { $stmt = db()->prepare(" SELECT m.*, u.display_name as username, u.username as login_name, u.avatar_url, (SELECT r.color FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_color, (SELECT r.icon_url FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_icon FROM messages m JOIN users u ON m.user_id = u.id WHERE m.thread_id = ? ORDER BY m.created_at ASC "); $stmt->execute([$active_server_id, $active_server_id, $active_thread_id]); $messages = $stmt->fetchAll(); } } if (!$active_thread && $channel_type === 'rules') { $stmt = db()->prepare("SELECT * FROM channel_rules WHERE channel_id = ? ORDER BY position ASC"); $stmt->execute([$active_channel_id]); $rules = $stmt->fetchAll(); } elseif ($channel_type === 'autorole') { $stmt = db()->prepare("SELECT ca.*, r.name as role_name FROM channel_autoroles ca JOIN roles r ON ca.role_id = r.id WHERE ca.channel_id = ? ORDER BY ca.id ASC"); $stmt->execute([$active_channel_id]); $autoroles = $stmt->fetchAll(); } elseif ($channel_type === 'forum') { $filter_status = $_GET['status'] ?? 'all'; $status_where = ""; if ($filter_status === 'resolved') { $status_where = " AND t.solution_message_id IS NOT NULL"; } elseif ($filter_status === 'unresolved') { $status_where = " AND t.solution_message_id IS NULL"; } $stmt = db()->prepare(" SELECT t.*, u.display_name as username, u.username as login_name, u.avatar_url, (SELECT COUNT(*) FROM messages m WHERE m.thread_id = t.id) as message_count, (SELECT MAX(created_at) FROM messages m WHERE m.thread_id = t.id) as last_activity, (SELECT r.color FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_color, (SELECT r.icon_url FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_icon, (SELECT GROUP_CONCAT(CONCAT(ft.name, ':', ft.color) SEPARATOR '|') FROM thread_tags tt JOIN forum_tags ft ON tt.tag_id = ft.id WHERE tt.thread_id = t.id) as tags FROM forum_threads t JOIN users u ON t.user_id = u.id WHERE t.channel_id = ? " . $status_where . " ORDER BY last_activity DESC, t.created_at DESC "); $stmt->execute([$active_server_id, $active_server_id, $active_channel_id]); $threads = $stmt->fetchAll(); } else { // Fetch messages $display_limit = !empty($active_channel['message_limit']) ? (int)$active_channel['message_limit'] : 50; $stmt = db()->prepare(" SELECT m.*, u.display_name as username, u.username as login_name, u.avatar_url, (SELECT r.color FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_color, (SELECT r.icon_url FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_icon FROM messages m JOIN users u ON m.user_id = u.id WHERE m.channel_id = ? ORDER BY m.created_at ASC LIMIT " . $display_limit . " "); $stmt->execute([$active_server_id, $active_server_id, $active_channel_id]); $messages = $stmt->fetchAll(); } $current_channel_name = 'general'; foreach($channels as $c) if($c['id'] == $active_channel_id) $current_channel_name = $c['name']; // Fetch voice sessions for the sidebar $stmt_vs = db()->prepare(" SELECT vs.channel_id, vs.user_id, u.username, u.display_name, u.avatar_url FROM voice_sessions vs JOIN users u ON vs.user_id = u.id "); $stmt_vs->execute(); $voice_sessions = $stmt_vs->fetchAll(); $voice_users_by_channel = []; foreach($voice_sessions as $vs) { $voice_users_by_channel[$vs['channel_id']][] = $vs; } // Fetch members $stmt = db()->prepare(" SELECT u.id, u.display_name as username, u.username as login_name, u.avatar_url, u.status, (SELECT GROUP_CONCAT(r.id) FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ?) as role_ids, (SELECT r.color FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_color, (SELECT r.icon_url FROM roles r JOIN user_roles ur ON r.id = ur.role_id WHERE ur.user_id = u.id AND r.server_id = ? ORDER BY r.position DESC LIMIT 1) as role_icon FROM users u JOIN server_members sm ON u.id = sm.user_id WHERE sm.server_id = ? "); $stmt->execute([$active_server_id, $active_server_id, $active_server_id, $active_server_id]); $all_server_members = $stmt->fetchAll(); $members = []; foreach($all_server_members as $m) { if (Permissions::canViewChannel($m['id'], $active_channel_id)) { $members[] = $m; } } // Fetch all server roles $stmt = db()->prepare("SELECT * FROM roles WHERE server_id = ? ORDER BY position DESC"); $stmt->execute([$active_server_id]); $server_roles = $stmt->fetchAll(); } // SEO & Env tags $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Discord-like messaging app built with PHP'; $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; ?>
# | '; elseif ($active_channel['type'] === 'rules') echo ''; elseif ($active_channel['type'] === 'autorole') echo ''; elseif ($active_channel['type'] === 'forum') echo ''; elseif ($active_channel['type'] === 'voice') echo ''; else echo ''; if (!empty($active_channel['icon'])) { echo ' ' . renderRoleIcon($active_channel['icon'], '16px') . ''; } } ?>Vous ne disposez pas de la permission d\'envoyer des messages dans ce salon.'; } else { $allow_files = true; foreach($channels as $c) { if($c['id'] == $active_channel_id) { $allow_files = (bool)$c['allow_file_sharing']; break; } } ?>