setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Activer les clés étrangères $db->exec('PRAGMA foreign_keys = ON;'); // Si la base de données est nouvellement créée, initialiser le schéma if (!$db_exists) { init_database($db); } } catch (PDOException $e) { // En mode débogage, afficher l'erreur if (DEBUG_MODE) { echo "Erreur de connexion à la base de données: " . $e->getMessage(); } // Journaliser l'erreur error_log("Erreur de connexion à la base de données: " . $e->getMessage()); die("Une erreur s'est produite lors de la connexion à la base de données."); } } return $db; } /** * Initialiser la base de données avec le schéma et les données initiales * * @param PDO $db Instance de connexion à la base de données */ function init_database($db) { try { // Charger le fichier de schéma SQL $schema = file_get_contents(__DIR__ . '/../data/schema.sql'); // Exécuter toutes les requêtes SQL du schéma $db->exec($schema); return true; } catch (PDOException $e) { // En mode débogage, afficher l'erreur if (DEBUG_MODE) { echo "Erreur d'initialisation de la base de données: " . $e->getMessage(); } // Journaliser l'erreur error_log("Erreur d'initialisation de la base de données: " . $e->getMessage()); die("Une erreur s'est produite lors de l'initialisation de la base de données."); } } /** * ======== FONCTIONS D'ACCÈS AUX MONSTRES ======== */ /** * Récupérer tous les monstres * * @param string $sort_by Critère de tri ('name_asc', 'name_desc', 'quests_count', 'recent_quests') * @return array Liste des monstres */ function get_all_monsters($sort_by = 'name_asc') { $db = get_db_connection(); // Pour déboguer - log le paramètre de tri et la requête SQL error_log("Tri demandé: " . $sort_by); switch ($sort_by) { case 'name_desc': $sql = 'SELECT * FROM monsters ORDER BY name DESC'; $stmt = $db->query($sql); error_log("SQL exécuté: " . $sql); break; case 'quests_count': // Version compatible avec SQLite $sql = ' SELECT m.*, COUNT(q.id) as quest_count FROM monsters m LEFT JOIN quests q ON m.id = q.monster_id GROUP BY m.id ORDER BY quest_count DESC, m.name ASC '; $stmt = $db->query($sql); error_log("SQL exécuté: " . $sql); break; case 'recent_quests': // Version compatible avec SQLite $sql = ' SELECT m.*, CASE WHEN MAX(q.date) IS NULL THEN 0 ELSE 1 END as has_quests, MAX(q.date) as latest_quest FROM monsters m LEFT JOIN quests q ON m.id = q.monster_id GROUP BY m.id ORDER BY has_quests DESC, latest_quest DESC, m.name ASC '; $stmt = $db->query($sql); error_log("SQL exécuté: " . $sql); break; case 'name_asc': default: $sql = 'SELECT * FROM monsters ORDER BY name ASC'; $stmt = $db->query($sql); error_log("SQL exécuté: " . $sql); break; } return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Récupérer un monstre par son ID * * @param int $id ID du monstre * @return array|false Données du monstre ou false si non trouvé */ function get_monster_by_id($id) { $db = get_db_connection(); $stmt = $db->prepare('SELECT * FROM monsters WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * Ajouter un nouveau monstre * * @param string $name Nom du monstre * @param string $image Chemin de l'image * @return int|false ID du nouveau monstre ou false en cas d'échec */ function add_monster($name, $image) { $db = get_db_connection(); $stmt = $db->prepare('INSERT INTO monsters (name, image) VALUES (:name, :image)'); $stmt->bindParam(':name', $name); $stmt->bindParam(':image', $image); if ($stmt->execute()) { return $db->lastInsertId(); } return false; } /** * Mettre à jour un monstre existant * * @param int $id ID du monstre * @param string $name Nouveau nom * @param string $image Nouveau chemin d'image * @return bool Succès de la mise à jour */ function update_monster($id, $name, $image) { $db = get_db_connection(); $stmt = $db->prepare('UPDATE monsters SET name = :name, image = :image WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); $stmt->bindParam(':name', $name); $stmt->bindParam(':image', $image); return $stmt->execute(); } /** * Supprimer un monstre * * @param int $id ID du monstre à supprimer * @return bool Succès de la suppression */ function delete_monster($id) { $db = get_db_connection(); $stmt = $db->prepare('DELETE FROM monsters WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); return $stmt->execute(); } /** * ======== FONCTIONS D'ACCÈS AUX QUÊTES ======== */ /** * Récupérer toutes les quêtes pour un monstre spécifique * * @param int $monster_id ID du monstre * @return array Liste des quêtes */ function get_quests_by_monster($monster_id) { $db = get_db_connection(); $stmt = $db->prepare('SELECT * FROM quests WHERE monster_id = :monster_id ORDER BY date DESC'); $stmt->bindParam(':monster_id', $monster_id, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Récupérer toutes les quêtes d'un certain type (small/large) pour un monstre * * @param int $monster_id ID du monstre * @param string $crown_type Type de couronne ('small' ou 'large') * @return array Liste des quêtes */ function get_quests_by_monster_and_crown($monster_id, $crown_type) { $db = get_db_connection(); $stmt = $db->prepare('SELECT * FROM quests WHERE monster_id = :monster_id AND crown_type = :crown_type ORDER BY date DESC'); $stmt->bindParam(':monster_id', $monster_id, PDO::PARAM_INT); $stmt->bindParam(':crown_type', $crown_type); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Ajouter une nouvelle quête * * @param int $monster_id ID du monstre * @param string $crown_type Type de couronne ('small' ou 'large') * @param string $player_name Nom du joueur * @param string $player_id ID du joueur en jeu * @return int|false ID de la nouvelle quête ou false en cas d'échec */ function add_quest($monster_id, $crown_type, $player_name, $player_id) { $db = get_db_connection(); $stmt = $db->prepare('INSERT INTO quests (monster_id, crown_type, player_name, player_id) VALUES (:monster_id, :crown_type, :player_name, :player_id)'); $stmt->bindParam(':monster_id', $monster_id, PDO::PARAM_INT); $stmt->bindParam(':crown_type', $crown_type); $stmt->bindParam(':player_name', $player_name); $stmt->bindParam(':player_id', $player_id); if ($stmt->execute()) { return $db->lastInsertId(); } return false; } /** * Supprimer une quête * * @param int $id ID de la quête à supprimer * @return bool Succès de la suppression */ function delete_quest($id) { $db = get_db_connection(); $stmt = $db->prepare('DELETE FROM quests WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); return $stmt->execute(); } /** * Nettoyer les quêtes expirées (plus vieilles que QUESTS_EXPIRATION_DAYS) * * @return int Nombre de quêtes supprimées */ function clean_old_quests() { $db = get_db_connection(); $days = QUESTS_EXPIRATION_DAYS; $stmt = $db->prepare("DELETE FROM quests WHERE date < datetime('now', '-{$days} days')"); $stmt->execute(); return $stmt->rowCount(); } /** * Compter les quêtes par type de couronne * * @return array Statistiques des quêtes */ function count_quests_by_crown_type() { $db = get_db_connection(); $stmt = $db->query(" SELECT COUNT(*) as total_quests, SUM(CASE WHEN crown_type = 'small' THEN 1 ELSE 0 END) as small_crown_quests, SUM(CASE WHEN crown_type = 'large' THEN 1 ELSE 0 END) as large_crown_quests FROM quests "); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * ======== FONCTIONS D'ACCÈS AUX ANNONCES ======== */ /** * Récupérer toutes les annonces * * @param bool $active_only Ne récupérer que les annonces actives * @return array Liste des annonces */ function get_all_announcements($active_only = false) { $db = get_db_connection(); $query = 'SELECT * FROM announcements'; if ($active_only) { $query .= ' WHERE active = 1'; } $query .= ' ORDER BY created_at ASC'; $stmt = $db->query($query); return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Récupérer une annonce par son ID * * @param int $id ID de l'annonce * @return array|false Données de l'annonce ou false si non trouvée */ function get_announcement_by_id($id) { $db = get_db_connection(); $stmt = $db->prepare('SELECT * FROM announcements WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * Ajouter une nouvelle annonce * * @param string $text Texte de l'annonce * @param bool $active Statut actif de l'annonce * @return int|false ID de la nouvelle annonce ou false en cas d'échec */ function add_announcement($text, $active = true) { $db = get_db_connection(); $active_int = $active ? 1 : 0; $stmt = $db->prepare('INSERT INTO announcements (text, active) VALUES (:text, :active)'); $stmt->bindParam(':text', $text); $stmt->bindParam(':active', $active_int, PDO::PARAM_INT); if ($stmt->execute()) { return $db->lastInsertId(); } return false; } /** * Mettre à jour une annonce existante * * @param int $id ID de l'annonce * @param string $text Nouveau texte * @param bool $active Nouveau statut * @return bool Succès de la mise à jour */ function update_announcement($id, $text, $active = true) { $db = get_db_connection(); $active_int = $active ? 1 : 0; $stmt = $db->prepare('UPDATE announcements SET text = :text, active = :active WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); $stmt->bindParam(':text', $text); $stmt->bindParam(':active', $active_int, PDO::PARAM_INT); return $stmt->execute(); } /** * Supprimer une annonce * * @param int $id ID de l'annonce à supprimer * @return bool Succès de la suppression */ function delete_announcement($id) { $db = get_db_connection(); $stmt = $db->prepare('DELETE FROM announcements WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); return $stmt->execute(); } /** * ======== FONCTIONS D'AUTHENTIFICATION ======== */ /** * Vérifier les identifiants d'un utilisateur * * @param string $username Nom d'utilisateur * @param string $password Mot de passe * @return bool L'authentification est-elle valide */ function check_login($username, $password) { $db = get_db_connection(); $stmt = $db->prepare('SELECT * FROM users WHERE username = :username'); $stmt->bindParam(':username', $username); $stmt->execute(); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user && password_verify($password, $user['password'])) { return true; } return false; } /** * Mettre à jour le mot de passe d'un utilisateur * * @param string $username Nom d'utilisateur * @param string $new_password Nouveau mot de passe * @return bool Succès de la mise à jour */ function update_user_password($username, $new_password) { $db = get_db_connection(); // Hacher le nouveau mot de passe $hashed_password = password_hash($new_password, PASSWORD_DEFAULT); $stmt = $db->prepare('UPDATE users SET password = :password WHERE username = :username'); $stmt->bindParam(':username', $username); $stmt->bindParam(':password', $hashed_password); return $stmt->execute(); } /** * Vérifier le mot de passe actuel d'un utilisateur * * @param string $username Nom d'utilisateur * @param string $current_password Mot de passe actuel * @return bool Le mot de passe est-il valide */ function verify_current_password($username, $current_password) { $db = get_db_connection(); $stmt = $db->prepare('SELECT password FROM users WHERE username = :username'); $stmt->bindParam(':username', $username); $stmt->execute(); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user && password_verify($current_password, $user['password'])) { return true; } return false; }