|
|
@@ -1,142 +1,168 @@
|
|
|
<?php
|
|
|
|
|
|
-/*
|
|
|
- * To change this license header, choose License Headers in Project Properties.
|
|
|
- * To change this template file, choose Tools | Templates
|
|
|
- * and open the template in the editor.
|
|
|
- */
|
|
|
-
|
|
|
/**
|
|
|
- * Description of ExcelFunctions
|
|
|
+ * Report exports for TimeKeeper:
|
|
|
+ * - ExcelFunctions::GeneratePdf() question report as HTML or PDF
|
|
|
+ * - ExcelFunctions::GenerateExcel() worksheet of random maths questions
|
|
|
+ * - Summary::GenerateSummary() kiosk-style score summary
|
|
|
*
|
|
|
- * @author gregory
|
|
|
+ * Changes from the current repo version:
|
|
|
+ * - ?user= is validated once, up front, for every entry point (GenerateSummary
|
|
|
+ * had no validation at all, and GeneratePdf only validated inside the pdf
|
|
|
+ * branch, after the SQL had already run with the raw value)
|
|
|
+ * - all SQL escapes the user and uses MPREFIX instead of `e107.e107_`
|
|
|
+ * - everything taken from the database or the URL is HTML-escaped (answers
|
|
|
+ * are typed by the students, so they are untrusted)
|
|
|
+ * - the correct/incorrect icons are text symbols: the <img> paths were
|
|
|
+ * relative, so they broke once the PDF source moved to the temp directory
|
|
|
+ * - PDF: wkhtmltopdf runs with local file access disabled, the PDF is only
|
|
|
+ * sent if it was actually produced, and the temp files are always removed
|
|
|
+ * - removed the debug "Memory use / Generation time" line and the early
|
|
|
+ * $sql->close() (it closed the shared connection before e107 finished)
|
|
|
+ * - Excel: the question loop started at row 0 (invalid, and the formulas
|
|
|
+ * pointed at row 0), multiplication passed an array to rand() (fatal on
|
|
|
+ * PHP 8), buildQuestion() looped forever if no subject was ticked, and the
|
|
|
+ * question count was unbounded
|
|
|
+ * - whereDate()/range handling lives in one trait instead of two copies
|
|
|
+ * - removed the dead, broken coverPage() in ExcelFunctions (COUNT(_id))
|
|
|
*/
|
|
|
+trait TkReportRequest {
|
|
|
+
|
|
|
+ /** Validated ?user= value, or null when missing or not a plain username. */
|
|
|
+ private function requestUser() {
|
|
|
+ $user = filter_input(INPUT_GET, 'user');
|
|
|
+ if (is_string($user) && preg_match('/^[A-Za-z0-9_.-]{1,50}$/', $user)) {
|
|
|
+ return $user;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function rangeWindows() {
|
|
|
+ $end = mktime(23, 59, 59, date('n'), date('j'));
|
|
|
+ return [
|
|
|
+ 'today' => ['start' => strtotime('- 24 hours', $end), 'end' => $end],
|
|
|
+ 'yesterday' => ['start' => strtotime('- 48 hours', $end), 'end' => strtotime('- 24 hours', $end)],
|
|
|
+ 'pastWeek' => ['start' => strtotime('- 7 days', $end), 'end' => $end],
|
|
|
+ 'pastMonth' => ['start' => strtotime('- 1 month', $end), 'end' => $end],
|
|
|
+ 'pastQuarter' => ['start' => strtotime('- 3 month', $end), 'end' => $end],
|
|
|
+ 'pastYear' => ['start' => strtotime('- 1 year', $end), 'end' => $end],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /** The requested ?range=, restricted to the known names ('today' otherwise). */
|
|
|
+ private function currentRange() {
|
|
|
+ $range = filter_input(INPUT_GET, 'range');
|
|
|
+ $windows = $this->rangeWindows();
|
|
|
+ return (is_string($range) && isset($windows[$range])) ? $range : 'today';
|
|
|
+ }
|
|
|
+
|
|
|
+ private function whereDate() {
|
|
|
+ $windows = $this->rangeWindows();
|
|
|
+ $window = $windows[$this->currentRange()];
|
|
|
+ return 'AND answereddatestamp>=' . (int) $window['start'] . ' AND answereddatestamp<=' . (int) $window['end'];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function esc($value) {
|
|
|
+ return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
class ExcelFunctions {
|
|
|
|
|
|
+ use TkReportRequest;
|
|
|
+
|
|
|
public function GeneratePdf() {
|
|
|
- $user = filter_input(INPUT_GET, 'user');
|
|
|
- if (!is_string($user) || !preg_match('/^[A-Za-z0-9_-]{1,50}$/', $user)) {
|
|
|
+ $user = $this->requestUser();
|
|
|
+ if ($user === null) {
|
|
|
return;
|
|
|
- } // before any query
|
|
|
+ }
|
|
|
|
|
|
- $whereDate = $this->whereDate();
|
|
|
- if ($user == "") {
|
|
|
+ $output = filter_input(INPUT_GET, 'output');
|
|
|
+ if ($output !== 'html' && $output !== 'pdf') {
|
|
|
return;
|
|
|
}
|
|
|
- $text = '<h1>TimeKeeper Report</h1>';
|
|
|
- $sql = e107::getDb();
|
|
|
|
|
|
- // $text .= $this->coverPage($sql,$user,$whereDate);
|
|
|
+ $sql = e107::getDb();
|
|
|
+ $text = '<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><h1>TimeKeeper Report</h1>'
|
|
|
+ . $this->questionsTable($sql, $user, $this->whereDate())
|
|
|
+ . '</body></html>';
|
|
|
|
|
|
- $text .= $this->questionsTable($sql, $user, $whereDate);
|
|
|
+ if ($output === 'html') {
|
|
|
+ echo $text;
|
|
|
+ exit;
|
|
|
+ }
|
|
|
|
|
|
- $text .= "\nMemory use: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MiB.\nGeneration time " . (microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) . ' seconds.';
|
|
|
+ $base = tempnam(sys_get_temp_dir(), 'tk');
|
|
|
+ if ($base === false) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $html = $base . '.html';
|
|
|
+ $pdf = $base . '.pdf';
|
|
|
|
|
|
- $sql->close();
|
|
|
+ file_put_contents($html, $text);
|
|
|
+ exec('wkhtmltopdf --quiet --disable-local-file-access ' . escapeshellarg($html) . ' ' . escapeshellarg($pdf) . ' 2>&1');
|
|
|
|
|
|
- $output = filter_input(INPUT_GET, 'output');
|
|
|
- if ($output == 'html') {
|
|
|
- echo $text;
|
|
|
- exit;
|
|
|
- } elseif ($output == 'pdf') {
|
|
|
- // pdf branch:
|
|
|
- $base = tempnam(sys_get_temp_dir(), 'tk');
|
|
|
- $html = $base . '.html';
|
|
|
- $pdf = $base . '.pdf';
|
|
|
- file_put_contents($html, $text);
|
|
|
- exec('wkhtmltopdf ' . escapeshellarg($html) . ' ' . escapeshellarg($pdf));
|
|
|
+ if (is_file($pdf) && filesize($pdf) > 0) {
|
|
|
header('Content-Type: application/pdf');
|
|
|
header('Content-Length: ' . filesize($pdf));
|
|
|
+ header('Content-Disposition: inline; filename="timekeeper-report.pdf"');
|
|
|
readfile($pdf);
|
|
|
- unlink($html);
|
|
|
- unlink($pdf);
|
|
|
- unlink($base);
|
|
|
- exit;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private function coverPage($sql, $user, $whereDate) {
|
|
|
- if (false) {
|
|
|
- $sql->gen("SELECT `subject`,
|
|
|
- ANY_VALUE(`percent`) as percent, ANY_VALUE(`quantity`) as quantity
|
|
|
- FROM e107.`e107_tkStats` WHERE `username` = '$user' GROUP BY (`subject`);");
|
|
|
-
|
|
|
- $text = '<table border="1" cellspacing="3" cellpadding="2">'
|
|
|
- . '<tr><td style="text-align:left">Subject</td><td>Score</td><td>Questions Remaining</td></tr>';
|
|
|
- while ($row = $sql->fetch()) {
|
|
|
- $text .= '<tr><td style="text-align:left">' . ucfirst($row['subject']) . '</td><td>' . $row['percent'] . '%</td><td>' . (1000 - $row['quantity']) . '</td></tr>';
|
|
|
- }
|
|
|
} else {
|
|
|
- $sql->gen("SELECT COUNT(_id) as cntr, CAST((SUM(correct)/COUNT(id)*100) as DECIMAL(5,2)) as percent
|
|
|
- FROM e107.`e107_tkReport` WHERE username = '$user'
|
|
|
- $whereDate");
|
|
|
- while ($row = $sql->fetch()) {
|
|
|
- if (filter_input(INPUT_GET, 'range') == "" || filter_input(INPUT_GET, 'range') == "today") {
|
|
|
- $text .= '<p>' . $row['cntr'] . ' question(s) have been answered for today with ' . $row['percent'] . '% accuracy.</p>';
|
|
|
- } else {
|
|
|
- $text .= '<p>' . $row['cntr'] . ' question(s) have been answered for this ' . filter_input(INPUT_GET, 'range') . ' with ' . $row['percent'] . '% accuracy.</p>';
|
|
|
- }
|
|
|
- }
|
|
|
+ header('HTTP/1.1 500 Internal Server Error');
|
|
|
+ echo 'The PDF could not be generated.';
|
|
|
}
|
|
|
- $text .= '</table>';
|
|
|
- return $text;
|
|
|
+
|
|
|
+ @unlink($html);
|
|
|
+ @unlink($pdf);
|
|
|
+ @unlink($base);
|
|
|
+ exit;
|
|
|
}
|
|
|
|
|
|
private function questionsTable($sql, $user, $whereDate) {
|
|
|
+ $sql->gen("SELECT * FROM `" . MPREFIX . "tkReport` WHERE username='" . $sql->escape($user) . "' $whereDate ORDER BY subject, answereddatestamp");
|
|
|
|
|
|
- $sql->gen("SELECT * FROM e107.e107_tkReport WHERE username='$user' $whereDate ORDER BY subject;");
|
|
|
- $head = "";
|
|
|
- $text = "";
|
|
|
+ $tableHead = '<table border="1" cellspacing="3" cellpadding="2"><tr>'
|
|
|
+ . '<td width="1295">Question</td>'
|
|
|
+ . '<td width="75">User Answer</td>'
|
|
|
+ . '<td width="75">Correct Answer</td>'
|
|
|
+ . '<td width="25"></td>'
|
|
|
+ . '</tr>';
|
|
|
+
|
|
|
+ $head = null;
|
|
|
+ $text = '';
|
|
|
|
|
|
while ($row = $sql->fetch()) {
|
|
|
- if ($head == "") {
|
|
|
- $head = $row["subject"];
|
|
|
- $text .= '<h3>' . ucfirst($head) . '</h3>'
|
|
|
- . '<table border="1" cellspacing="3" cellpadding="2">'
|
|
|
- . '<tr>'
|
|
|
- . '<td width="1295">Question</td>'
|
|
|
- . '<td width="75">User Answer</td>'
|
|
|
- . '<td width="75">Correct Answer</td>'
|
|
|
- . '<td width="25"></td>'
|
|
|
- . '</tr>';
|
|
|
- } elseif ($head != $row["subject"]) {
|
|
|
- $head = $row["subject"];
|
|
|
- $text .= '</table><h3>' . ucfirst($head) . '</h3><table border="1" cellspacing="3" cellpadding="2"><tr><td width="1295">Question</td><td width="75">User Answer</td><td width="75">Correct Answer</td><td width="25"></td></tr>';
|
|
|
+ if ($row['subject'] !== $head) {
|
|
|
+ if ($head !== null) {
|
|
|
+ $text .= '</table>';
|
|
|
+ }
|
|
|
+ $head = $row['subject'];
|
|
|
+ $text .= '<h3>' . $this->esc(ucfirst($head)) . '</h3>' . $tableHead;
|
|
|
}
|
|
|
- $text .= "<tr><td>" . $row["question"] . '</td><td>' . $row["userAnswer"] . '</td><td>' . $row["answer"] . '</td><td>' . $this->correctOrNot($row["correct"]) . '</td></tr>';
|
|
|
+ $text .= '<tr><td>' . $this->esc($row['question']) . '</td><td>' . $this->esc($row['userAnswer']) . '</td><td>' . $this->esc($row['answer']) . '</td><td>' . $this->correctOrNot($row['correct']) . '</td></tr>';
|
|
|
}
|
|
|
- $text .= '</table>';
|
|
|
- return $text;
|
|
|
- }
|
|
|
|
|
|
- private function whereDate() {
|
|
|
- $returnRange = filter_input(INPUT_GET, 'range');
|
|
|
- $unixTimeTodayEnd = mktime(23, 59, 59, date('n'), date('j'));
|
|
|
- $returnValues = ['today' => ['start' => strtotime('- 24 hours', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'yesterday' => ['start' => strtotime('- 48 hours', $unixTimeTodayEnd), 'end' => strtotime('- 24 hours', $unixTimeTodayEnd)]
|
|
|
- , 'pastWeek' => ['start' => strtotime('- 7 days', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastMonth' => ['start' => strtotime('- 1 month', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastQuarter' => ['start' => strtotime('- 3 month', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastYear' => ['start' => strtotime('- 1 year', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- ];
|
|
|
-
|
|
|
- if (!isset($returnValues[$returnRange])) {
|
|
|
- $returnRange = 'today';
|
|
|
+ if ($head === null) {
|
|
|
+ return '<p>No questions were answered in this period.</p>';
|
|
|
}
|
|
|
|
|
|
- return "AND answereddatestamp>='" . $returnValues[$returnRange]['start'] . "' AND answereddatestamp<='" . $returnValues[$returnRange]['end'] . "'";
|
|
|
+ return $text . '</table>';
|
|
|
}
|
|
|
|
|
|
private function correctOrNot($state) {
|
|
|
if ($state) {
|
|
|
- return '<img src="' . e_IMAGE . 'admin_images/true_16.png"/>';
|
|
|
- } else {
|
|
|
- return '<img src="' . e_IMAGE . 'admin_images/false_16.png"/>';
|
|
|
+ return '<span style="color:green">✔</span>';
|
|
|
}
|
|
|
+ return '<span style="color:red">✘</span>';
|
|
|
}
|
|
|
|
|
|
public function GenerateExcel() {
|
|
|
- require_once('phar://lib/PHPExcel.phar/PHPExcel.php');
|
|
|
+ $lib = __DIR__ . '/lib/PHPExcel.phar';
|
|
|
+ if (!is_file($lib)) {
|
|
|
+ e107::getMessage()->addError('The Excel library (lib/PHPExcel.phar) is not installed.');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ require_once('phar://' . $lib . '/PHPExcel.php');
|
|
|
|
|
|
$objPHPExcel = new PHPExcel();
|
|
|
$objPHPExcel->getProperties()->setCreator("Gregory J Huxley")->setLastModifiedBy("TimeKeeper");
|
|
|
@@ -152,54 +178,54 @@ class ExcelFunctions {
|
|
|
}
|
|
|
|
|
|
private function buildSheet($objPHPExcel) {
|
|
|
- $numberOfQuestions = filter_input(INPUT_POST, 'numberOfQuestions');
|
|
|
- if (!$numberOfQuestions) {
|
|
|
+ $numberOfQuestions = (int) filter_input(INPUT_POST, 'numberOfQuestions');
|
|
|
+ if ($numberOfQuestions < 1) {
|
|
|
$numberOfQuestions = 5;
|
|
|
}
|
|
|
- $objPHPExcel->getActiveSheet()->setTitle("Questions");
|
|
|
- for ($i = 0; $i <= $numberOfQuestions; $i++) {
|
|
|
+ $numberOfQuestions = min($numberOfQuestions, 500);
|
|
|
+
|
|
|
+ $sheet = $objPHPExcel->setActiveSheetIndex(0);
|
|
|
+ $sheet->setTitle("Questions");
|
|
|
+
|
|
|
+ // Rows are 1-based, and the answer-check formulas refer to row $i.
|
|
|
+ for ($i = 1; $i <= $numberOfQuestions; $i++) {
|
|
|
$counter = 0;
|
|
|
foreach ($this->buildQuestion($i) as $value) {
|
|
|
- $objPHPExcel->setActiveSheetIndex(0)->setCellValueByColumnAndRow($counter, $i, $value);
|
|
|
+ $sheet->setCellValueByColumnAndRow($counter, $i, $value);
|
|
|
$counter++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private function buildQuestion($i) {//http://localhost/e107_plugins/timekeeper/timekeeper.php?numberOfQuestions=20&addition=0&addition__switch=0&subtraction=0&multiplication=0&division=0&GetExcel=Generate+Sheet
|
|
|
- while (true) {
|
|
|
- switch (rand(1, 4)) {
|
|
|
- case 1:// addition
|
|
|
- $enabledSubject = filter_has_var(INPUT_POST, 'addition__switch');
|
|
|
- if ($enabledSubject) {
|
|
|
- return $this->addition($i);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 2:// subtraction
|
|
|
- $enabledSubject = filter_has_var(INPUT_POST, 'subtraction__switch');
|
|
|
- if ($enabledSubject) {
|
|
|
- return $this->subtraction($i);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 3:// multiplication
|
|
|
- $enabledSubject = filter_has_var(INPUT_POST, 'multiplication__switch');
|
|
|
- if ($enabledSubject) {
|
|
|
- return $this->multiplication($i);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 4:// division
|
|
|
- $enabledSubject = filter_has_var(INPUT_POST, 'division__switch');
|
|
|
- if ($enabledSubject) {
|
|
|
- return $this->division($i);
|
|
|
- }
|
|
|
- break;
|
|
|
+ $subjects = ['addition', 'subtraction', 'multiplication', 'division'];
|
|
|
+
|
|
|
+ $enabled = [];
|
|
|
+ foreach ($subjects as $subject) {
|
|
|
+ if (filter_has_var(INPUT_POST, $subject . '__switch')) {
|
|
|
+ $enabled[] = $subject;
|
|
|
}
|
|
|
}
|
|
|
+ if (empty($enabled)) {
|
|
|
+ $enabled = $subjects; // nothing ticked: use all of them rather than looping forever
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ($enabled[array_rand($enabled)]) {
|
|
|
+ case 'addition':
|
|
|
+ return $this->addition($i);
|
|
|
+ case 'subtraction':
|
|
|
+ return $this->subtraction($i);
|
|
|
+ case 'multiplication':
|
|
|
+ return $this->multiplication($i);
|
|
|
+ default:
|
|
|
+ return $this->division($i);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private function addition($i) {
|
|
|
$question = [rand(1, 1000)];
|
|
|
- for ($int = 1; $int <= rand(1, 3); $int++) {
|
|
|
+ $extra = rand(1, 3);
|
|
|
+ for ($int = 1; $int <= $extra; $int++) {
|
|
|
array_push($question, '+');
|
|
|
array_push($question, rand(1, 1000));
|
|
|
}
|
|
|
@@ -210,9 +236,10 @@ class ExcelFunctions {
|
|
|
|
|
|
private function subtraction($i) {
|
|
|
$question = [rand(100, 1000)];
|
|
|
- for ($int = 1; $int <= rand(1, 2); $int++) {
|
|
|
+ $extra = rand(1, 2);
|
|
|
+ for ($int = 1; $int <= $extra; $int++) {
|
|
|
array_push($question, '-');
|
|
|
- array_push($question, rand(1, $question[0] / 2));
|
|
|
+ array_push($question, rand(1, (int) ($question[0] / 2)));
|
|
|
}
|
|
|
array_push($question, '=');
|
|
|
array_push($question, $this->checkFormula($i, $question));
|
|
|
@@ -220,12 +247,10 @@ class ExcelFunctions {
|
|
|
}
|
|
|
|
|
|
private function multiplication($i) {
|
|
|
- $startNumber = [rand(1, 99)];
|
|
|
- $question = $startNumber;
|
|
|
- for ($int = 1; $int <= rand(1, 1); $int++) {
|
|
|
- array_push($question, '*');
|
|
|
- array_push($question, rand(1, $startNumber));
|
|
|
- }
|
|
|
+ $startNumber = rand(1, 99);
|
|
|
+ $question = [$startNumber];
|
|
|
+ array_push($question, '*');
|
|
|
+ array_push($question, rand(1, $startNumber));
|
|
|
array_push($question, '=');
|
|
|
array_push($question, $this->checkFormula($i, $question));
|
|
|
return $question;
|
|
|
@@ -262,11 +287,12 @@ class ExcelFunctions {
|
|
|
$counter++;
|
|
|
}
|
|
|
}
|
|
|
+ unset($value);
|
|
|
return '=IF(' . substr(strrchr($formula, "="), 1) . '="","",IF(' . $formula . ',"Correct","Wrong"))'; // =IF(L1="","",IF((A1*C1*E1*H1*J1)=L1,"Correct","Wrong"))
|
|
|
}
|
|
|
|
|
|
private function setHeader() {
|
|
|
- // Redirect output to a client’s web browser (Excel2007)
|
|
|
+ // Redirect output to a client's web browser (Excel5)
|
|
|
header('Content-Type: application/vnd.ms-excel');
|
|
|
header('Content-Disposition: attachment;filename="Questions.xls"');
|
|
|
header('Cache-Control: max-age=0');
|
|
|
@@ -281,77 +307,38 @@ class ExcelFunctions {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Description of Summary
|
|
|
- *
|
|
|
- * @author gregory
|
|
|
- */
|
|
|
class Summary {
|
|
|
|
|
|
- public function GenerateSummary() {//base64_encode
|
|
|
- $user = filter_input(INPUT_GET, 'user');
|
|
|
- $whereDate = $this->whereDate();
|
|
|
- if ($user == "") {
|
|
|
+ use TkReportRequest;
|
|
|
+
|
|
|
+ public function GenerateSummary() {
|
|
|
+ $user = $this->requestUser();
|
|
|
+ if ($user === null) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
$sql = e107::getDb();
|
|
|
|
|
|
- $text = '<body style="background-color:#31363b;"><div style="font-size:250%;color:#fcfcfc;">';
|
|
|
-
|
|
|
- $text .= $this->coverPage($sql, $user, $whereDate);
|
|
|
-
|
|
|
- //$text .= "\nMemory use: ".(memory_get_peak_usage(true)/1024/1024)." MiB.\nGeneration time " . (microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]).' seconds.';
|
|
|
- //print_a($whereDate);
|
|
|
- $sql->close();
|
|
|
- echo $text . '</div></body>';
|
|
|
- //$pdf->makePDF([$text, 'e107site', 'Gregory', 'Timekeeper Report', 'Timekeeper Report', 'Timekeeper Report', e_PLUGIN.'/timekeeper/timekeeper.php']);
|
|
|
-
|
|
|
+ echo '<!DOCTYPE html><html><head><meta charset="utf-8"></head>'
|
|
|
+ . '<body style="background-color:#31363b;"><div style="font-size:250%;color:#fcfcfc;">'
|
|
|
+ . $this->coverPage($sql, $user, $this->whereDate())
|
|
|
+ . '</div></body></html>';
|
|
|
exit;
|
|
|
}
|
|
|
|
|
|
private function coverPage($sql, $user, $whereDate) {
|
|
|
- if (false) {
|
|
|
- $sql->gen("SELECT MAX(`timekeeper_yearLevel`) as timekeeper_yearLevel, `timekeeper_subject`,
|
|
|
- ANY_VALUE(`timekeeper_percent`) as timekeeper_percent, ANY_VALUE(`timekeeper_quantity`) as timekeeper_quantity
|
|
|
- FROM e107.`e107_timekeeperStats` WHERE `timekeeper_username` = '$user' GROUP BY (`timekeeper_subject`);");
|
|
|
-
|
|
|
- $text = '<table border="1" cellspacing="3" cellpadding="2">'
|
|
|
- . '<tr><td style="text-align:left">Year</td><td style="text-align:left">Subject</td><td>Score</td><td>Questions Remaining</td></tr>';
|
|
|
- while ($row = $sql->fetch()) {
|
|
|
- $text .= '<tr><td>' . $row['timekeeper_yearLevel'] . '</td><td style="text-align:left">' . ucfirst($row['timekeeper_subject']) . '</td><td>' . $row['timekeeper_percent'] . '%</td><td>' . (1000 - $row['timekeeper_quantity']) . '</td></tr>';
|
|
|
- }
|
|
|
- } else {
|
|
|
- $sql->gen("SELECT COUNT(id) as cntr, CAST((SUM(correct)/COUNT(id)*100) as DECIMAL(5,2)) as percent
|
|
|
- FROM e107.`e107_tkReport` WHERE username = '$user'
|
|
|
+ $sql->gen("SELECT COUNT(id) AS cntr, CAST((SUM(correct)/COUNT(id)*100) AS DECIMAL(5,2)) AS percent
|
|
|
+ FROM `" . MPREFIX . "tkReport` WHERE username = '" . $sql->escape($user) . "'
|
|
|
$whereDate");
|
|
|
- while ($row = $sql->fetch()) {
|
|
|
- if (filter_input(INPUT_GET, 'range') == "" || filter_input(INPUT_GET, 'range') == "today") {
|
|
|
- $text .= 'Questions ' . filter_input(INPUT_GET, 'range') . '<br/><br/>' . $row['cntr'] . '<br/>' . $row['percent'] . '% correct.';
|
|
|
- } else {
|
|
|
- $text .= 'Questions ' . filter_input(INPUT_GET, 'range') . ' ' . $row['cntr'] . '<br/><br/>' . $row['percent'] . '% correct.';
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- $text .= '</table>';
|
|
|
- return $text;
|
|
|
- }
|
|
|
|
|
|
- private function whereDate() {
|
|
|
- $returnRange = filter_input(INPUT_GET, 'range');
|
|
|
- $unixTimeTodayEnd = mktime(23, 59, 59, date('n'), date('j'));
|
|
|
- $returnValues = ['today' => ['start' => strtotime('- 24 hours', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'yesterday' => ['start' => strtotime('- 48 hours', $unixTimeTodayEnd), 'end' => strtotime('- 24 hours', $unixTimeTodayEnd)]
|
|
|
- , 'pastWeek' => ['start' => strtotime('- 7 days', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastMonth' => ['start' => strtotime('- 1 month', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastQuarter' => ['start' => strtotime('- 3 month', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- , 'pastYear' => ['start' => strtotime('- 1 year', $unixTimeTodayEnd), 'end' => $unixTimeTodayEnd]
|
|
|
- ];
|
|
|
+ $row = $sql->fetch();
|
|
|
+ $count = is_array($row) ? (int) $row['cntr'] : 0;
|
|
|
+ $percent = (is_array($row) && $row['percent'] !== null) ? $row['percent'] : 0;
|
|
|
+ $range = $this->esc($this->currentRange());
|
|
|
|
|
|
- if (!isset($returnValues[$returnRange])) {
|
|
|
- $returnRange = 'today';
|
|
|
+ if ($range === 'today') {
|
|
|
+ return 'Questions ' . $range . '<br/><br/>' . $count . '<br/>' . $percent . '% correct.';
|
|
|
}
|
|
|
-
|
|
|
- return "AND answereddatestamp>='" . $returnValues[$returnRange]['start'] . "' AND answereddatestamp<='" . $returnValues[$returnRange]['end'] . "'";
|
|
|
+ return 'Questions ' . $range . ' ' . $count . '<br/><br/>' . $percent . '% correct.';
|
|
|
}
|
|
|
}
|