tk_stats_page.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <?php
  2. /**
  3. * Kiosk-style score page: tk_stats_page.php?user=<name>
  4. *
  5. * Changes from the current repo version:
  6. * - ?user= must be a plain username; it is escaped for SQL and for HTML
  7. * - optional shared secret: if the plugin pref `stats_key` is set, the page
  8. * needs ?key=<that value>. Until it is set the page stays open to anyone,
  9. * as before (it shows a student's scores and remaining minutes)
  10. * - an unknown user no longer crashes (count(false) is fatal on PHP 8)
  11. * - one GROUP BY query replaces the hand-built UNION; no subjects no longer
  12. * produces invalid SQL or undefined-variable notices
  13. * - a student with exactly 1 answer today now also gets the "games enabled"
  14. * line (the singular branch skipped it)
  15. * - `e107.e107_tkReport` -> MPREFIX; removed the leftover print_r('hi')
  16. * - settings row: reads `username` / `minQuestionCount` as before and falls
  17. * back to the timekeeper_username / timekeeper_Min_Question_Count names
  18. * used by timekeeper_sql.php, until it's settled which one your table has
  19. */
  20. if (!defined('e107_INIT')) {
  21. require_once('../../class2.php');
  22. }
  23. if (!e107::isInstalled('timekeeper')) {
  24. return '';
  25. }
  26. // Optional shared secret (plugin pref `stats_key`).
  27. $requiredKey = (string) e107::getPlugPref('timekeeper', 'stats_key', '');
  28. if ($requiredKey !== '' && !hash_equals($requiredKey, (string) filter_input(INPUT_GET, 'key'))) {
  29. http_response_code(403);
  30. exit;
  31. }
  32. $userName = filter_input(INPUT_GET, 'user');
  33. if (!is_string($userName) || !preg_match('/^[A-Za-z0-9_.-]{1,50}$/', $userName)) {
  34. exit;
  35. }
  36. $sql = e107::getDb();
  37. $u = $sql->escape($userName);
  38. $reportTable = '`' . MPREFIX . 'tkReport`';
  39. // Settings row (unknown users show nothing).
  40. $settings = $sql->retrieve('timekeeper', '*', 'username="' . $u . '"');
  41. if (!is_array($settings)) {
  42. $settings = $sql->retrieve('timekeeper', '*', 'timekeeper_username="' . $u . '"');
  43. }
  44. if (!is_array($settings)) {
  45. exit;
  46. }
  47. $minQuestions = 0;
  48. foreach (['minQuestionCount', 'timekeeper_Min_Question_Count'] as $column) {
  49. if (isset($settings[$column])) {
  50. $minQuestions = (int) $settings[$column];
  51. break;
  52. }
  53. }
  54. // Score per subject, all time.
  55. $sql->gen("SELECT `subject`, COUNT(id) AS `count`,
  56. CAST((SUM(correct) / COUNT(id) * 100) AS DECIMAL(5,2)) AS percent
  57. FROM $reportTable WHERE `username` = '$u' GROUP BY `subject` ORDER BY `subject`");
  58. $subjectRows = [];
  59. while ($row = $sql->fetch()) {
  60. $subjectRows[] = $row;
  61. }
  62. $safeUser = htmlspecialchars($userName, ENT_QUOTES, 'UTF-8');
  63. $text = '<div><h1>Score for ' . $safeUser . '</h1>';
  64. $text .= "<table style='width:100%;text-align:center;'>"
  65. . "<thead><tr><td style='text-align:left'>Subject</td><td>Score</td><td>No.Questions</td></tr></thead>"
  66. . "<tbody>";
  67. foreach ($subjectRows as $row) {
  68. $text .= "<tr><td style='text-align:left'>" . htmlspecialchars(ucfirst($row['subject']), ENT_QUOTES, 'UTF-8') . '</td><td>' . htmlspecialchars($row['percent']) . '%</td><td>' . (int) $row['count'] . '</td></tr>';
  69. }
  70. $text .= '</tbody></table>';
  71. // Today.
  72. $sql->gen("SELECT COUNT(id) AS cntr, CAST((SUM(correct)/COUNT(id)*100) AS DECIMAL(5,2)) AS percent
  73. FROM $reportTable WHERE username = '$u'
  74. AND answereddatestamp >= UNIX_TIMESTAMP(CURRENT_DATE())
  75. AND answereddatestamp <= UNIX_TIMESTAMP(CURRENT_DATE() + INTERVAL 1 DAY)");
  76. $today = $sql->fetch();
  77. $answeredToday = is_array($today) ? (int) $today['cntr'] : 0;
  78. if ($answeredToday > 0) {
  79. $percent = htmlspecialchars($today['percent']);
  80. if ($answeredToday === 1) {
  81. $text .= '<p>1 question has been answered<br/>today with ' . $percent . '% accuracy.</p><br/>';
  82. } else {
  83. $text .= '<p>' . $answeredToday . ' questions have been answered<br/>today with ' . $percent . '% accuracy.</p><br/>';
  84. }
  85. if ($minQuestions <= $answeredToday) {
  86. $text .= '<label style="background: darkgreen;">Games enabled</label><br/>';
  87. $currentScore = $sql->retrieve('timekeeperScore', 'timekeeper_lifetimecorrect, timekeeper_lifetimequestions, timekeeper_minutes', 'timekeeper_username="' . $u . '"');
  88. $minutes = is_array($currentScore) ? (int) $currentScore['timekeeper_minutes'] : 0;
  89. $text .= '<label>You have ' . $minutes . ' minutes remaining.</label>';
  90. } else {
  91. $text .= '<label>Games disabled</label>';
  92. }
  93. }
  94. $text .= '</div>';
  95. echo '<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="refresh" content="60"></head>'
  96. . '<body style="background-color: #1a0000;color:white;">' . $text . '</body></html>';