1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { 10 header("location: index.php"); 11 exit; 12} 13 14/** 15 * 16 */ 17class QuizLib extends TikiLib 18{ 19 /** 20 * @param $quizId 21 * @return bool 22 */ 23 public function get_quiz($quizId) 24 { 25 $query = "select * from `tiki_quizzes` where `quizId`=?"; 26 27 $result = $this->query($query, [(int) $quizId]); 28 29 if (! $result->numRows()) { 30 return false; 31 } 32 33 $res = $result->fetchRow(); 34 return $res; 35 } 36 37 public function compute_quiz_stats() 38 { 39 $query = "select `quizId` from `tiki_user_quizzes`"; 40 41 $result = $this->fetchAll($query, []); 42 43 $quizStatsSum = $this->table('tiki_quiz_stats_sum'); 44 45 foreach ($result as $res) { 46 $quizId = $res["quizId"]; 47 48 $quizName = $this->getOne("select `name` from `tiki_quizzes` where `quizId`=?", [(int) $quizId]); 49 $timesTaken = $this->getOne("select count(*) from `tiki_user_quizzes` where `quizId`=?", [(int) $quizId]); 50 $avgpoints = $this->getOne("select avg(`points`) from `tiki_user_quizzes` where `quizId`=?", [(int) $quizId]); 51 $maxPoints = $this->getOne("select max(`maxPoints`) from `tiki_user_quizzes` where `quizId`=?", [(int) $quizId]); 52 $avgavg = ($maxPoints != 0) ? $avgpoints / $maxPoints * 100 : 0.0; 53 $avgtime = $this->getOne("select avg(`timeTaken`) from `tiki_user_quizzes` where `quizId`=?", [(int) $quizId]); 54 55 $quizStatsSum->delete(['quizId' => (int) $quizId,]); 56 $quizStatsSum->insert( 57 [ 58 'quizId' => (int) $quizId, 59 'quizName' => $quizName, 60 'timesTaken' => (int) $timesTaken, 61 'avgpoints' => (float) $avgpoints, 62 'avgtime' => $avgtime, 63 'avgavg' => $avgavg, 64 ] 65 ); 66 } 67 } 68 69 /** 70 * @param $offset 71 * @param $maxRecords 72 * @param string $sort_mode 73 * @param null $find 74 * @return array 75 */ 76 public function list_quizzes($offset, $maxRecords, $sort_mode = 'name_desc', $find = null) 77 { 78 79 $quizzes = $this->table('tiki_quizzes'); 80 $conditions = []; 81 82 if (! empty($find)) { 83 $findesc = '%' . $find . '%'; 84 $conditions['search'] = $quizzes->expr('(`name` like ? or `description` like ?)', [$findesc, $findesc]); 85 } 86 87 $result = $quizzes->fetchColumn('quizId', $conditions); 88 $res = $ret = $retids = []; 89 $n = 0; 90 91 //FIXME Perm:filter ? 92 foreach ($result as $res) { 93 $objperm = Perms::get('quizzes', $res); 94 95 if ($objperm->take_quiz) { 96 if (($maxRecords == -1) || (($n >= $offset) && ($n < ($offset + $maxRecords)))) { 97 $retids[] = $res; 98 } 99 $n++; 100 } 101 } 102 103 if ($n > 0) { 104 $result = $quizzes->fetchAll( 105 $quizzes->all(), 106 ['quizId' => $quizzes->in($retids)], 107 -1, 108 -1, 109 $quizzes->expr($this->convertSortMode($sort_mode)) 110 ); 111 112 $questions = $this->table('tiki_quiz_questions'); 113 $results = $this->table('tiki_quiz_results'); 114 115 foreach ($result as $res) { 116 $res['questions'] = $questions->fetchCount(['quizId' => (int) $res['quizId']]); 117 $res['results'] = $results->fetchCount(['quizId' => (int) $res['quizId']]); 118 $ret[] = $res; 119 } 120 } 121 122 return [ 123 'data' => $ret, 124 'cant' => $n, 125 ]; 126 } 127 128 /** 129 * @param $userResultId 130 * @return bool 131 */ 132 public function get_user_quiz_result($userResultId) 133 { 134 $query = "select * from `tiki_user_quizzes` where `userResultId`=?"; 135 136 $result = $this->query($query, [$userResultId]); 137 138 if (! $result->numRows()) { 139 return false; 140 } 141 142 $res = $result->fetchRow(); 143 return $res; 144 } 145 146 /** 147 * @param $quizId 148 * @param int $offset 149 * @param $maxRecords 150 * @param string $sort_mode 151 * @param string $find 152 * @return array 153 */ 154 public function list_quiz_question_stats($quizId, $offset = 0, $maxRecords = -1, $sort_mode = 'position_asc', $find = '') 155 { 156 157 $query = "select distinct(tqs.`questionId`)" 158 . " from `tiki_quiz_stats` tqs,`tiki_quiz_questions` tqq" 159 . " where tqs.`questionId`=tqq.`questionId` and tqs.`quizId` = ? order by " 160 . $this->convertSortMode($sort_mode); 161 162 $result = $this->query($query, [(int) $quizId]); 163 $ret = []; 164 165 while ($res = $result->fetchRow()) { 166 $question = $this->getOne("select `question` from `tiki_quiz_questions` where `questionId`=?", [(int) $res["questionId"]]); 167 168 $total_votes = $this->getOne( 169 "select sum(`votes`) from `tiki_quiz_stats` where `quizId`=? and `questionId`=?", 170 [(int) $quizId, (int) $res["questionId"]] 171 ); 172 $query2 = "select tqq.`optionId`,`votes`,`optionText`" 173 . " from `tiki_quiz_stats` tqq,`tiki_quiz_question_options` tqo" 174 . " where tqq.`optionId`=tqo.`optionId` and tqq.`questionId`=?" 175 ; 176 $result2 = $this->query($query2, [(int) $res["questionId"]]); 177 $options = []; 178 179 while ($res = $result2->fetchRow()) { 180 $opt = []; 181 182 $opt["optionText"] = $res["optionText"]; 183 $opt["votes"] = $res["votes"]; 184 $opt["avg"] = $res["votes"] / $total_votes * 100; 185 $options[] = $opt; 186 } 187 188 $ques = []; 189 $ques["options"] = $options; 190 $ques["question"] = $question; 191 $ret[] = $ques; 192 } 193 194 return $ret; 195 } 196 197 /** 198 * @param $answerUploadId 199 */ 200 public function download_answer($answerUploadId) 201 { 202 203 $query = "SELECT `filecontent`, `filetype`, `filename`, `filesize` FROM `tiki_user_answers_uploads` WHERE `answerUploadId`=?"; 204 205 $result = $this->query($query, [(int) $answerUploadId]); 206 $ret = []; 207 208 while ($res = $result->fetchRow()) { 209 $data = $res['filecontent']; 210 $name = $res['filename']; 211 $type = $res['filetype']; 212 $size = $res['filesize']; 213 } 214 215 $name = htmlspecialchars($name); 216 217 header("Content-type: $type"); 218 header("Content-length: $size"); 219 header("Content-Disposition: attachment; filename=\"$name\""); 220 header("Content-Description: PHP Generated Data"); 221 print $data; 222 } 223 224 225 /** 226 * @param $userResultId 227 * @return array 228 */ 229 public function get_user_quiz_questions($userResultId) 230 { 231 $query = "select distinct(tqs.`questionId`) from `tiki_user_answers` tqs,`tiki_quiz_questions` tqq" 232 . " where tqs.`questionId`=tqq.`questionId` and tqs.`userResultId` = ? order by `position` desc"; 233 234 $result = $this->query($query, [(int) $userResultId]); 235 $ret = []; 236 237 while ($res = $result->fetchRow()) { 238 $question = $this->getOne("select `question` from `tiki_quiz_questions` where `questionId`=?", [(int) $res["questionId"]]); 239 240 $questionId = $res["questionId"]; 241 242 $query2 = "select tqq.`optionId`,tqo.`points`,`optionText`" 243 . " from `tiki_user_answers` tqq,`tiki_quiz_question_options` tqo" 244 . " where tqq.`optionId`=tqo.`optionId` and tqq.`userResultId`=? and tqq.`questionId`=?"; 245 $result2 = $this->query($query2, [(int) $userResultId, (int) $questionId]); 246 $options = []; 247 248 while ($res = $result2->fetchRow()) { 249 $opt = []; 250 251 $opt["optionText"] = $res["optionText"]; 252 $opt["points"] = $res["points"]; 253 254 $query3 = "select `answerUploadId`, `filename` from `tiki_user_answers_uploads` where `userResultId` = ? and `questionId` = ?"; 255 $result3 = $this->query($query3, [(int) $userResultId, (int) $questionId]); 256 257 while ($res2 = $result3->fetchRow()) { 258 $opt["filename"] = $res2["filename"]; 259 $opt["answerUploadId"] = $res2["answerUploadId"]; 260 } 261 262 $options[] = $opt; 263 } 264 265 266 $ques = []; 267 $ques["options"] = $options; 268 $ques["question"] = $question; 269 $ret[] = $ques; 270 } 271 272 273 return $ret; 274 } 275 276 /** 277 * @param $userResultId 278 */ 279 public function remove_quiz_stat($userResultId) 280 { 281 $query = "select `quizId`,`user` from `tiki_user_quizzes` where `userResultId`=?"; 282 $bindvars = [(int) $userResultId]; 283 284 $result = $this->query($query, $bindvars); 285 $res = $result->fetchRow(); 286 $user = $res["user"]; 287 $quizId = $res["quizId"]; 288 289 $query = "delete from `tiki_user_taken_quizzes` where `user`=? and `quizId`=?"; 290 $result = $this->query($query, [$user, (int) $quizId]); 291 292 $query = "delete from `tiki_user_quizzes` where `userResultId`=?"; 293 $result = $this->query($query, $bindvars); 294 $query = "delete from `tiki_user_answers` where `userResultId`=?"; 295 $result = $this->query($query, $bindvars); 296 } 297 298 /** 299 * @param $quizId 300 */ 301 public function clear_quiz_stats($quizId) 302 { 303 $query = "delete from `tiki_user_taken_quizzes` where `quizId`=?"; 304 $bindvars = [(int) $quizId]; 305 306 $result = $this->query($query, $bindvars); 307 308 $query = "delete from `tiki_quiz_stats_sum` where `quizId`=?"; 309 $result = $this->query($query, $bindvars); 310 311 $query = "delete from `tiki_quiz_stats` where `quizId`=?"; 312 $result = $this->query($query, $bindvars); 313 314 $query = "delete from `tiki_user_quizzes` where `quizId`=?"; 315 $result = $this->query($query, $bindvars); 316 317 $query = "delete from `tiki_user_answers` where `quizId`=?"; 318 $result = $this->query($query, $bindvars); 319 } 320 321 /** 322 * @param $quizId 323 * @param $offset 324 * @param $maxRecords 325 * @param $sort_mode 326 * @param $find 327 * @return array 328 */ 329 public function list_quiz_stats($quizId, $offset, $maxRecords, $sort_mode, $find) 330 { 331 $this->compute_quiz_stats(); 332 333 $query = "select `passingperct` from `tiki_quizzes` where `quizId` = ?"; 334 $passingperct = $this->getOne($query, [(int) $quizId]); 335 336 if ($find) { 337 //isnt that superflous? hmm. 338 $findesc = '%' . $find . '%'; 339 } 340 $mid = " where `quizId`=?"; 341 $bindvars = [(int) $quizId]; 342 343 $query = "select * from `tiki_user_quizzes` $mid order by " . $this->convertSortMode($sort_mode); 344 $query_cant = "select count(*) from `tiki_user_quizzes` $mid"; 345 $result = $this->query($query, $bindvars, $maxRecords, $offset); 346 $cant = $this->getOne($query_cant, $bindvars); 347 $ret = []; 348 349 while ($res = $result->fetchRow()) { 350 $res["avgavg"] = ($res["maxPoints"] != 0) ? $res["points"] / $res["maxPoints"] * 100 : 0.0; 351 352 if (isset($passingperct) && $passingperct > 0) { 353 $res['ispassing'] = ($res["avgavg"] >= $passingperct) ? true : false; 354 } 355 356 $hasDet = $this->getOne( 357 "select count(*) from `tiki_user_answers` where `userResultId`=?", 358 [(int) $res["userResultId"]] 359 ); 360 if ($hasDet) { 361 $res["hasDetails"] = 'y'; 362 } else { 363 $res["hasDetails"] = 'n'; 364 } 365 366 $ret[] = $res; 367 } 368 369 $retval = []; 370 $retval["data"] = $ret; 371 $retval["cant"] = $cant; 372 return $retval; 373 } 374 375 /** 376 * @param $offset 377 * @param $maxRecords 378 * @param $sort_mode 379 * @param $find 380 * @return array 381 */ 382 public function list_quiz_sum_stats($offset, $maxRecords, $sort_mode, $find) 383 { 384 $this->compute_quiz_stats(); 385 386 $stats = $this->table('tiki_quiz_stats_sum'); 387 $conditions = []; 388 389 if ($find) { 390 $conditions['quizName'] = $stats->like("%$find%"); 391 } 392 393 return [ 394 'data' => $stats->fetchAll($stats->all(), $conditions, $maxRecords, $offset, $stats->expr($this->convertSortMode($sort_mode))), 395 'cant' => $stats->fetchCount($conditions), 396 ]; 397 } 398 399 400 401 // Takes a given uploaded answer and inserts it into the DB. - burley 402 /** 403 * @param $userResultId 404 * @param $questionId 405 * @param $filename 406 * @param $filetype 407 * @param $filesize 408 * @param $tmp_name 409 */ 410 public function register_user_quiz_answer_upload($userResultId, $questionId, $filename, $filetype, $filesize, $tmp_name) 411 { 412 413 $data = fread(fopen($tmp_name, "r"), filesize($tmp_name)); 414 415 $query = "insert into `tiki_user_answers_uploads`" 416 . "(`userResultId`,`questionId`,`filename`,`filetype`,`filesize`,`filecontent`)" 417 . " values(?,?,?,?,?,?)"; 418 $result = $this->query($query, [(int) $userResultId, (int) $questionId, $filename, $filetype, $filesize, $data]); 419 } 420 421 422 /** 423 * @param $userResultId 424 * @param $quizId 425 * @param $questionId 426 * @param $optionId 427 */ 428 public function register_user_quiz_answer($userResultId, $quizId, $questionId, $optionId) 429 { 430 $query = "insert into `tiki_user_answers`(`userResultId`,`quizId`,`questionId`,`optionId`) values(?,?,?,?)"; 431 $result = $this->query($query, [(int) $userResultId, (int) $quizId, (int) $questionId, (int) $optionId]); 432 } 433 434 /** 435 * @param $quizId 436 * @param $user 437 * @param $timeTaken 438 * @param $points 439 * @param $maxPoints 440 * @param $resultId 441 * @return mixed 442 */ 443 public function register_quiz_stats($quizId, $user, $timeTaken, $points, $maxPoints, $resultId) 444 { 445 // Fix a bug if no result is indicated. 446 if (! $resultId) { 447 $resultId = 0; 448 } 449 450 $query = "insert into `tiki_user_quizzes`(`user`,`quizId`,`timestamp`,`timeTaken`,`points`,`maxPoints`,`resultId`) values(?,?,?,?,?,?,?)"; 451 $result = $this->query( 452 $query, 453 [ 454 $user, 455 $quizId, 456 $this->now, 457 $timeTaken, 458 $points, 459 $maxPoints, 460 $resultId 461 ] 462 ); 463 $queryId = $this->getOne( 464 "select max(`userResultId`) from `tiki_user_quizzes` where `timestamp`=? and `quizId`=?", 465 [$this->now, (int) $quizId] 466 ); 467 return $queryId; 468 } 469 470 /** 471 * @param $quizId 472 * @param $questionId 473 * @param $optionId 474 * @return bool 475 */ 476 public function register_quiz_answer($quizId, $questionId, $optionId) 477 { 478 $cant = $this->getOne( 479 "select count(*) from `tiki_quiz_stats` where `quizId`=? and `questionId`=? and `optionId`=?", 480 [(int) $quizId, (int) $questionId, (int) $optionId] 481 ); 482 483 if ($cant) { 484 $query = "update `tiki_quiz_stats` set `votes`=`votes`+1 where `quizId`=? and `questionId`=? and `optionId`=?"; 485 $bindvars = [(int) $quizId, (int) $questionId, (int) $optionId]; 486 } else { 487 $query = "insert into `tiki_quiz_stats`(`quizId`,`questionId`,`optionId`,`votes`) values(?,?,?,?)"; 488 $bindvars = [(int) $quizId, (int) $questionId, (int) $optionId,1]; 489 } 490 491 $result = $this->query($query, $bindvars); 492 493 return true; 494 } 495 496 /** 497 * @param $quizId 498 * @param $points 499 * @return int 500 */ 501 public function calculate_quiz_result($quizId, $points) 502 { 503 $query = "select * from `tiki_quiz_results` where `fromPoints`<=? and `toPoints`>=? and `quizId`=?"; 504 505 $result = $this->query($query, [(int) $points, (int) $points, (int) $quizId]); 506 507 if (! $result->numRows()) { 508 return 0; 509 } 510 511 $res = $result->fetchRow(); 512 return $res; 513 } 514 515 /** 516 * @param $user 517 * @param $quizId 518 * @return mixed 519 */ 520 public function user_has_taken_quiz($user, $quizId) 521 { 522 $cant = $this->getOne("select count(*) from `tiki_user_taken_quizzes` where `user`=? and `quizId`=?", [$user, (int) $quizId]); 523 524 return $cant; 525 } 526 527 /** 528 * @param $user 529 * @param $quizId 530 */ 531 public function user_takes_quiz($user, $quizId) 532 { 533 $query = "delete from `tiki_user_taken_quizzes` where `user`=? and `quizId`=?"; 534 $bindvars = [$user,(int) $quizId]; 535 $result = $this->query($query, $bindvars, -1, -1, false); 536 $query = "insert into `tiki_user_taken_quizzes`(`user`,`quizId`) values(?,?)"; 537 $result = $this->query($query, $bindvars); 538 } 539 540 /** 541 * @param $resultId 542 * @param $quizId 543 * @param $fromPoints 544 * @param $toPoints 545 * @param $answer 546 * @return mixed 547 */ 548 public function replace_quiz_result($resultId, $quizId, $fromPoints, $toPoints, $answer) 549 { 550 if ($resultId) { 551 // update an existing quiz 552 $query = "update `tiki_quiz_results` set `fromPoints` = ?, `toPoints` = ?, `quizId` = ?, `answer` = ? where `resultId` = ?"; 553 $bindvars = [(int) $fromPoints,(int) $toPoints, (int) $quizId, $answer, (int) $resultId]; 554 $result = $this->query($query, $bindvars); 555 } else { 556 // insert a new quiz 557 558 $query = "insert into `tiki_quiz_results`(`quizId`,`fromPoints`,`toPoints`,`answer`) values(?,?,?,?)"; 559 $bindvars = [(int) $quizId, (int) $fromPoints, (int) $toPoints, $answer]; 560 $result = $this->query($query, $bindvars); 561 $queryid = "select max(`resultId`) from `tiki_quiz_results` where `fromPoints`=? and `toPoints`=? and `quizId`=?"; 562 $quizId = $this->getOne($queryid, [(int) $fromPoints, (int) $toPoints, $quizId]); 563 } 564 565 return $quizId; 566 } 567 568 /** 569 * @param $resultId 570 * @return bool 571 */ 572 public function get_quiz_result($resultId) 573 { 574 $query = "select * from `tiki_quiz_results` where `resultId`=?"; 575 576 $result = $this->query($query, [(int) $resultId]); 577 578 if (! $result->numRows()) { 579 return false; 580 } 581 582 $res = $result->fetchRow(); 583 return $res; 584 } 585 586 /** 587 * @param $resultId 588 * @return bool 589 */ 590 public function remove_quiz_result($resultId) 591 { 592 $query = "delete from `tiki_quiz_results` where `resultId`=?"; 593 594 $result = $this->query($query, [$resultId]); 595 return true; 596 } 597 598 /** 599 * @param $quizId 600 * @param $offset 601 * @param $maxRecords 602 * @param $sort_mode 603 * @param $find 604 * @return array 605 */ 606 public function list_quiz_results($quizId, $offset, $maxRecords, $sort_mode, $find) 607 { 608 609 if ($find) { 610 $findesc = '%' . $find . '%'; 611 612 $mid = " where `quizId`=? and `answer` like ? "; 613 $bindvars = [(int) $quizId, $findesc]; 614 } else { 615 $mid = " where `quizId`=? "; 616 $bindvars = [(int) $quizId]; 617 } 618 619 $query = "select * from `tiki_quiz_results` $mid order by " . $this->convertSortMode($sort_mode); 620 $query_cant = "select count(*) from `tiki_quiz_results` $mid"; 621 $result = $this->query($query, $bindvars, $maxRecords, $offset); 622 $cant = $this->getOne($query_cant, $bindvars); 623 $ret = []; 624 625 while ($res = $result->fetchRow()) { 626 $ret[] = $res; 627 } 628 629 $retval = []; 630 $retval["data"] = $ret; 631 $retval["cant"] = $cant; 632 return $retval; 633 } 634 635 // called by tiki-edit_quiz.php 636 /** 637 * @param $quizId 638 * @param $name 639 * @param $description 640 * @param $canRepeat 641 * @param $storeResults 642 * @param $immediateFeedback 643 * @param $showAnswers 644 * @param $shuffleQuestions 645 * @param $shuffleAnswers 646 * @param $questionsPerPage 647 * @param $timeLimited 648 * @param $timeLimit 649 * @param $publishDate 650 * @param $expireDate 651 * @param $passingperct 652 * @return mixed 653 */ 654 public function replace_quiz($quizId, $name, $description, $canRepeat, $storeResults, $immediateFeedback, $showAnswers, $shuffleQuestions, $shuffleAnswers, $questionsPerPage, $timeLimited, $timeLimit, $publishDate, $expireDate, $passingperct 655 ) 656 { 657 if ($quizId) { 658 // update an existing quiz 659 $query = "update `tiki_quizzes` set `name` = ?, `description` = ?, `canRepeat` = ?, `storeResults` = ?,"; 660 $query .= "`immediateFeedback` = ?, `showAnswers` = ?, `shuffleQuestions` = ?, `shuffleAnswers` = ?, "; 661 $query .= "`publishDate` = ?, `expireDate` = ?, "; 662 $query .= "`questionsPerPage` = ?, `timeLimited` = ?, `timeLimit` =?, `passingperct` = ? where `quizId` = ?"; 663 $bindvars = [$name, 664 $description, 665 $canRepeat, 666 $storeResults, 667 $immediateFeedback, 668 $showAnswers, 669 $shuffleQuestions, 670 $shuffleAnswers, 671 $publishDate, 672 $expireDate, 673 (int) $questionsPerPage, 674 $timeLimited, 675 (int) $timeLimit, 676 (int) $passingperct, 677 (int) $quizId 678 ]; 679 680 $result = $this->query($query, $bindvars); 681 } else { 682 // insert a new quiz 683 684 $query = "insert into `tiki_quizzes`(`name`,`description`,`canRepeat`,`storeResults`,"; 685 $query .= "`immediateFeedback`, `showAnswers`, `shuffleQuestions`, `shuffleAnswers`,"; 686 $query .= "`publishDate`, `expireDate`,"; 687 $query .= "`questionsPerPage`,`timeLimited`,`timeLimit`,`created`,`taken`,`passingperct`)"; 688 $query .= " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 689 $bindvars = [ 690 $name, 691 $description, 692 $canRepeat, 693 $storeResults, 694 $immediateFeedback, 695 $showAnswers, 696 $shuffleQuestions, 697 $shuffleAnswers, 698 $publishDate, 699 $expireDate, 700 (int) $questionsPerPage, 701 $timeLimited, 702 (int) $timeLimit, 703 (int) $this->now, 704 0, 705 (int) $passingperct 706 ]; 707 $result = $this->query($query, $bindvars); 708 $queryid = "select max(`quizId`) from `tiki_quizzes` where `created`=?"; 709 $quizId = $this->getOne($queryid, [(int) $this->now]); 710 } 711 712 return $quizId; 713 } 714 715 /** 716 * @param $questionId 717 * @param $question 718 * @param $type 719 * @param $quizId 720 * @param $position 721 * @return mixed 722 */ 723 public function replace_quiz_question($questionId, $question, $type, $quizId, $position) 724 { 725 if ($questionId) { 726 // update an existing quiz 727 $query = "update `tiki_quiz_questions` set `type`=?, `position` = ?, `question` = ? where `questionId` = ? and `quizId`=?"; 728 $bindvars = [$type,(int) $position, $question, (int) $questionId, (int) $quizId]; 729 $result = $this->query($query, $bindvars); 730 } else { 731 // insert a new quiz 732 733 $query = "insert into `tiki_quiz_questions`(`question`,`type`,`quizId`,`position`) values(?,?,?,?)"; 734 $bindvars = [$question, $type, (int) $quizId, (int) $position]; 735 $result = $this->query($query, $bindvars); 736 $queryid = "select max(`questionId`) from `tiki_quiz_questions` where `question` like ? and `type`=?"; 737 $questionId = $this->getOne($queryid, [substr($question, 0, 200) . "%", $type]); 738 } 739 return $questionId; 740 } 741 742 /** 743 * @param $optionId 744 * @param $option 745 * @param $points 746 * @param $questionId 747 * @return mixed 748 */ 749 public function replace_question_option($optionId, $option, $points, $questionId) 750 { 751 752 // validating the points value 753 if ((! is_numeric($points)) || ($points == "")) { 754 $points = 0; 755 } 756 if ($optionId) { 757 $query = "update `tiki_quiz_question_options` set `points`=?, `optionText` = ? where `optionId` = ? and `questionId`=?"; 758 $bindvars = [(int) $points, $option,(int) $optionId, (int) $questionId]; 759 $result = $this->query($query, $bindvars); 760 } else { 761 $query = "insert into `tiki_quiz_question_options`(`optionText`,`points`,`questionId`) values(?,?,?)"; 762 $result = $this->query($query, [$option, (int) $points, (int) $questionId]); 763 $queryid = "select max(`optionId`) from `tiki_quiz_question_options` where `optionText`=? and `questionId`=?"; 764 $optionId = $this->getOne($queryid, [$option, (int) $questionId]); 765 } 766 767 return $optionId; 768 } 769 770 /** 771 * @param $questionId 772 * @return bool 773 */ 774 public function get_quiz_question($questionId) 775 { 776 $query = "select * from `tiki_quiz_questions` where `questionId`=?"; 777 $result = $this->query($query, [(int) $questionId]); 778 if (! $result->numRows()) { 779 return false; 780 } 781 $res = $result->fetchRow(); 782 return $res; 783 } 784 785 /** 786 * @param $optionId 787 * @return bool 788 */ 789 public function get_quiz_question_option($optionId) 790 { 791 $query = "select * from `tiki_quiz_question_options` where `optionId`=?"; 792 $result = $this->query($query, [(int) $optionId]); 793 if (! $result->numRows()) { 794 return false; 795 } 796 $res = $result->fetchRow(); 797 return $res; 798 } 799 800 /** 801 * @param $quizId 802 * @param $offset 803 * @param $maxRecords 804 * @param $sort_mode 805 * @param $find 806 * @return array 807 */ 808 public function list_quiz_questions($quizId, $offset, $maxRecords, $sort_mode, $find) 809 { 810 if ($find) { 811 $findesc = '%' . $find . '%'; 812 $mid = " where `quizId`=? and `question` like ? "; 813 $bindvars = [(int) $quizId, $findesc]; 814 } else { 815 $mid = " where `quizId`=? "; 816 $bindvars = [(int) $quizId]; 817 } 818 819 $query = "select * from `tiki_quiz_questions` $mid order by " . $this->convertSortMode($sort_mode); 820 $query_cant = "select count(*) from `tiki_quiz_questions` $mid"; 821 $result = $this->query($query, $bindvars, $maxRecords, $offset); 822 $cant = $this->getOne($query_cant, $bindvars); 823 $ret = []; 824 825 while ($res = $result->fetchRow()) { 826 $res["options"] = $this->getOne("select count(*) from `tiki_quiz_question_options` where `questionId`=?", [(int) $res["questionId"]]); 827 $res["maxPoints"] = $this->getOne("select max(`points`) from `tiki_quiz_question_options` where `questionId`=?", [(int) $res["questionId"]]); 828 $ret[] = $res; 829 } 830 831 $retval = []; 832 $retval["data"] = $ret; 833 $retval["cant"] = $cant; 834 return $retval; 835 } 836 837 /** 838 * @param $offset 839 * @param $maxRecords 840 * @param string $sort_mode 841 * @param $find 842 * @return array 843 */ 844 public function list_all_questions($offset, $maxRecords, $sort_mode = "position_desc", $find) 845 { 846 if ($find) { 847 $findesc = '%' . $find . '%'; 848 849 $mid = " where `question` like ? "; 850 $bindvars = [$findesc]; 851 } else { 852 $mid = " "; 853 $bindvars = []; 854 } 855 856 $query = "select * from `tiki_quiz_questions` $mid order by " . $this->convertSortMode($sort_mode); 857 $query_cant = "select count(*) from `tiki_quiz_questions` $mid"; 858 $result = $this->query($query, $bindvars, $maxRecords, $offset); 859 $cant = $this->getOne($query_cant, $bindvars); 860 $ret = []; 861 862 while ($res = $result->fetchRow()) { 863 $res["options"] 864 = $this->getOne("select count(*) from `tiki_quiz_question_options` where `questionId`=?", [(int) $res["questionId"]]); 865 866 $ret[] = $res; 867 } 868 869 $retval = []; 870 $retval["data"] = $ret; 871 $retval["cant"] = $cant; 872 return $retval; 873 } 874 875 /** 876 * @param $questionId 877 * @param $offset 878 * @param $maxRecords 879 * @param $sort_mode 880 * @param $find 881 * @return array 882 */ 883 public function list_quiz_question_options($questionId, $offset, $maxRecords, $sort_mode, $find) 884 { 885 if ($find) { 886 $findesc = '%' . $find . '%'; 887 888 $mid = " where `questionId`=? and `optionText` like ? "; 889 $bindvars = [(int) $questionId,$findesc]; 890 } else { 891 $mid = " where `questionId`=? "; 892 $bindvars = [(int) $questionId]; 893 } 894 895 $query = "select * from `tiki_quiz_question_options` $mid order by " . $this->convertSortMode($sort_mode); 896 $query_cant = "select count(*) from `tiki_quiz_question_options` $mid"; 897 $result = $this->query($query, $bindvars, $maxRecords, $offset); 898 $cant = $this->getOne($query_cant, $bindvars); 899 $ret = []; 900 901 while ($res = $result->fetchRow()) { 902 $ret[] = $res; 903 } 904 905 $retval = []; 906 $retval["data"] = $ret; 907 $retval["cant"] = $cant; 908 return $retval; 909 } 910 911 /** 912 * @param $questionId 913 * @return bool 914 */ 915 public function remove_quiz_question($questionId) 916 { 917 $query = "delete from `tiki_quiz_questions` where `questionId`=?"; 918 919 $result = $this->query($query, [(int) $questionId]); 920 // Remove all the options for the question 921 $query = "delete from `tiki_quiz_question_options` where `questionId`=?"; 922 $result = $this->query($query, [(int) $questionId]); 923 return true; 924 } 925 926 /** 927 * @param $optionId 928 * @return bool 929 */ 930 public function remove_quiz_question_option($optionId) 931 { 932 $query = "delete from `tiki_quiz_question_options` where `optionId`=?"; 933 934 $result = $this->query($query, [(int) $optionId]); 935 return true; 936 } 937 938 /** 939 * @param $quizId 940 * @return bool 941 */ 942 public function remove_quiz($quizId) 943 { 944 $query = "delete from `tiki_quizzes` where `quizId`=?"; 945 946 $result = $this->query($query, [(int) $quizId]); 947 $query = "select * from `tiki_quiz_questions` where `quizId`=?"; 948 $result = $this->query($query, [(int) $quizId]); 949 950 // Remove all the options for each question 951 while ($res = $result->fetchRow()) { 952 $questionId = $res["questionId"]; 953 954 $query2 = "delete from `tiki_quiz_question_options` where `questionId`=?"; 955 $result2 = $this->query($query2, [(int) $questionId]); 956 } 957 958 // Remove all the questions 959 $query = "delete from `tiki_quiz_questions` where `quizId`=?"; 960 $result = $this->query($query, [(int) $quizId]); 961 $query = "delete from `tiki_quiz_results` where `quizId`=?"; 962 $result = $this->query($query, [(int) $quizId]); 963 $query = "delete from `tiki_quiz_stats` where `quizId`=?"; 964 $result = $this->query($query, [(int) $quizId]); 965 $query = "delete from `tiki_user_quizzes` where `quizId`=?"; 966 $result = $this->query($query, [(int) $quizId]); 967 $query = "delete from `tiki_user_answers` where `quizId`=?"; 968 $result = $this->query($query, [(int) $quizId]); 969 $this->remove_object('quiz', $quizId); 970 return true; 971 } 972 973 /** 974 * @param $id 975 * @return Quiz 976 */ 977 public function quiz_fetch($id) 978 { 979 if ($id == 0) { 980 $quiz = new Quiz; 981 } else { 982 echo __FILE__ . " line: " . __LINE__ . " : Need to fetch a quiz from the database" . "<br />"; 983 } 984 return $quiz; 985 } 986 987 // $quiz is a quiz object 988 /** 989 * @param $quiz 990 * @return mixed 991 */ 992 public function quiz_store($quiz) 993 { 994 echo __FILE__ . " line: " . __LINE__ . ": in quizlib->quiz_store<br />"; 995 echo "Store stuff in the dbFields array.<br />"; 996 foreach ($quiz->dbFields as $f) { 997 } 998 die; 999 if ($quizId) { 1000 // update an existing quiz 1001 $query = "update `tiki_quizzes` set `name` = ?, `description` = ?, `canRepeat` = ?, `storeResults` = ?,"; 1002 $query .= "`immediateFeedback` = ?, `showAnswers` = ?, `shuffleQuestions` = ?, `shuffleAnswers` = ?, "; 1003 $query .= "`publishDate` = ?, `expireDate` = ?, "; 1004 $query .= "`questionsPerPage` = ?, `timeLimited` = ?, `timeLimit` =? where `quizId` = ?"; 1005 $bindvars = [ 1006 $name, 1007 $description, 1008 $canRepeat, 1009 $storeResults, 1010 $immediateFeedback, 1011 $showAnswers, 1012 $shuffleQuestions, 1013 $shuffleAnswers, 1014 $publishDate, 1015 $expireDate, 1016 (int) $questionsPerPage, 1017 $timeLimited, 1018 (int) $timeLimit, 1019 (int) $quizId 1020 ]; 1021 1022 $result = $this->query($query, $bindvars); 1023 } else { 1024 // insert a new quiz 1025 1026 $query = "insert into `tiki_quizzes`(`name`,`description`,`canRepeat`,`storeResults`,"; 1027 $query .= "`immediateFeedback`, `showAnswers`, `shuffleQuestions`, `shuffleAnswers`,"; 1028 $query .= "`publishDate`, `expireDate`,"; 1029 $query .= "`questionsPerPage`,`timeLimited`,`timeLimit`,`created`,`taken`) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 1030 $bindvars = [$name, 1031 $description, 1032 $canRepeat, 1033 $storeResults, 1034 $immediateFeedback, 1035 $showAnswers, 1036 $shuffleQuestions, 1037 $shuffleAnswers, 1038 $publishDate, 1039 $expireDate, 1040 (int) $questionsPerPage, 1041 $timeLimited, 1042 (int) $timeLimit, 1043 (int) $this->now, 1044 0 1045 ]; 1046 $result = $this->query($query, $bindvars); 1047 $queryid = "select max(`quizId`) from `tiki_quizzes` where `created`=?"; 1048 $quizId = $this->getOne($queryid, [(int) $this->now]); 1049 } 1050 1051 return $quizId; 1052 } 1053 1054 /** 1055 * @return string 1056 */ 1057 public function get_upload_dir() 1058 { 1059 return "quiz_uploads/"; 1060 } 1061} 1062 1063// Find the next non-blank or return -1 1064/** 1065 * @param $text 1066 * @return int 1067 */ 1068function NextText($text) 1069{ 1070 $found = -1; 1071 for ($i = 0, $icount_text = count($text); $i < $icount_text; $i++) { 1072 if (strlen($text[$i]) > 0) { 1073 $found = $i; 1074 break; 1075 } 1076 } 1077 return $found; 1078} 1079 1080// Find the next blank or retrun the last element 1081/** 1082 * @param $text 1083 * @return int 1084 */ 1085function NextBlank($text) 1086{ 1087 $found = 0; 1088 for ($i = 0, $icount_text = count($text); $i < $icount_text; $i++) { 1089 $found = $i; 1090 if ($text[$i] == "") { 1091 break; 1092 } 1093 } 1094 return $found; 1095} 1096 1097/** 1098 * @param $s 1099 */ 1100function quizlib_error_exit($s) 1101{ 1102 $smarty = TikiLib::lib('smarty'); 1103 $smarty->assign('msg', $s); 1104 1105 $smarty->display("error.tpl"); 1106 die; 1107} 1108 1109// Called by tiki-edit_quiz_questions.php 1110// Convert a block of text into an array of question objects. 1111/** 1112 * @param $text 1113 * @return array 1114 */ 1115function TextToQuestions($text) 1116{ 1117 $text = preg_replace("/\r\n/", "\n", $text); 1118 $text = preg_replace("/\n\r/", "\n", $text); 1119 $text = preg_replace("/\r/", "\n", $text); 1120 $text = preg_replace("/\t/", " ", $text); 1121 $text = preg_replace("/[ ]+/", " ", $text); 1122 1123 $text = preg_split("/\n/", $text); 1124 1125 if ($text[count($text) - 1] != "") { 1126 $text[] = ""; 1127 } 1128 1129 for ($i = 0, $icount_text = count($text); $i < $icount_text; $i++) { 1130 $text[$i] = trim($text[$i]); 1131 if ($text[$i] and ! ctype_print($text[$i])) { 1132 quizlib_error_exit( 1133 "lib/quizzes/quizlib.php line " 1134 . __LINE__ 1135 . ": Your text has invalid character(s) near line $i where it says:\n $text[$i]" 1136 ); 1137 } 1138 } 1139 1140 $questions = []; 1141 1142 while (NextText($text) != -1) { 1143 $text = array_slice($text, NextText($text)); 1144 $lines = array_slice($text, 0, NextBlank($text)); 1145 $text = array_slice($text, NextBlank($text)); 1146 if (count($lines) > 0) { 1147 $question = new HW_QuizQuestionMultipleChoice($lines); 1148 array_push($questions, $question); 1149 } 1150 } 1151 return $questions; 1152} 1153 1154// An abstract class 1155/** 1156 * 1157 */ 1158class HW_QuizQuestion 1159{ 1160 public $question; 1161 1162 /** 1163 * @param $lines 1164 */ 1165 public function from_text($lines) 1166 { 1167 // Set the question according to an array of text lines. 1168 } 1169 public function getQuestion() 1170 { 1171 return $this->question; 1172 } 1173 public function to_text() 1174 { 1175 // Export the question to an array of text lines. 1176 } 1177 public function getAnswerCount() 1178 { 1179 // How many possible answers (i.e. choices in a multiple-choice) 1180 } 1181} 1182 1183// A multiple-choice quiz question 1184// e.g. 1185// $question = "What is your favorite color?"; 1186// $choices = Array(Array('text'=>"Red", 'correct'=>1), 1187// Array('text'=>"Blue", 'correct'=>1), 1188// Array('text'=>"Green",'correct'=>1)); 1189// Any of the answers are correct in this example. 1190/** 1191 * 1192 */ 1193class HW_QuizQuestionMultipleChoice extends HW_QuizQuestion 1194{ 1195 public $choices = []; 1196 1197 /** 1198 * @param $lines 1199 */ 1200 public function __construct($lines) 1201 { 1202 $this->from_text($lines); 1203 } 1204 1205 // Import from text array 1206 // $lines is in array of text items. 1207 // The 0th line is the question. 1208 // The rest of the lines are answers. 1209 // Correct answers start with a "*" 1210 /** 1211 * @param $lines 1212 */ 1213 public function from_text($lines) 1214 { 1215 $this->question = $lines[0]; 1216 $this->choices = []; 1217 $lines = array_slice($lines, 1); 1218 foreach ($lines as $line) { 1219 if (preg_match("/^\*\s*(.*)/", $line, $match)) { 1220 // Ignore spaces after the "*" 1221 $a = ['text' => $match[1],'correct' => 1]; 1222 } else { 1223 $a = ['text' => $line,'correct' => 0]; 1224 } 1225 array_push($this->choices, $a); 1226 } 1227 } 1228 1229 // Export the question to an array of text lines. 1230 /** 1231 * @param bool $show_answer 1232 * @return array 1233 */ 1234 public function to_text($show_answer = false) 1235 { 1236 $lines = []; 1237 array_push($lines, $this->question); 1238 foreach ($this->choices as $choice) { 1239 if ($show_answer && $choice['correct']) { 1240 array_push($lines, "*" . $choice['text']); 1241 } else { 1242 array_push($lines, " " . $choice['text']); 1243 } 1244 } 1245 return $lines; 1246 } 1247 1248 /** 1249 * @return int 1250 */ 1251 public function getChoiceCount() 1252 { 1253 return count($this->choices); 1254 } 1255 1256 /** 1257 * @param $i 1258 * @return mixed 1259 */ 1260 public function getChoice($i) 1261 { 1262 return $this->choices[$i]['text']; 1263 } 1264 1265 /** 1266 * @param $i 1267 * @return mixed 1268 */ 1269 public function getCorrect($i) 1270 { 1271 return $this->choices[$i]['correct']; 1272 } 1273 1274 public function dump() 1275 { 1276 echo "question = \"" . $this->question . "\"\n"; 1277 echo "choices =\n"; 1278 foreach ($this->choices as $choice) { 1279 if ($choice['correct']) { 1280 echo "*"; 1281 } else { 1282 echo " "; 1283 } 1284 echo $choice['text'] . "\n"; 1285 } 1286 } 1287} 1288 1289// A Yes-No quiz question 1290// e.g. 1291// $question = "Do you wiki?"; 1292// $answer = -1 (unknown), 0 (no), 1 (yes) 1293/** 1294 * 1295 */ 1296class HW_QuizQuestionYesNo extends HW_QuizQuestion 1297{ 1298 public $question; 1299 public $answer = -1; 1300 1301 /** 1302 * @param $lines 1303 */ 1304 public function __construct($lines) 1305 { 1306 $this->from_text($lines); 1307 } 1308 1309 // Import from text array 1310 // $lines is in array of text items. 1311 // The 0th line is the question. 1312 // The first line is the answer. 1313 /** 1314 * @param $lines 1315 */ 1316 public function from_text($lines) 1317 { 1318 $this->question = $lines[0]; 1319 if (preg_match("/^\s*[Yy][Ee][Ss]\s*$/", $lines[1])) { 1320 // Ignore spaces and case 1321 $this->answer = 1; 1322 } elseif (preg_match("/^\s*[Nn][Oo]\s*$/", $lines[1])) { 1323 // Ignore spaces and case 1324 $this->answer = 0; 1325 } else { 1326 $this->answer = -1; 1327 } 1328 } 1329 1330 /** 1331 * @param bool $show_answer 1332 * @return array 1333 */ 1334 public function to_text($show_answer = false) 1335 { 1336 // Export the question to an array of text lines. 1337 $lines = []; 1338 array_push($lines, $this->question); 1339 if ($this->answer == 1) { 1340 array_push($lines, " Yes"); 1341 } elseif ($this->answer == 0) { 1342 array_push($lines, " No"); 1343 } else { 1344 array_push($lines, " Unknown"); 1345 } 1346 return $lines; 1347 } 1348 1349 public function dump() 1350 { 1351 echo "question = \"" . $this->question . "\"\n"; 1352 echo "answer = $this->answer\n"; 1353 } 1354} 1355 1356/** 1357 * 1358 */ 1359class Quiz 1360{ 1361 public $id; 1362 public $bDeleted; 1363 public $timestamp; 1364 public $nAuthor; 1365 public $bOnline; 1366 public $nTaken; 1367 public $sName; 1368 public $sDescription; 1369 public $datePub; 1370 public $dateExp; 1371 public $bRandomQuestions; 1372 public $nRandomQuestions; 1373 public $bShuffleQuestions; 1374 public $bShuffleAnswers; 1375 public $bLimitQuestionsPerPage; 1376 public $nLimitQuestionsPerPage; 1377 public $bTimeLimited; 1378 public $nTimeLimit; 1379 public $bMultiSession; 1380 public $bCanRepeat; 1381 public $nCanRepeat; 1382 public $sGradingMethod; 1383 public $sShowScore; 1384 public $sShowCorrectAnswers; 1385 public $sPublishStats; 1386 public $bAdditionalQuestions; 1387 public $bForum; 1388 public $sForum; 1389 public $sPrologue; 1390 public $sData; 1391 public $sEpilogue; 1392 public $dbFields; 1393 1394 public function __construct() 1395 { 1396 global $user; 1397 $userlib = TikiLib::lib('user'); 1398 $this->dbFields = [ 1399 "id", 1400 "bDeleted", 1401 "timestamp", 1402 "nAuthor", 1403 "bOnline", 1404 "nTaken", 1405 "sName", 1406 "sDescription", 1407 "datePub", 1408 "dateExp", 1409 "bRandomQuestions", 1410 "nRandomQuestions", 1411 "bShuffleQuestions", 1412 "bShuffleAnswers", 1413 "bLimitQuestionsPerPage", 1414 "nLimitQuestionsPerPage", 1415 "bTimeLimited", 1416 "nTimeLimit", 1417 "bMultiSession", 1418 "bCanRepeat", 1419 "nCanRepeat", 1420 "sGradingMethod", 1421 "sShowScore", 1422 "sShowCorrectAnswers", 1423 "sPublishStats", 1424 "bAdditionalQuestions", 1425 "bForum", 1426 "sForum", 1427 "sPrologue", 1428 "sData", 1429 "sEpilogue" 1430 ]; 1431 $this->id = 0; 1432 $this->bDeleted = 0; 1433 $this->timestamp = $this->now; 1434 $this->nAuthor = $userlib->get_user_id($user); 1435 $this->sAuthor = $user; 1436 $this->bOnline = 'n'; 1437 $this->nTaken = 'n'; 1438 $this->sName = ""; 1439 $this->sDescription = ""; 1440 $this->datePub = $this->now; 1441 $this->dateExp = TikiLib::make_time(0, 0, 0, 1, 1, TikiLib::date_format("%Y") + 10); 1442 $this->bRandomQuestions = "y"; 1443 $this->nRandomQuestions = 10; 1444 $this->nShuffleQuestions = "y"; 1445 $this->bShuffleAnswers = "y"; 1446 $this->bLimitQuestionsPerPage = "y"; 1447 $this->nLimitQuestionsPerPage = 1; 1448 $this->bTimeLimited = "n"; 1449 $this->nTimeLimit = "1"; 1450 $this->bMultiSession = "n"; 1451 $this->bCanRepeat = "y"; 1452 $this->nCanRepeat = "unlimited"; 1453 $this->sGradingMethod = "machine"; 1454 $this->sShowScore = "immediately"; 1455 $this->sShowCorrectAnswers = "immediately"; 1456 $this->sPublishStats = "immediately"; 1457 $this->bAdditionalQuestions = "n"; 1458 1459 $this->forum = "n"; 1460 $this->forumName = ""; 1461 $this->prologue = ""; 1462 $this->epilogue = ""; 1463 } 1464 1465 // dump as html text 1466 /** 1467 * @return array 1468 */ 1469 public function show_html() 1470 { 1471 $userlib = TikiLib::lib('user'); 1472 $lines = []; 1473 $lines[] = "id = " . $this->id . "<br />"; 1474 $lines[] = "deleted = " . $this->deleted . "<br />"; 1475 $authorInfo = $userlib->get_userid_info($this->author); 1476 $lines[] = "author id = " . $this->author . "; author login = " . $authorInfo["login"] . "<br />"; 1477 $lines[] = "version = " . $this->version . "<br />"; 1478 $lines[] = "timestamp = " . $this->date_format("%a, %e %b %Y %H:%M:%S %O", $this->timestamp) . "<br />"; 1479 $lines[] = "online = " . $this->online . "<br />"; 1480 $lines[] = "studentAttempts = " . $this->studentAttempts . "<br />"; 1481 $lines[] = "name = " . $this->name . "<br />"; 1482 $lines[] = "description = " . $this->description . "<br />"; 1483 $lines[] = "datePub = " . $this->date_format("%a, %e %b %Y %H:%M:%S %O", $this->datePub) . "<br />"; 1484 $lines[] = "dateExp = " . $this->date_format("%a, %e %b %Y %H:%M:%S %O", $this->dateExp) . "<br />"; 1485 $lines[] = "nQuestion = " . $this->nQuestion . "<br />"; 1486 $lines[] = "nQuestions = " . $this->nQuestions . "<br />"; 1487 $lines[] = "shuffleQuestions = " . $this->shuffleQuestions . "<br />"; 1488 $lines[] = "shuffleAnswers = " . $this->shuffleAnswers . "<br />"; 1489 $lines[] = "limitDisplay = " . $this->limitDisplay . "<br />"; 1490 $lines[] = "questionsPerPage = " . $this->questionsPerPage . "<br />"; 1491 $lines[] = "timeLimited = " . $this->timeLimited . "<br />"; 1492 $lines[] = "timeLimit = " . $this->timeLimit . "<br />"; 1493 $lines[] = "multiSession = " . $this->multiSession . "<br />"; 1494 $lines[] = "canRepeat = " . $this->canRepeat . "<br />"; 1495 $lines[] = "repetitions = " . $this->repetitions . "<br />"; 1496 $lines[] = "gradingMethod = " . $this->gradingMethod . "<br />"; 1497 $lines[] = "showScore = " . $this->showScore . "<br />"; 1498 $lines[] = "showCorrectAnswers = " . $this->showCorrectAnswers . "<br />"; 1499 $lines[] = "publishStats = " . $this->publishStats . "<br />"; 1500 $lines[] = "additionalQuestions = " . $this->additionalQuestions . "<br />"; 1501 $lines[] = "forum = " . $this->forum . "<br />"; 1502 $lines[] = "forumName = " . $this->forumName . "<br />"; 1503 $lines[] = "data = " . $this->data . "<br />"; 1504 return $lines; 1505 } 1506 1507 // Use any data in the array to replace the instance data. 1508 /** 1509 * @param $data 1510 */ 1511 public function data_load($data) 1512 { 1513 foreach ($this as $key => $val) { 1514 if (isset($data[$key]) && ($data[$key] != $val)) { 1515 $this->$key = $data[$key]; 1516 } 1517 } 1518 } 1519 1520 /** 1521 * @param $quiz 1522 */ 1523 public function compare($quiz) 1524 { 1525 } 1526 1527 public function getAnswerCount() 1528 { 1529 // How many possible answers (i.e. choices in a multiple-choice) 1530 } 1531} 1532