Files
webval/enseignant/export.php

268 lines
8.8 KiB
PHP

<?php
/**
* EXPORT ÉVALUATION - BASÉ SUR STRUCTURE RÉELLE BDD
* Structure vérifiée via diagnostic_structure_bdd.php
*/
require_once '../config/config.php';
require_once '../config/database.php';
require_once '../config/session.php';
if (session_status() === PHP_SESSION_NONE) {
SessionManager::startSession();
}
if (!isset($_SESSION['user_id']) || $_SESSION['type_libelle'] !== 'enseignant') {
die('Accès refusé');
}
$id_evaluation = $_GET['id_evaluation'] ?? null;
$format = $_GET['format'] ?? 'csv';
if (!$id_evaluation || !in_array($format, ['csv', 'json'])) {
die('Paramètres invalides');
}
try {
$db = Database::getInstance()->getConnection();
// Évaluation
$stmt = $db->prepare("SELECT * FROM evaluations WHERE id_evaluation = ?");
$stmt->execute([$id_evaluation]);
$evaluation = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$evaluation) {
die('Évaluation non trouvée');
}
// Questions
$stmt = $db->prepare("SELECT * FROM questions WHERE id_evaluation = ? ORDER BY ordre ASC");
$stmt->execute([$id_evaluation]);
$questions = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Tentatives (CORRECTION: date_fin au lieu de date_soumission)
$stmt = $db->prepare("
SELECT
te.*,
TIMESTAMPDIFF(MINUTE, te.date_debut, COALESCE(te.date_fin, NOW())) as duree_minutes_calc,
u.login, u.nom, u.prenom,
c.nom_classe
FROM tentatives_eleves te
JOIN utilisateurs u ON te.id_eleve = u.id_utilisateur
LEFT JOIN classes c ON u.id_classe = c.id_classe
WHERE te.id_evaluation = ?
ORDER BY u.nom, u.prenom
");
$stmt->execute([$id_evaluation]);
$tentatives = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($format === 'csv') {
exportCSV($evaluation, $questions, $tentatives);
} else {
exportJSON($evaluation, $questions, $tentatives);
}
} catch (Exception $e) {
die('Erreur: ' . $e->getMessage());
}
/**
* Extrait réponse correcte depuis reponse_correcte_json
* Format réel: {"reponse": "x = 4"}
*/
function extraireReponseCorrecte($question) {
// 1. Essayer reponse_correcte_json d'abord (pour type number, text, etc.)
$correcte_data = json_decode($question['reponse_correcte_json'] ?? '{}', true);
if (isset($correcte_data['reponse'])) {
$rep = $correcte_data['reponse'];
if (is_array($rep)) {
return implode(' | ', $rep);
}
return $rep;
}
// 2. Fallback: chercher dans options_json (pour checkbox, qcm, select)
$options = json_decode($question['options_json'] ?? '{}', true);
if (isset($options['reponses']) && is_array($options['reponses'])) {
$correctes = [];
foreach ($options['reponses'] as $rep) {
if (isset($rep['est_correcte']) && $rep['est_correcte'] === true) {
$correctes[] = $rep['texte'] ?? $rep['id'];
}
}
if (!empty($correctes)) {
return implode(' + ', $correctes);
}
}
// 2b. Format avec 'options' (select)
if (isset($options['options']) && is_array($options['options'])) {
foreach ($options['options'] as $opt) {
if (isset($opt['est_correcte']) && $opt['est_correcte'] === true) {
return $opt['texte'];
}
}
}
// 3. Fallback ultime: options_json peut être un simple array ["opt1", "opt2"]
if (isset($options['correct_answer'])) {
return $options['correct_answer'];
}
return 'N/A';
}
function exportCSV($evaluation, $questions, $tentatives) {
$filename = sprintf(
'eval_%d_%s_%s.csv',
$evaluation['id_evaluation'],
preg_replace('/[^a-z0-9]/i', '_', substr($evaluation['titre'], 0, 30)),
date('Ymd_His')
);
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Pragma: no-cache');
header('Expires: 0');
$output = fopen('php://output', 'w');
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// En-tête
$headers = ['ID', 'Élève', 'Classe', 'Login', 'Statut', 'Début', 'Fin', 'Durée(min)', 'Note', 'Note sur', '%'];
foreach ($questions as $q) {
$headers[] = 'Q' . $q['ordre'];
}
foreach ($questions as $q) {
$headers[] = 'Q' . $q['ordre'] . '_Correcte';
}
fputcsv($output, $headers, ';');
// Données
foreach ($tentatives as $t) {
$reponses = json_decode($t['reponses_json'] ?? '{}', true) ?: [];
$row = [
$t['id_tentative'],
$t['prenom'] . ' ' . $t['nom'],
$t['nom_classe'] ?: 'Libre',
$t['login'],
$t['statut'],
$t['date_debut'],
$t['date_fin'] ?: '-',
$t['temps_passe'] ?? $t['duree_minutes_calc'],
$t['note'] !== null ? number_format($t['note'], 2, ',', '') : 'N/A',
$t['note_sur'] ?? $evaluation['note_totale'],
$t['pourcentage'] !== null ? number_format($t['pourcentage'], 1, ',', '') . '%' : 'N/A'
];
// Réponses élève
foreach ($questions as $q) {
$rep = $reponses[$q['id_question']] ?? '';
if (is_array($rep)) {
$rep = implode(' + ', $rep);
} elseif (is_object($rep)) {
$rep = json_encode($rep, JSON_UNESCAPED_UNICODE);
}
$row[] = $rep;
}
// Réponses correctes
foreach ($questions as $q) {
$row[] = extraireReponseCorrecte($q);
}
fputcsv($output, $row, ';');
}
fclose($output);
exit;
}
function exportJSON($evaluation, $questions, $tentatives) {
$filename = sprintf(
'eval_%d_%s_%s.json',
$evaluation['id_evaluation'],
preg_replace('/[^a-z0-9]/i', '_', substr($evaluation['titre'], 0, 30)),
date('Ymd_His')
);
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
$export = [
'metadata' => [
'date_export' => date('Y-m-d H:i:s'),
'exporteur' => $_SESSION['login'] ?? 'Enseignant'
],
'evaluation' => [
'id' => (int)$evaluation['id_evaluation'],
'titre' => $evaluation['titre'],
'description' => $evaluation['description'] ?? '',
'type' => $evaluation['type'],
'duree_minutes' => (int)$evaluation['duree_minutes'],
'note_totale' => (float)$evaluation['note_totale'],
'nb_questions' => count($questions),
'tentatives_max' => (int)$evaluation['tentatives_max']
],
'questions' => [],
'tentatives' => []
];
foreach ($questions as $q) {
$export['questions'][] = [
'id' => (int)$q['id_question'],
'ordre' => (int)$q['ordre'],
'type' => $q['type_question'],
'enonce' => $q['enonce'],
'options' => json_decode($q['options_json'] ?? '[]', true),
'reponse_correcte' => extraireReponseCorrecte($q),
'points' => (float)$q['points'],
'explication' => $q['explication'] ?? null
];
}
foreach ($tentatives as $t) {
$reponses = json_decode($t['reponses_json'] ?? '{}', true) ?: [];
$details = [];
foreach ($questions as $q) {
$details[] = [
'question_id' => (int)$q['id_question'],
'ordre' => (int)$q['ordre'],
'reponse_eleve' => $reponses[$q['id_question']] ?? null,
'reponse_correcte' => extraireReponseCorrecte($q)
];
}
$export['tentatives'][] = [
'id' => (int)$t['id_tentative'],
'eleve' => [
'id' => (int)$t['id_eleve'],
'nom' => $t['nom'],
'prenom' => $t['prenom'],
'login' => $t['login'],
'classe' => $t['nom_classe'] ?? 'Libre'
],
'numero_tentative' => (int)$t['numero_tentative'],
'statut' => $t['statut'],
'note' => $t['note'] !== null ? (float)$t['note'] : null,
'note_sur' => $t['note_sur'] !== null ? (float)$t['note_sur'] : (float)$evaluation['note_totale'],
'pourcentage' => $t['pourcentage'] !== null ? (float)$t['pourcentage'] : null,
'dates' => [
'debut' => $t['date_debut'],
'fin' => $t['date_fin']
],
'temps_passe_minutes' => $t['temps_passe'] ?? (int)$t['duree_minutes_calc'],
'reponses_detaillees' => $details
];
}
echo json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
?>