prepare("SELECT * FROM membre WHERE id = :id_membre"); $stmt->execute(['id_membre' => $id_membre]); $membre = $stmt->fetch(); if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['action']) && $_POST['action'] === 'update_bg') { $chatbox_bg = $_POST['chatbox_bg'] ?? null; $message_bg = $_POST['message_bg'] ?? null; $channel_id = (int)$_POST['channel_id']; $stmt = $pdo->prepare("INSERT INTO channel_backgrounds (channel_id, chatbox_bg, message_bg) VALUES (:channel_id, :chatbox_bg, :message_bg) ON DUPLICATE KEY UPDATE chatbox_bg = :chatbox_bg, message_bg = :message_bg"); $stmt->execute([ 'channel_id' => $channel_id, 'chatbox_bg' => $chatbox_bg, 'message_bg' => $message_bg ]); exit; } if (!empty($_FILES['audio']) && $_FILES['audio']['error'] === UPLOAD_ERR_OK) { $tmp = $_FILES['audio']['tmp_name']; $orig = basename($_FILES['audio']['name']); $ext = strtolower(pathinfo($orig, PATHINFO_EXTENSION)); // n’accepter que certaines extensions if (!in_array($ext, ['ogg','webm','wav','mp3'])) { http_response_code(400); exit('Type audio non autorisé'); } // Génération d’un nom unique $filename = time() . '_' . bin2hex(random_bytes(5)) . '.' . $ext; $dest = __DIR__ . '/vocal/' . $filename; $relPath = 'vocal/' . $filename; if (!move_uploaded_file($tmp, $dest)) { http_response_code(500); exit('Erreur de sauvegarde du fichier'); } // INSERT en laissant message vide et en mettant le chemin dans fichier $stmt = $pdo->prepare(" INSERT INTO chatcanalweb (id_membre, channel_id, message, fichier, created_at) VALUES (:user, :channel, '', :file, NOW()) "); $stmt->execute([ ':user' => $_SESSION['id_membre'], ':channel' => intval($_POST['channel_id']), ':file' => $relPath ]); header('Location: chat.php?channel_id=' . intval($_POST['channel_id'])); exit; } // … reste de votre traitement des messages texte … // ── Gestion de la publication d’invitation ── if ($_SERVER["REQUEST_METHOD"] === "POST" && ($_POST['action'] ?? '') === 'publish_invite') { $type = $_POST['type']; // 'channel' ou 'group' $channel_id = (int)$_POST['channel_id']; // 1) Récupération du code d’invitation du canal // 1) Récupération des infos du canal $stmtChan = $pdo->prepare("SELECT invite_code, nom AS channel_name FROM channels WHERE id = ?"); $stmtChan->execute([$channel_id]); $chanInfo = $stmtChan->fetch(PDO::FETCH_ASSOC); $invite_code = $chanInfo['invite_code'] ?? ''; $channel_name = $chanInfo['channel_name'] ?? 'Nom inconnu'; // 2) Récupération du groupe lié $stmt = $pdo->prepare("SELECT group_id FROM group_channels WHERE channel_id = ?"); $stmt->execute([$channel_id]); $grp = $stmt->fetch(PDO::FETCH_ASSOC); $group_id = $grp['group_id'] ?? null; // 3) Récupération des infos du groupe if ($group_id) { $s2 = $pdo->prepare(" SELECT g.invite_code, g.name AS group_name, g.image_path, m.pseudo AS creator_pseudo FROM groups g LEFT JOIN membre m ON g.created_by = m.id WHERE g.id = ? "); $s2->execute([$group_id]); $groupInfo = $s2->fetch(PDO::FETCH_ASSOC); } // 4) Construction de la carte HTML ob_start(); ?>
Bannière du groupe/canal
@ ID canal : Cliquez ici pour copier le lien du canal

Code canal :

ID groupe :

cliquez ici pour copier le lien du groupe

Code groupe :

Rejoindre le canal Rejoindre le groupe
prepare(" INSERT INTO chatcanalweb (id_membre, message, channel_id, created_at, is_system) VALUES (:id, :msg, :chan, NOW(), 1) "); $ins->execute([ 'id' => $id_membre, 'msg' => $cardHtml, 'chan' => $channel_id ]); // On répond JSON pour le fetch() echo json_encode(['status'=>'ok']); exit; } // Fonction pour vérifier les permissions function hasPermission($pdo, $channelId, $userId, $requiredRole) { // Le créateur du canal a tous les droits $stmt = $pdo->prepare("SELECT created_by FROM channels WHERE id = ?"); $stmt->execute([$channelId]); if ($stmt->fetchColumn() == $userId) { return true; } // Vérifier le rôle dans channel_roles $stmt = $pdo->prepare("SELECT role FROM channel_roles WHERE channel_id = ? AND member_id = ?"); $stmt->execute([$channelId, $userId]); $role = $stmt->fetchColumn(); // Définir la hiérarchie des rôles $hierarchy = [ 'visiteur' => 0, 'utilisateur' => 1, 'moderateur' => 2, 'administrateur' => 3 ]; return isset($hierarchy[$role]) && $hierarchy[$role] >= $hierarchy[$requiredRole]; } // Vérification des liens d'invitation if (!empty($_GET['invite']) && !empty($_GET['channel_id'])) { $channel_id = (int)$_GET['channel_id']; $stmt = $pdo->prepare("SELECT is_private, private_type FROM channels WHERE id = ?"); $stmt->execute([$channel_id]); $channel = $stmt->fetch(); if ($channel && $channel['is_private'] && $channel['private_type'] === 'link') { $_SESSION['channel_access'][$channel_id] = true; // Ajouter l'utilisateur au canal s'il n'est pas déjà membre $stmt = $pdo->prepare("INSERT IGNORE INTO channel_members (channel_id, member_id, joined_at) VALUES (?, ?, NOW())"); $stmt->execute([$channel_id, $_SESSION['id_membre']]); } } // En haut du fichier, après avoir chargé les channels include('group_functions.php'); $userGroups = get_user_groups($pdo, $id_membre); $groupChannels = []; foreach ($userGroups as $group) { $groupChannels[$group['id']] = get_group_channels($pdo, $group['id'], $id_membre); } function extractZipAndFind3DModel($zipPath, $extractTo) { $zip = new ZipArchive; if ($zip->open($zipPath) === TRUE) { $zip->extractTo($extractTo); $zip->close(); $allowed3D = ['glb', 'gltf', 'obj', 'fbx', 'usdz']; $dirIterator = new RecursiveDirectoryIterator($extractTo); $iterator = new RecursiveIteratorIterator($dirIterator); foreach ($iterator as $file) { if ($file->isFile()) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (in_array($ext, $allowed3D)) { return $file->getPathname(); } } } } return ''; } function cleanHtml($html, $allowed_tags) { // 1) Chargement et parsing libxml_use_internal_errors(true); $dom = new DOMDocument(); // on force l'encodage UTF-8 et on enlève wrapper $dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // 2) On parcourt tous les noeuds foreach ($dom->getElementsByTagName('*') as $el) { $tag = $el->nodeName; // a) Balise non autorisée → on remplace par son contenu if (stripos($allowed_tags, "<{$tag}>") === false) { $frag = $dom->createDocumentFragment(); while ($el->firstChild) { $frag->appendChild($el->firstChild); } $el->parentNode->replaceChild($frag, $el); continue; } // b) Définition des attributs autorisés par balise switch ($tag) { case 'img': $keep = ['src', 'width', 'height', 'class', 'style', 'id']; break; case 'a': $keep = ['href', 'id', 'class', 'style']; break; case 'div': $keep = ['align', 'class', 'style', 'id']; break; case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'p': case 'span': case 'blockquote': case 'i': case 'b': case 'u': case 'audio': case 'source': case 'audio': $keep = ['class', 'style', 'id']; break; case 'table': case 'tr': case 'td': case 'th': case 'tbody': $keep = ['class', 'style', 'id']; break; default: $keep = ['style']; } // c) Filtrage et sécurisation des attributs foreach (iterator_to_array($el->attributes) as $attr) { $name = $attr->name; $value = $attr->value; if (!in_array($name, $keep)) { $el->removeAttribute($name); } else { // pour width/height on cast en int, sinon htmlentities if (in_array($name, ['width','height'])) { $value = (int) $value; } $el->setAttribute($name, htmlspecialchars($value, ENT_QUOTES)); } } } // 3) Retour du HTML purifié return $dom->saveHTML(); } // Vérification de l'accès au canal avant tout traitement if (!empty($_GET['channel_id'])) { $channel_id = (int)$_GET['channel_id']; // Vérification du bannissement $stmt = $pdo->prepare("SELECT 1 FROM channel_bans WHERE channel_id = ? AND banned_user_id = ? AND (expires_at IS NULL OR expires_at > NOW())"); $stmt->execute([$channel_id, $id_membre]); if ($stmt->fetchColumn()) { die("Vous avez été banni de ce canal"); } // Vérification du mute $stmt = $pdo->prepare("SELECT expires_at FROM channel_mutes WHERE channel_id = ? AND muted_user_id = ? AND (expires_at IS NULL OR expires_at > NOW())"); $stmt->execute([$channel_id, $id_membre]); $mute = $stmt->fetch(); if ($mute) { $expires = $mute['expires_at'] ? date('d/m/Y H:i', strtotime($mute['expires_at'])) : 'indéfiniment'; die("Vous êtes actuellement muet dans ce canal jusqu'au $expires"); } // Vérifier si le channel appartient à un groupe où l'utilisateur est membre $stmt = $pdo->prepare(" SELECT c.is_private, c.private_type, EXISTS( SELECT 1 FROM group_members gm JOIN group_channels gc ON gm.group_id = gc.group_id WHERE gm.member_id = :user_id AND gc.channel_id = c.id ) as in_group FROM channels c WHERE c.id = :channel_id "); $stmt->execute(['channel_id' => $channel_id, 'user_id' => $id_membre]); $channel = $stmt->fetch(); if ($channel) { if ($channel['is_private']) { // Si channel a un code, vérifier le code if ($channel['private_type'] === 'code' && empty($_SESSION['channel_access'][$channel_id])) { header("Location: verify_channel.php?channel_id=".$channel_id); exit(); } // Si simple lien ET pas dans le groupe, refuser else if ($channel['private_type'] === 'link' && !$channel['in_group']) { die("Accès refusé - Ce canal est privé"); } // Si dans le groupe, autoriser automatiquement else if ($channel['in_group']) { // Ajouter automatiquement comme membre si pas déjà $stmt = $pdo->prepare("INSERT IGNORE INTO channel_members (channel_id, member_id, joined_at) VALUES (?, ?, NOW())"); $stmt->execute([$channel_id, $id_membre]); } } } } // Traitement de la requête POST (envoi de message) if ($_SERVER["REQUEST_METHOD"] === "POST") { if ($_POST['action'] === 'ask_ai') { $userQuestion = trim($_POST['message']); file_put_contents('debug_ai.txt', $userQuestion); // debug temporaire $channel_id = (int)$_POST['channel_id']; $postData = [ "model" => "meta-llama/llama-4-scout-17b-16e-instruct", // ou celui que tu veux "messages" => [ ["role" => "system", "content" => "Tu es une IA intégrée dans un chat. Voici des infos : - Utilisateur : {$membre['pseudo']} (ID: {$id_membre}) - Rôle dans le canal de l'utilisateur qui te parle {$role} - soit direct quand tu répond, pas de blablainutile, pas de bonjour et ne pose jamais de question, soit direct ne passe pas par 4 chemin - Commandes disponibles : /help pour voir toute les commandes possible dans le Chat - possiblilité que l'utilisateur propose un jeu pile ou face, pierre feuille ciseau ou le pendu, il peu changer la calligraphie des texte, la taille la couleur, la position, faire des emoji, faire un partage decran, faire des audio faire des text a lien - Objectif : répondre utilement, proposer des actions ou aider à exécuter des commandes. Tu es une IA intégrée dans une plateforme de chat communautaire avancée. Tu assistes les utilisateurs et tu peux répondre à des questions ou proposer des actions. Tu structure correctement tes reponses utilise • des que tu fait des listes, des que tu a loccasion de fournir des liens url envoie hesite pas avec la balise a href nom du site/page /a tu utilise beaucoup de emoji pour rendre vivant tes reponses utilise jamais ce symbole ** dans tes reponses ces pas jolie - tu utilises ces balises : b - i - u - s - mark - span - br - interdiction de utiliser ces 5 balises:h1 h2 h3 h4 h5 - utilise tout le temps la balise p et utilise style= pour la taille, le padding et la couleur etc etc soit toujours épuré et jolie. toujours utiliser la balise p pour tout les text et paragraphe basique - pour rendre jolie les reponses et aussi pour les titre et moyen titre grace a style= font-size et utilise font-family directement dans la balise p exemple :

"user", "content" => "Voici une question d’un utilisateur dans le chat : $userQuestion"] ], "temperature" => 0.5, "max_tokens" => 3500 ]; $ch = curl_init("https://api.groq.com/openai/v1/chat/completions"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer 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", "Content-Type: application/json" ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData)); $apiResponse = curl_exec($ch); curl_close($ch); $data = json_decode($apiResponse, true); if (!isset($data['choices'][0]['message']['content'])) { file_put_contents("debug_groq.txt", $apiResponse); // pour savoir pourquoi Groq ne répond pas $reply = "Erreur : la réponse de l'IA est vide ou invalide."; } else { $reply = trim($data['choices'][0]['message']['content']); } $stmt = $pdo->prepare("INSERT INTO chatcanalweb (id_membre, message, channel_id, created_at, is_system) VALUES (:id, :msg, :channel_id, NOW(), 1)"); $stmt->execute([ 'id' => $id_membre, 'msg' => "[🤖 Réponse IA]
$reply", 'channel_id' => $channel_id ]); echo json_encode(['status' => 'ok']); exit; } $rawMessage = trim($_POST['message']); $isCommand = strpos($rawMessage, '/') === 0; $allowed_tags = '