quiz questions + options (no answers) + user's results // POST api/quiz.php -> grade an attempt, save the result // JSON body: {quiz_id, answers: [[optIdx,...], ...]} (one array per question) // Response includes the correct options so the UI can mark the attempt. require_once __DIR__ . '/../includes/auth.php'; require_once __DIR__ . '/../includes/functions.php'; header('Content-Type: application/json'); $userId = requireLoginApi(); function quizProgressRow(int $userId, int $quizId): array { $stmt = db()->prepare( 'SELECT best_score, last_score, total_questions, attempts, completed FROM quiz_progress WHERE user_id = ? AND quiz_id = ?' ); $stmt->execute([$userId, $quizId]); return $stmt->fetch() ?: ['best_score' => 0, 'last_score' => 0, 'total_questions' => 0, 'attempts' => 0, 'completed' => 0]; } if ($_SERVER['REQUEST_METHOD'] === 'GET') { $quiz = getQuiz((int)($_GET['id'] ?? 0)); if (!$quiz) { http_response_code(404); echo json_encode(['error' => 'Quiz not found']); exit; } $file = quizFilePath($quiz); $questions = $file ? parseQuizFile($file) : []; if (!$questions) { http_response_code(404); echo json_encode(['error' => 'Quiz file is missing — rescan the library']); exit; } $folder = getFolder((int)$quiz['folder_id']); $p = quizProgressRow($userId, (int)$quiz['id']); echo json_encode([ 'quiz' => ['id' => (int)$quiz['id'], 'name' => $quiz['name']], 'folder' => ['id' => (int)$folder['id'], 'name' => $folder['name']], 'breadcrumbs' => array_map( fn($c) => ['id' => (int)$c['id'], 'name' => $c['name']], folderBreadcrumbs($folder) ), 'questions' => array_map(fn($q) => [ 'text' => $q['text'], 'multi' => $q['multi'], 'options' => $q['options'], ], $questions), 'progress' => [ 'attempts' => (int)$p['attempts'], 'best_score' => (int)$p['best_score'], 'last_score' => (int)$p['last_score'], 'total' => count($questions), 'completed' => (bool)$p['completed'], ], ]); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; } $data = json_decode(file_get_contents('php://input'), true) ?: []; verifyCsrfApi($data); $quiz = getQuiz((int)($data['quiz_id'] ?? 0)); $answers = $data['answers'] ?? null; if (!$quiz || !is_array($answers)) { http_response_code(400); echo json_encode(['error' => 'Bad request']); exit; } $file = quizFilePath($quiz); $questions = $file ? parseQuizFile($file) : []; if (!$questions) { http_response_code(404); echo json_encode(['error' => 'Quiz file is missing — rescan the library']); exit; } $score = 0; $results = []; foreach ($questions as $i => $q) { $selected = array_values(array_unique(array_map('intval', (array)($answers[$i] ?? [])))); sort($selected); $correct = $q['correct']; sort($correct); $isCorrect = $selected === $correct; if ($isCorrect) $score++; $results[] = [ 'correct' => $isCorrect, 'correct_options' => $correct, 'selected' => $selected, ]; } $total = count($questions); $completed = ($score === $total) ? 1 : 0; db()->prepare( 'INSERT INTO quiz_progress (user_id, quiz_id, best_score, last_score, total_questions, attempts, completed) VALUES (?, ?, ?, ?, ?, 1, ?) ON DUPLICATE KEY UPDATE last_score = VALUES(last_score), best_score = GREATEST(best_score, VALUES(best_score)), total_questions = VALUES(total_questions), attempts = attempts + 1, completed = GREATEST(completed, VALUES(completed))' )->execute([$userId, (int)$quiz['id'], $score, $score, $total, $completed]); echo json_encode([ 'score' => $score, 'total' => $total, 'completed' => (bool)$completed, 'results' => $results, ]);