* * Changes from the current repo version: * - ?user= must be a plain username; it is escaped for SQL and for HTML * - optional shared secret: if the plugin pref `stats_key` is set, the page * needs ?key=. Until it is set the page stays open to anyone, * as before (it shows a student's scores and remaining minutes) * - an unknown user no longer crashes (count(false) is fatal on PHP 8) * - one GROUP BY query replaces the hand-built UNION; no subjects no longer * produces invalid SQL or undefined-variable notices * - a student with exactly 1 answer today now also gets the "games enabled" * line (the singular branch skipped it) * - `e107.e107_tkReport` -> MPREFIX; removed the leftover print_r('hi') * - settings row: reads `username` / `minQuestionCount` as before and falls * back to the timekeeper_username / timekeeper_Min_Question_Count names * used by timekeeper_sql.php, until it's settled which one your table has */ if (!defined('e107_INIT')) { require_once('../../class2.php'); } if (!e107::isInstalled('timekeeper')) { return ''; } // Optional shared secret (plugin pref `stats_key`). $requiredKey = (string) e107::getPlugPref('timekeeper', 'stats_key', ''); if ($requiredKey !== '' && !hash_equals($requiredKey, (string) filter_input(INPUT_GET, 'key'))) { http_response_code(403); exit; } $userName = filter_input(INPUT_GET, 'user'); if (!is_string($userName) || !preg_match('/^[A-Za-z0-9_.-]{1,50}$/', $userName)) { exit; } $sql = e107::getDb(); $u = $sql->escape($userName); $reportTable = '`' . MPREFIX . 'tkReport`'; // Settings row (unknown users show nothing). $settings = $sql->retrieve('timekeeper', '*', 'username="' . $u . '"'); if (!is_array($settings)) { $settings = $sql->retrieve('timekeeper', '*', 'timekeeper_username="' . $u . '"'); } if (!is_array($settings)) { exit; } $minQuestions = 0; foreach (['minQuestionCount', 'timekeeper_Min_Question_Count'] as $column) { if (isset($settings[$column])) { $minQuestions = (int) $settings[$column]; break; } } // Score per subject, all time. $sql->gen("SELECT `subject`, COUNT(id) AS `count`, CAST((SUM(correct) / COUNT(id) * 100) AS DECIMAL(5,2)) AS percent FROM $reportTable WHERE `username` = '$u' GROUP BY `subject` ORDER BY `subject`"); $subjectRows = []; while ($row = $sql->fetch()) { $subjectRows[] = $row; } $safeUser = htmlspecialchars($userName, ENT_QUOTES, 'UTF-8'); $text = '

Score for ' . $safeUser . '

'; $text .= "" . "" . ""; foreach ($subjectRows as $row) { $text .= "'; } $text .= '
SubjectScoreNo.Questions
" . htmlspecialchars(ucfirst($row['subject']), ENT_QUOTES, 'UTF-8') . '' . htmlspecialchars($row['percent']) . '%' . (int) $row['count'] . '
'; // Today. $sql->gen("SELECT COUNT(id) AS cntr, CAST((SUM(correct)/COUNT(id)*100) AS DECIMAL(5,2)) AS percent FROM $reportTable WHERE username = '$u' AND answereddatestamp >= UNIX_TIMESTAMP(CURRENT_DATE()) AND answereddatestamp <= UNIX_TIMESTAMP(CURRENT_DATE() + INTERVAL 1 DAY)"); $today = $sql->fetch(); $answeredToday = is_array($today) ? (int) $today['cntr'] : 0; if ($answeredToday > 0) { $percent = htmlspecialchars($today['percent']); if ($answeredToday === 1) { $text .= '

1 question has been answered
today with ' . $percent . '% accuracy.


'; } else { $text .= '

' . $answeredToday . ' questions have been answered
today with ' . $percent . '% accuracy.


'; } if ($minQuestions <= $answeredToday) { $text .= '
'; $currentScore = $sql->retrieve('timekeeperScore', 'timekeeper_lifetimecorrect, timekeeper_lifetimequestions, timekeeper_minutes', 'timekeeper_username="' . $u . '"'); $minutes = is_array($currentScore) ? (int) $currentScore['timekeeper_minutes'] : 0; $text .= ''; } else { $text .= ''; } } $text .= '
'; echo '' . '' . $text . '';