Initial commit (code), runtime ignoré, secrets exclus

This commit is contained in:
nicoboy
2026-01-02 15:05:25 +01:00
commit 2fdcf50bc1
87 changed files with 11525 additions and 0 deletions

303
soumettre_evaluation.php Normal file
View File

@ -0,0 +1,303 @@
<?php
/**
* SOUMISSION FINALE DE L'ÉVALUATION
* Calcul de la note et sauvegarde définitive
*/
define('APP_ROOT', dirname(__DIR__));
require_once __DIR__ . '/config/config.php';
require_once __DIR__ . '/config/database.php';
// session_start(); // Géré par config/session.php
/**
* Normalise une réponse mathématique (entier, fraction, décimal)
* @param string $reponse La réponse brute de l'élève
* @return float|false Valeur normalisée ou false si invalide
*/
function normaliser_reponse_mathematique($reponse) {
if (empty($reponse)) return false;
$reponse = trim($reponse);
$reponse = str_replace(',', '.', $reponse); // Virgule française → point
// Cas fraction (ex: "2/3", "-5/3")
if (preg_match('/^([+-]?\d+)\s*\/\s*([+-]?\d+)$/', $reponse, $matches)) {
$numerateur = (float)$matches[1];
$denominateur = (float)$matches[2];
if ($denominateur == 0) return false; // Division par zéro
return $numerateur / $denominateur;
}
// Cas nombre décimal ou entier
if (is_numeric($reponse)) {
return (float)$reponse;
}
return false; // Format invalide
}
/**
* Compare deux réponses mathématiques avec tolérance
* @param float $attendue Réponse attendue (normalisée)
* @param float $donnee Réponse de l'élève (normalisée)
* @param float $epsilon Tolérance de comparaison
* @return bool True si les réponses sont équivalentes
*/
function comparer_reponses_mathematiques($attendue, $donnee, $epsilon = 0.0001) {
return abs($attendue - $donnee) < $epsilon;
}
// Vérification authentification
if (!isLoggedIn() || !isEleve()) {
header('Location: login.php?error=access_denied');
exit();
}
// $auth = new Auth(); // MIGRÉ vers SessionManager
$user = currentUser();
$db = Database::getInstance()->getConnection();
$id_evaluation = isset($_POST['id_evaluation']) ? (int)$_POST['id_evaluation'] :
(isset($_GET['id_evaluation']) ? (int)$_GET['id_evaluation'] :
(isset($_GET['id']) ? (int)$_GET['id'] : 0));
$id_tentative = isset($_POST['id_tentative']) ? (int)$_POST['id_tentative'] :
(isset($_GET['id_tentative']) ? (int)$_GET['id_tentative'] : 0);
$auto_submit = isset($_GET['auto']) && $_GET['auto'] == 1;
if ($id_tentative <= 0 || $id_evaluation <= 0) {
die("Données invalides");
}
// Vérifier que la tentative appartient à l'élève
$stmt = $db->prepare("
SELECT * FROM tentatives_eleves
WHERE id_tentative = ?
AND id_eleve = ?
AND statut = 'en_cours'
");
$stmt->execute([$id_tentative, $user['id_utilisateur']]);
$tentative = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$tentative) {
die("Tentative introuvable ou déjà terminée");
}
// Récupérer les réponses finales si soumission manuelle
if (!$auto_submit && $_SERVER['REQUEST_METHOD'] === 'POST') {
$reponses = [];
foreach ($_POST as $key => $value) {
if (strpos($key, 'reponse_') === 0) {
$id_question = str_replace('reponse_', '', $key);
$reponses[$id_question] = $value;
}
}
// Mettre à jour les réponses finales
$reponses_json = json_encode($reponses, JSON_UNESCAPED_UNICODE);
$stmt = $db->prepare("
UPDATE tentatives_eleves
SET reponses_json = ?
WHERE id_tentative = ?
");
$stmt->execute([$reponses_json, $id_tentative]);
// Recharger la tentative avec les nouvelles réponses
$stmt = $db->prepare("SELECT * FROM tentatives_eleves WHERE id_tentative = ?");
$stmt->execute([$id_tentative]);
$tentative = $stmt->fetch(PDO::FETCH_ASSOC);
}
// Récupérer toutes les questions de l'évaluation
$stmt = $db->prepare("
SELECT * FROM questions
WHERE id_evaluation = ?
ORDER BY ordre ASC
");
$stmt->execute([$id_evaluation]);
$questions = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Décoder les réponses de l'élève
$reponses_eleve = json_decode($tentative['reponses_json'], true) ?: [];
// CALCUL DE LA NOTE
$points_obtenus = 0;
$points_totaux = 0;
foreach ($questions as $question) {
$id_question = $question['id_question'];
$points_question = (float)$question['points'];
$points_totaux += $points_question;
// Récupérer la réponse de l'élève
$reponse_eleve = $reponses_eleve[$id_question] ?? null;
// Récupérer les options et la réponse correcte de la question
$options = json_decode($question['options_json'], true);
$reponse_correcte_data = json_decode($question['reponse_correcte_json'], true);
// Vérifier la réponse selon le type
switch ($question['type_question']) {
case 'checkbox':
// Trouver toutes les réponses correctes
$reponses_correctes = [];
if (isset($options['reponses'])) {
foreach ($options['reponses'] as $rep) {
if (isset($rep['est_correcte']) && $rep['est_correcte'] === true) {
$reponses_correctes[] = $rep['texte'];
}
}
}
$reponses_eleve_array = is_array($reponse_eleve) ? $reponse_eleve : [];
// Toutes correctes = points complets
sort($reponses_correctes);
sort($reponses_eleve_array);
if ($reponses_correctes === $reponses_eleve_array) {
$points_obtenus += $points_question;
} else {
// Points partiels selon le nombre de bonnes réponses
$nb_correctes = count($reponses_correctes);
if ($nb_correctes > 0) {
$nb_bonnes = count(array_intersect($reponses_correctes, $reponses_eleve_array));
$nb_mauvaises = count(array_diff($reponses_eleve_array, $reponses_correctes));
$points_partiels = max(0, ($nb_bonnes - $nb_mauvaises) / $nb_correctes * $points_question);
$points_obtenus += $points_partiels;
}
}
break;
case 'qcm':
// Trouver la réponse correcte dans le tableau reponses
$reponse_correcte = null;
if (isset($options['reponses'])) {
foreach ($options['reponses'] as $rep) {
if (isset($rep['est_correcte']) && $rep['est_correcte'] === true) {
$reponse_correcte = $rep['texte'];
break;
}
}
}
if ($reponse_eleve === $reponse_correcte) {
$points_obtenus += $points_question;
}
break;
case 'number':
// La réponse correcte est dans reponse_correcte_json: {"reponse": "18"}
$reponse_correcte = $reponse_correcte_data['reponse'] ?? null;
// Normaliser les deux réponses (gère entiers, fractions, décimaux)
$valeur_eleve = normaliser_reponse_mathematique($reponse_eleve);
$valeur_attendue = normaliser_reponse_mathematique($reponse_correcte);
// Comparer avec tolérance
if ($valeur_eleve !== false && $valeur_attendue !== false) {
if (comparer_reponses_mathematiques($valeur_attendue, $valeur_eleve)) {
$points_obtenus += $points_question;
}
}
break;
case 'text':
// Pour les questions texte, nécessite correction manuelle
// On compte 0 point automatiquement, à corriger manuellement
break;
case 'select':
// La réponse correcte est dans reponse_correcte_json: {"id": "opt2"}
// Les options sont dans options_json: {"options": [{"id": "opt1", "texte": "...", "est_correcte": false}, ...]}
$id_reponse_correcte = $reponse_correcte_data['id'] ?? null;
// L'élève peut avoir répondu avec l'ID ou le texte, on vérifie les deux
$est_correct = false;
if ($id_reponse_correcte && isset($options['options'])) {
// Trouver le texte correspondant à l'ID correct
$texte_correct = null;
foreach ($options['options'] as $opt) {
if (($opt['id'] ?? '') === $id_reponse_correcte) {
$texte_correct = $opt['texte'] ?? null;
break;
}
}
// Vérifier si la réponse de l'élève correspond (ID ou texte)
if ($reponse_eleve === $id_reponse_correcte || $reponse_eleve === $texte_correct) {
$est_correct = true;
}
}
if ($est_correct) {
$points_obtenus += $points_question;
}
break;
case 'text_trous':
$trous = $options['trous'] ?? [];
$reponses_eleve_trous = is_array($reponse_eleve) ? $reponse_eleve : [];
$nb_trous = count($trous);
$nb_corrects = 0;
foreach ($trous as $trou) {
$trou_id = $trou['id'];
$reponse_correcte = $trou['reponse_correcte'];
$reponse_eleve_trou = $reponses_eleve_trous[$trou_id] ?? '';
if (trim(strtolower($reponse_eleve_trou)) === trim(strtolower($reponse_correcte))) {
$nb_corrects++;
}
}
$points_obtenus += ($nb_corrects / $nb_trous) * $points_question;
break;
}
}
// Calculer le pourcentage
$pourcentage = $points_totaux > 0 ? ($points_obtenus / $points_totaux) * 100 : 0;
// Récupérer la note totale de l'évaluation
$stmt = $db->prepare("SELECT note_totale FROM evaluations WHERE id_evaluation = ?");
$stmt->execute([$id_evaluation]);
$eval = $stmt->fetch(PDO::FETCH_ASSOC);
$note_sur = $eval['note_totale'] ?? 20;
// Calculer la note finale
$note_finale = ($pourcentage / 100) * $note_sur;
// Calculer le temps passé
$date_debut = new DateTime($tentative['date_debut']);
$date_fin = new DateTime();
$temps_passe = $date_fin->getTimestamp() - $date_debut->getTimestamp();
// Mettre à jour la tentative
try {
$stmt = $db->prepare("
UPDATE tentatives_eleves
SET statut = 'terminee',
note = ?,
note_sur = ?,
pourcentage = ?,
temps_passe = ?,
date_fin = NOW()
WHERE id_tentative = ?
");
$stmt->execute([
round($note_finale, 2),
$note_sur,
round($pourcentage, 2),
$temps_passe,
$id_tentative
]);
// Redirection vers la page de résultat
header('Location: resultat_evaluation.php?id=' . $id_evaluation);
exit();
} catch (Exception $e) {
error_log("Erreur soumission évaluation: " . $e->getMessage());
die("Erreur lors de la soumission de l'évaluation");
}
?>