.., 'count' => ..] now * - user escaped in SQL; the hard-coded `e107.` database name replaced by * MPREFIX * - the previous tkLastQuestion row is removed before inserting the new one * (each question used to add another row) * - the token from TkAnswerStore::issue() is built once, before the form * - leftover commented-out debug line removed */ class numbers2 { private $user; /** * Setup new numbers engine * * @param string $user User to supply the question for. */ public function __construct($user) { $this->user = $user; } public function getNumbers() { $difficulty = $this->difficulty(); $question = $this->getSequence($difficulty); $questionHtml = $this->htmlify($question); $db = e107::getDb(); $db->delete('tkLastQuestion', "user = '" . $db->escape($this->user) . "'"); $db->insert('tkLastQuestion', ['user' => $this->user, 'LastQuestionHtml' => base64_encode($questionHtml)]); e107::getRender()->tablerender('Numbers', $questionHtml); } /** * Difficulty based on the last month of answers. * * @return array ['percent' => float 0-100, 'count' => int] */ private function difficulty() { $db = e107::getDb(); $stats = $db->retrieve( "SELECT (SUM(correct)/COUNT(correct)*100) AS percent, COUNT(correct) AS count FROM `" . MPREFIX . "tkReport` WHERE answereddatestamp >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 MONTH) AND username = '" . $db->escape($this->user) . "' AND subject = 'numbers'" ); if (!is_array($stats) || (int) $stats['count'] === 0) { return ['percent' => 0, 'count' => 0]; } return ['percent' => (float) $stats['percent'], 'count' => (int) $stats['count']]; } private function getSequence($difficulty) { $count = (int) $difficulty['count']; $percent = (float) $difficulty['percent']; $startingNumber = mt_rand(0, (int) pow($count, ($percent / 100) * 2)); if ($count >= 300) { $incrementalNumber = mt_rand(1, 100); } elseif ($count >= 200) { $incrementalNumber = mt_rand(1, 10); } elseif ($count >= 100) { $incrementalNumber = mt_rand(1, 5); } else { $incrementalNumber = mt_rand(1, 2); } $missingNumber = mt_rand(1, 10); $TempQuestion = []; for ($i = 1; $i <= 10; $i++) { if ($i == $missingNumber) { $TempQuestion[] = "___,"; $solution = round($startingNumber); } elseif ($i == 10) { $TempQuestion[] = round($startingNumber); } else { $TempQuestion[] = round($startingNumber) . ","; } if ($percent >= 90 && $count >= 200) { $startingNumber += round((2 * $incrementalNumber) / $i); } elseif ($percent >= 80 && $count >= 100) { $startingNumber += $incrementalNumber * ($i * 15); } else { $startingNumber += $incrementalNumber; } } return ['answer1' => $solution, 'question' => $TempQuestion, 'type' => 'numbers']; } private function htmlify($question) { // Expected answer stays on the server; the form only carries a token. $token = TkAnswerStore::issue($this->user, $question); $frm = e107::getForm(); $fString = $frm->open('questionForm', 'post', '', ['autocomplete' => 'off', 'class' => 'formclass']); $fString .= $frm->label('

Numbers

') . "
\n"; $fString .= $frm->label('Find the missing number.') . "\n"; $fString .= '
'; foreach ($question['question'] as $seq) { $fString .= $frm->label($seq . "   ") . "\n"; } $fString .= '

'; $fString .= $frm->text('a1', '', 80, ['placeholder' => 'Write answer here!', 'autocomplete' => "off", 'spellcheck' => "false"]) . "\n"; $fString .= $frm->hidden('checkerData', $token, ['id' => 'checkerData']); $fString .= $frm->hidden('subject', 'numbers', ['id' => 'subject']); $fString .= '
' . "\n"; $fString .= $frm->button('Answer', 'Check answer') . "\n"; $fString .= $frm->close(); $fString .= '

'; return $fString; } }