&1` redirects stderr to stdout to capture any errors. $command = 'python3 ' . escapeshellarg($temp_file) . ' 2>&1'; // Execute the command $output = shell_exec($command); // Clean up the temporary file unlink($temp_file); return $output ?? ''; } /** * Compares the actual output with the expected output, ignoring whitespace differences. * * @param string $actualOutput The output from the user's code. * @param string $expectedOutput The correct output from the database. * @return bool True if the outputs match, false otherwise. */ function compare_outputs(string $actualOutput, string $expectedOutput): bool { return trim($actualOutput) === trim($expectedOutput); } /** * Awards a specific badge to a user if they don't already have it. * * @param PDO $pdo The database connection. * @param int $user_id The user's ID. * @param string $badgeName The name of the badge to award. */ function award_badge(PDO $pdo, int $user_id, string $badgeName): void { // Find the badge ID $stmt = $pdo->prepare('SELECT id FROM badges WHERE name = ?'); $stmt->execute([$badgeName]); $badge = $stmt->fetch(); if ($badge) { // Insert the badge for the user, ignoring duplicates $stmt = $pdo->prepare('INSERT IGNORE INTO user_badges (user_id, badge_id) VALUES (?, ?)'); $stmt->execute([$user_id, $badge['id']]); } } // --- Main Logic --- if (!isset($_SESSION['user_id'])) { header('Location: login.php'); exit; } $user_id = $_SESSION['user_id']; if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['challenge_id'], $_POST['solution'])) { header('Location: challenges.php'); exit; } $challenge_id = $_POST['challenge_id']; $solution = $_POST['solution']; $language = $_POST['language'] ?? 'python'; // Default to python if (empty($solution)) { $_SESSION['error_message'] = 'Please provide a solution.'; header('Location: challenge.php?id=' . $challenge_id); exit; } $pdo = db(); // Get challenge details $stmt = $pdo->prepare('SELECT name, expected_output FROM challenges WHERE id = ?'); $stmt->execute([$challenge_id]); $challenge = $stmt->fetch(); if (!$challenge) { header('Location: challenges.php'); exit; } // --- Grading --- $status = 'pending'; if ($language === 'python') { $actual_output = execute_python_safely($solution); if (compare_outputs($actual_output, $challenge['expected_output'])) { $status = 'passed'; } else { $status = 'failed'; } } // --- Record Submission --- $stmt = $pdo->prepare(' INSERT INTO challenge_submissions (user_id, challenge_id, language, submission_content, status) VALUES (?, ?, ?, ?, ?) '); $stmt->execute([$user_id, $challenge_id, $language, $solution, $status]); // --- Post-Submission Actions --- if ($status === 'passed') { $_SESSION['success_message'] = "Correct solution for '{$challenge['name']}'! Well done!"; // Award "First Challenge Completed" badge if it's their first $stmt = $pdo->prepare('SELECT COUNT(*) as passed_count FROM challenge_submissions WHERE user_id = ? AND status = 'passed''); $stmt->execute([$user_id]); $result = $stmt->fetch(); if ($result && $result['passed_count'] === 1) { award_badge($pdo, $user_id, 'First Challenge Completed'); $_SESSION['success_message'] .= ' You just earned the "First Challenge Completed" badge!'; } // Send congratulatory email $stmt = $pdo->prepare('SELECT name, email FROM users WHERE id = ?'); $stmt->execute([$user_id]); $user = $stmt->fetch(); if ($user) { require_once 'mail/MailService.php'; $subject = 'Congratulations on completing a challenge!'; $body = "Hello {$user['name']},

You have successfully completed the '{$challenge['name']}' challenge. Keep up the great work!

You can view any new badges or certificates in your profile.

Best regards,
The RS Learning Lab Team"; MailService::sendMail($user['email'], $subject, $body, strip_tags($body)); } } elseif ($status === 'failed') { $_SESSION['error_message'] = "Your solution for '{$challenge['name']}' is incorrect. Try again!"; } else { $_SESSION['info_message'] = 'Your solution has been submitted successfully and is pending review.'; } header('Location: challenges.php'); exit;