PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/question/format/webct/format.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 665 lines | 634 code | 4 blank | 27 comment | 1 complexity | abd5d80778473945ea823781e9b3f2c4 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Web CT question importer.
  18. *
  19. * @package qformat
  20. * @subpackage webct
  21. * @copyright 2004 ASP Consulting http://www.asp-consulting.net
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. defined('MOODLE_INTERNAL') || die();
  25. /**
  26. * Manipulate HTML editites in a string. Used by WebCT import.
  27. * @param string $string
  28. * @return string
  29. */
  30. function unhtmlentities($string){
  31. $search = array ("'<script[?>]*?>.*?</script>'si", // remove javascript
  32. "'<[\/\!]*?[^<?>]*?>'si", // remove HTML tags
  33. "'([\r\n])[\s]+'", // remove spaces
  34. "'&(quot|#34);'i", // remove HTML entites
  35. "'&(amp|#38);'i",
  36. "'&(lt|#60);'i",
  37. "'&(gt|#62);'i",
  38. "'&(nbsp|#160);'i",
  39. "'&(iexcl|#161);'i",
  40. "'&(cent|#162);'i",
  41. "'&(pound|#163);'i",
  42. "'&(copy|#169);'i",
  43. "'&#(\d+);'e"); // Evaluate like PHP
  44. $replace = array ("",
  45. "",
  46. "\\1",
  47. "\"",
  48. "&",
  49. "<",
  50. "?>",
  51. " ",
  52. chr(161),
  53. chr(162),
  54. chr(163),
  55. chr(169),
  56. "chr(\\1)");
  57. return preg_replace ($search, $replace, $string);
  58. }
  59. /**
  60. * Helper function for WebCT import.
  61. * @param unknown_type $formula
  62. */
  63. function qformat_webct_convert_formula($formula) {
  64. // Remove empty space, as it would cause problems otherwise:
  65. $formula = str_replace(' ', '', $formula);
  66. // Remove paranthesis after e,E and *10**:
  67. while (preg_match('~[0-9.](e|E|\\*10\\*\\*)\\([+-]?[0-9]+\\)~', $formula, $regs)) {
  68. $formula = str_replace(
  69. $regs[0], preg_replace('/[)(]/', '', $regs[0]), $formula);
  70. }
  71. // Replace *10** with e where possible
  72. while (preg_match('~(^[+-]?|[^eE][+-]|[^0-9eE+-])[0-9.]+\\*10\\*\\*[+-]?[0-9]+([^0-9.eE]|$)~',
  73. $formula, $regs)) {
  74. $formula = str_replace(
  75. $regs[0], str_replace('*10**', 'e', $regs[0]), $formula);
  76. }
  77. // Replace other 10** with 1e where possible
  78. while (preg_match('~(^|[^0-9.eE])10\\*\\*[+-]?[0-9]+([^0-9.eE]|$)~', $formula, $regs)) {
  79. $formula = str_replace(
  80. $regs[0], str_replace('10**', '1e', $regs[0]), $formula);
  81. }
  82. // Replace all other base**exp with the PHP equivalent function pow(base,exp)
  83. // (Pretty tricky to exchange an operator with a function)
  84. while (2 == count($splits = explode('**', $formula, 2))) {
  85. // Find $base
  86. if (preg_match('~^(.*[^0-9.eE])?(([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][+-]?[0-9]+)?|\\{[^}]*\\})$~',
  87. $splits[0], $regs)) {
  88. // The simple cases
  89. $base = $regs[2];
  90. $splits[0] = $regs[1];
  91. } else if (preg_match('~\\)$~', $splits[0])) {
  92. // Find the start of this parenthesis
  93. $deep = 1;
  94. for ($i = 1 ; $deep ; ++$i) {
  95. if (!preg_match('~^(.*[^[:alnum:]_])?([[:alnum:]_]*([)(])([^)(]*[)(]){'.$i.'})$~',
  96. $splits[0], $regs)) {
  97. print_error("parenthesisinproperstart", 'question', '', $splits[0]);
  98. }
  99. if ('(' == $regs[3]) {
  100. --$deep;
  101. } else if (')' == $regs[3]) {
  102. ++$deep;
  103. } else {
  104. print_error('impossiblechar', 'question', '', $regs[3]);
  105. }
  106. }
  107. $base = $regs[2];
  108. $splits[0] = $regs[1];
  109. } else {
  110. print_error('badbase', 'question', '', $splits[0]);
  111. }
  112. // Find $exp (similar to above but a little easier)
  113. if (preg_match('~^([+-]?(\\{[^}]\\}|([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][+-]?[0-9]+)?))(.*)~',
  114. $splits[1], $regs)) {
  115. // The simple case
  116. $exp = $regs[1];
  117. $splits[1] = $regs[6];
  118. } else if (preg_match('~^[+-]?[[:alnum:]_]*\\(~', $splits[1])) {
  119. // Find the end of the parenthesis
  120. $deep = 1;
  121. for ($i = 1 ; $deep ; ++$i) {
  122. if (!preg_match('~^([+-]?[[:alnum:]_]*([)(][^)(]*){'.$i.'}([)(]))(.*)~',
  123. $splits[1], $regs)) {
  124. print_error("parenthesisinproperclose", 'question', '', $splits[1]);
  125. }
  126. if (')' == $regs[3]) {
  127. --$deep;
  128. } else if ('(' == $regs[3]) {
  129. ++$deep;
  130. } else {
  131. print_error("impossiblechar", 'question');
  132. }
  133. }
  134. $exp = $regs[1];
  135. $splits[1] = $regs[4];
  136. }
  137. // Replace it!
  138. $formula = "$splits[0]pow($base,$exp)$splits[1]";
  139. }
  140. // Nothing more is known to need to be converted
  141. return $formula;
  142. }
  143. /**
  144. * Web CT question importer.
  145. *
  146. * @copyright 2004 ASP Consulting http://www.asp-consulting.net
  147. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  148. */
  149. class qformat_webct extends qformat_default {
  150. function provide_import() {
  151. return true;
  152. }
  153. protected function readquestions($lines) {
  154. $webctnumberregex =
  155. '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?';
  156. $questions = array();
  157. $errors = array();
  158. $warnings = array();
  159. $webct_options = array();
  160. $ignore_rest_of_question = FALSE;
  161. $nLineCounter = 0;
  162. $nQuestionStartLine = 0;
  163. $bIsHTMLText = FALSE;
  164. $lines[] = ":EOF:"; // for an easiest processing of the last line
  165. // $question = $this->defaultquestion();
  166. foreach ($lines as $line) {
  167. $nLineCounter++;
  168. $line = iconv("Windows-1252","UTF-8",$line);
  169. // Processing multiples lines strings
  170. if (isset($questiontext) and is_string($questiontext)) {
  171. if (preg_match("~^:~",$line)) {
  172. $question->questiontext = trim($questiontext);
  173. unset($questiontext);
  174. }
  175. else {
  176. $questiontext .= str_replace('\:', ':', $line);
  177. continue;
  178. }
  179. }
  180. if (isset($answertext) and is_string($answertext)) {
  181. if (preg_match("~^:~",$line)) {
  182. $answertext = trim($answertext);
  183. $question->answer[$currentchoice] = $answertext;
  184. $question->subanswers[$currentchoice] = $answertext;
  185. unset($answertext);
  186. }
  187. else {
  188. $answertext .= str_replace('\:', ':', $line);
  189. continue;
  190. }
  191. }
  192. if (isset($responsetext) and is_string($responsetext)) {
  193. if (preg_match("~^:~",$line)) {
  194. $question->subquestions[$currentchoice] = trim($responsetext);
  195. unset($responsetext);
  196. }
  197. else {
  198. $responsetext .= str_replace('\:', ':', $line);
  199. continue;
  200. }
  201. }
  202. if (isset($feedbacktext) and is_string($feedbacktext)) {
  203. if (preg_match("~^:~",$line)) {
  204. $question->feedback[$currentchoice] = trim($feedbacktext);
  205. unset($feedbacktext);
  206. }
  207. else {
  208. $feedbacktext .= str_replace('\:', ':', $line);
  209. continue;
  210. }
  211. }
  212. if (isset($generalfeedbacktext) and is_string($generalfeedbacktext)) {
  213. if (preg_match("~^:~",$line)) {
  214. $question->tempgeneralfeedback= trim($generalfeedbacktext);
  215. unset($generalfeedbacktext);
  216. }
  217. else {
  218. $generalfeedbacktext .= str_replace('\:', ':', $line);
  219. continue;
  220. }
  221. }
  222. $line = trim($line);
  223. if (preg_match("~^:(TYPE|EOF):~i",$line)) {
  224. // New Question or End of File
  225. if (isset($question)) { // if previous question exists, complete, check and save it
  226. // Setup default value of missing fields
  227. if (!isset($question->name)) {
  228. $question->name = $this->create_default_question_name(
  229. $question->questiontext, get_string('questionname', 'question'));
  230. }
  231. if (!isset($question->defaultmark)) {
  232. $question->defaultmark = 1;
  233. }
  234. if (!isset($question->image)) {
  235. $question->image = "";
  236. }
  237. // Perform sanity checks
  238. $QuestionOK = TRUE;
  239. if (strlen($question->questiontext) == 0) {
  240. $warnings[] = get_string("missingquestion", "qformat_webct", $nQuestionStartLine);
  241. $QuestionOK = FALSE;
  242. }
  243. if (sizeof($question->answer) < 1) { // a question must have at least 1 answer
  244. $errors[] = get_string("missinganswer", "qformat_webct", $nQuestionStartLine);
  245. $QuestionOK = FALSE;
  246. }
  247. else {
  248. // Create empty feedback array
  249. foreach ($question->answer as $key => $dataanswer) {
  250. if(!isset( $question->feedback[$key])){
  251. $question->feedback[$key] = '';
  252. }
  253. }
  254. // this tempgeneralfeedback allows the code to work with versions from 1.6 to 1.9
  255. // when question->generalfeedback is undefined, the webct feedback is added to each answer feedback
  256. if (isset($question->tempgeneralfeedback)){
  257. if (isset($question->generalfeedback)) {
  258. $question->generalfeedback = $question->tempgeneralfeedback;
  259. } else {
  260. foreach ($question->answer as $key => $dataanswer) {
  261. if ($question->tempgeneralfeedback !=''){
  262. $question->feedback[$key] = $question->tempgeneralfeedback.'<br/>'.$question->feedback[$key];
  263. }
  264. }
  265. }
  266. unset($question->tempgeneralfeedback);
  267. }
  268. $maxfraction = -1;
  269. $totalfraction = 0;
  270. foreach($question->fraction as $fraction) {
  271. if ($fraction > 0) {
  272. $totalfraction += $fraction;
  273. }
  274. if ($fraction > $maxfraction) {
  275. $maxfraction = $fraction;
  276. }
  277. }
  278. switch ($question->qtype) {
  279. case 'shortanswer':
  280. if ($maxfraction != 1) {
  281. $maxfraction = $maxfraction * 100;
  282. $errors[] = "'$question->name': ".get_string("wronggrade", "qformat_webct", $nLineCounter).' '.get_string("fractionsnomax", "question", $maxfraction);
  283. $QuestionOK = FALSE;
  284. }
  285. break;
  286. case 'multichoice':
  287. if ($question->single) {
  288. if ($maxfraction != 1) {
  289. $maxfraction = $maxfraction * 100;
  290. $errors[] = "'$question->name': ".get_string("wronggrade", "qformat_webct", $nLineCounter).' '.get_string("fractionsnomax", "question", $maxfraction);
  291. $QuestionOK = FALSE;
  292. }
  293. } else {
  294. $totalfraction = round($totalfraction,2);
  295. if ($totalfraction != 1) {
  296. $totalfraction = $totalfraction * 100;
  297. $errors[] = "'$question->name': ".get_string("wronggrade", "qformat_webct", $nLineCounter).' '.get_string("fractionsaddwrong", "question", $totalfraction);
  298. $QuestionOK = FALSE;
  299. }
  300. }
  301. break;
  302. case 'calculated':
  303. foreach ($question->answers as $answer) {
  304. if ($formulaerror = qtype_calculated_find_formula_errors($answer)) {
  305. $warnings[] = "'$question->name': ". $formulaerror;
  306. $QuestionOK = FALSE;
  307. }
  308. }
  309. foreach ($question->dataset as $dataset) {
  310. $dataset->itemcount=count($dataset->datasetitem);
  311. }
  312. $question->import_process=TRUE ;
  313. unset($question->answer); //not used in calculated question
  314. break;
  315. case 'match':
  316. // MDL-10680:
  317. // switch subquestions and subanswers
  318. foreach ($question->subquestions as $id=>$subquestion) {
  319. $temp = $question->subquestions[$id];
  320. $question->subquestions[$id] = $question->subanswers[$id];
  321. $question->subanswers[$id] = $temp;
  322. }
  323. if (count($question->answer) < 3){
  324. // add a dummy missing question
  325. $question->name = 'Dummy question added '.$question->name ;
  326. $question->answer[] = 'dummy';
  327. $question->subanswers[] = 'dummy';
  328. $question->subquestions[] = 'dummy';
  329. $question->fraction[] = '0.0';
  330. $question->feedback[] = '';
  331. }
  332. break;
  333. default:
  334. // No problemo
  335. }
  336. }
  337. if ($QuestionOK) {
  338. // echo "<pre>"; print_r ($question);
  339. $questions[] = $question; // store it
  340. unset($question); // and prepare a new one
  341. $question = $this->defaultquestion();
  342. }
  343. }
  344. $nQuestionStartLine = $nLineCounter;
  345. }
  346. // Processing Question Header
  347. if (preg_match("~^:TYPE:MC:1(.*)~i",$line,$webct_options)) {
  348. // Multiple Choice Question with only one good answer
  349. $question = $this->defaultquestion();
  350. $question->feedback = array();
  351. $question->qtype = 'multichoice';
  352. $question->single = 1; // Only one answer is allowed
  353. $ignore_rest_of_question = FALSE;
  354. continue;
  355. }
  356. if (preg_match("~^:TYPE:MC:N(.*)~i",$line,$webct_options)) {
  357. // Multiple Choice Question with several good answers
  358. $question = $this->defaultquestion();
  359. $question->feedback = array();
  360. $question->qtype = 'multichoice';
  361. $question->single = 0; // Many answers allowed
  362. $ignore_rest_of_question = FALSE;
  363. continue;
  364. }
  365. if (preg_match("~^:TYPE:S~i",$line)) {
  366. // Short Answer Question
  367. $question = $this->defaultquestion();
  368. $question->feedback = array();
  369. $question->qtype = 'shortanswer';
  370. $question->usecase = 0; // Ignore case
  371. $ignore_rest_of_question = FALSE;
  372. continue;
  373. }
  374. if (preg_match("~^:TYPE:C~i",$line)) {
  375. // Calculated Question
  376. $question = $this->defaultquestion();
  377. $question->qtype = 'calculated';
  378. $question->answers = array(); // No problem as they go as :FORMULA: from webct
  379. $question->units = array();
  380. $question->dataset = array();
  381. // To make us pass the end-of-question sanity checks
  382. $question->answer = array('dummy');
  383. $question->fraction = array('1.0');
  384. $question->feedback = array();
  385. $currentchoice = -1;
  386. $ignore_rest_of_question = FALSE;
  387. continue;
  388. }
  389. if (preg_match("~^:TYPE:M~i",$line)) {
  390. // Match Question
  391. $question = $this->defaultquestion();
  392. $question->qtype = 'match';
  393. $question->feedback = array();
  394. $ignore_rest_of_question = FALSE; // match question processing is not debugged
  395. continue;
  396. }
  397. if (preg_match("~^:TYPE:P~i",$line)) {
  398. // Paragraph Question
  399. $warnings[] = get_string("paragraphquestion", "qformat_webct", $nLineCounter);
  400. unset($question);
  401. $ignore_rest_of_question = TRUE; // Question Type not handled by Moodle
  402. continue;
  403. }
  404. if (preg_match("~^:TYPE:~i",$line)) {
  405. // Unknow Question
  406. $warnings[] = get_string("unknowntype", "qformat_webct", $nLineCounter);
  407. unset($question);
  408. $ignore_rest_of_question = TRUE; // Question Type not handled by Moodle
  409. continue;
  410. }
  411. if ($ignore_rest_of_question) {
  412. continue;
  413. }
  414. if (preg_match("~^:TITLE:(.*)~i",$line,$webct_options)) {
  415. $name = trim($webct_options[1]);
  416. $question->name = $this->clean_question_name($name);
  417. continue;
  418. }
  419. if (preg_match("~^:IMAGE:(.*)~i",$line,$webct_options)) {
  420. $filename = trim($webct_options[1]);
  421. if (preg_match("~^http://~i",$filename)) {
  422. $question->image = $filename;
  423. }
  424. continue;
  425. }
  426. // Need to put the parsing of calculated items here to avoid ambitiuosness:
  427. // if question isn't defined yet there is nothing to do here (avoid notices)
  428. if (!isset($question)) {
  429. continue;
  430. }
  431. if (isset($question->qtype ) && 'calculated' == $question->qtype && preg_match(
  432. "~^:([[:lower:]].*|::.*)-(MIN|MAX|DEC|VAL([0-9]+))::?:?($webctnumberregex)~", $line, $webct_options)) {
  433. $datasetname = preg_replace('/^::/', '', $webct_options[1]);
  434. $datasetvalue = qformat_webct_convert_formula($webct_options[4]);
  435. switch ($webct_options[2]) {
  436. case 'MIN':
  437. $question->dataset[$datasetname]->min = $datasetvalue;
  438. break;
  439. case 'MAX':
  440. $question->dataset[$datasetname]->max = $datasetvalue;
  441. break;
  442. case 'DEC':
  443. $datasetvalue = floor($datasetvalue); // int only!
  444. $question->dataset[$datasetname]->length = max(0, $datasetvalue);
  445. break;
  446. default:
  447. // The VAL case:
  448. $question->dataset[$datasetname]->datasetitem[$webct_options[3]] = new stdClass();
  449. $question->dataset[$datasetname]->datasetitem[$webct_options[3]]->itemnumber = $webct_options[3];
  450. $question->dataset[$datasetname]->datasetitem[$webct_options[3]]->value = $datasetvalue;
  451. break;
  452. }
  453. continue;
  454. }
  455. $bIsHTMLText = preg_match("~:H$~i",$line); // True if next lines are coded in HTML
  456. if (preg_match("~^:QUESTION~i",$line)) {
  457. $questiontext=""; // Start gathering next lines
  458. continue;
  459. }
  460. if (preg_match("~^:ANSWER([0-9]+):([^:]+):([0-9\.\-]+):(.*)~i",$line,$webct_options)) { // Shortanswer.
  461. $currentchoice=$webct_options[1];
  462. $answertext=$webct_options[2]; // Start gathering next lines
  463. $question->fraction[$currentchoice]=($webct_options[3]/100);
  464. continue;
  465. }
  466. if (preg_match("~^:ANSWER([0-9]+):([0-9\.\-]+)~i",$line,$webct_options)) {
  467. $answertext=""; // Start gathering next lines
  468. $currentchoice=$webct_options[1];
  469. $question->fraction[$currentchoice]=($webct_options[2]/100);
  470. continue;
  471. }
  472. if (preg_match('~^:FORMULA:(.*)~i', $line, $webct_options)) {
  473. // Answer for a calculated question
  474. ++$currentchoice;
  475. $question->answers[$currentchoice] =
  476. qformat_webct_convert_formula($webct_options[1]);
  477. // Default settings:
  478. $question->fraction[$currentchoice] = 1.0;
  479. $question->tolerance[$currentchoice] = 0.0;
  480. $question->tolerancetype[$currentchoice] = 2; // nominal (units in webct)
  481. $question->feedback[$currentchoice] = '';
  482. $question->correctanswerlength[$currentchoice] = 4;
  483. $datasetnames = question_bank::get_qtype('calculated')->
  484. find_dataset_names($webct_options[1]);
  485. foreach ($datasetnames as $datasetname) {
  486. $question->dataset[$datasetname] = new stdClass();
  487. $question->dataset[$datasetname]->datasetitem = array();
  488. $question->dataset[$datasetname]->name = $datasetname ;
  489. $question->dataset[$datasetname]->distribution = 'uniform';
  490. $question->dataset[$datasetname]->status ='private';
  491. }
  492. continue;
  493. }
  494. if (preg_match("~^:L([0-9]+)~i",$line,$webct_options)) {
  495. $answertext=""; // Start gathering next lines
  496. $currentchoice=$webct_options[1];
  497. $question->fraction[$currentchoice]=1;
  498. continue;
  499. }
  500. if (preg_match("~^:R([0-9]+)~i",$line,$webct_options)) {
  501. $responsetext=""; // Start gathering next lines
  502. $currentchoice=$webct_options[1];
  503. continue;
  504. }
  505. if (preg_match("~^:REASON([0-9]+):?~i",$line,$webct_options)) {
  506. $feedbacktext=""; // Start gathering next lines
  507. $currentchoice=$webct_options[1];
  508. continue;
  509. }
  510. if (preg_match("~^:FEEDBACK([0-9]+):?~i",$line,$webct_options)) {
  511. $generalfeedbacktext=""; // Start gathering next lines
  512. $currentchoice=$webct_options[1];
  513. continue;
  514. }
  515. if (preg_match('~^:FEEDBACK:(.*)~i',$line,$webct_options)) {
  516. $generalfeedbacktext=""; // Start gathering next lines
  517. continue;
  518. }
  519. if (preg_match('~^:LAYOUT:(.*)~i',$line,$webct_options)) {
  520. // ignore since layout in question_multichoice is no more used in moodle
  521. // $webct_options[1] contains either vertical or horizontal ;
  522. continue;
  523. }
  524. if (isset($question->qtype ) && 'calculated' == $question->qtype && preg_match('~^:ANS-DEC:([1-9][0-9]*)~i', $line, $webct_options)) {
  525. // We can but hope that this always appear before the ANSTYPE property
  526. $question->correctanswerlength[$currentchoice] = $webct_options[1];
  527. continue;
  528. }
  529. if (isset($question->qtype )&& 'calculated' == $question->qtype && preg_match("~^:TOL:($webctnumberregex)~i", $line, $webct_options)) {
  530. // We can but hope that this always appear before the TOL property
  531. $question->tolerance[$currentchoice] =
  532. qformat_webct_convert_formula($webct_options[1]);
  533. continue;
  534. }
  535. if (isset($question->qtype )&& 'calculated' == $question->qtype && preg_match('~^:TOLTYPE:percent~i', $line)) {
  536. // Percentage case is handled as relative in Moodle:
  537. $question->tolerance[$currentchoice] /= 100;
  538. $question->tolerancetype[$currentchoice] = 1; // Relative
  539. continue;
  540. }
  541. if (preg_match('~^:UNITS:(.+)~i', $line, $webct_options)
  542. and $webctunits = trim($webct_options[1])) {
  543. // This is a guess - I really do not know how different webct units are separated...
  544. $webctunits = explode(':', $webctunits);
  545. $unitrec->multiplier = 1.0; // Webct does not seem to support this
  546. foreach ($webctunits as $webctunit) {
  547. $unitrec->unit = trim($webctunit);
  548. $question->units[] = $unitrec;
  549. }
  550. continue;
  551. }
  552. if (!empty($question->units) && preg_match('~^:UNITREQ:(.*)~i', $line, $webct_options)
  553. && !$webct_options[1]) {
  554. // There are units but units are not required so add the no unit alternative
  555. // We can but hope that the UNITS property always appear before this property
  556. $unitrec->unit = '';
  557. $unitrec->multiplier = 1.0;
  558. $question->units[] = $unitrec;
  559. continue;
  560. }
  561. if (!empty($question->units) && preg_match('~^:UNITCASE:~i', $line)) {
  562. // This could be important but I was not able to figure out how
  563. // it works so I ignore it for now
  564. continue;
  565. }
  566. if (isset($question->qtype )&& 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:dec~i', $line)) {
  567. $question->correctanswerformat[$currentchoice]='1';
  568. continue;
  569. }
  570. if (isset($question->qtype )&& 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:sig~i', $line)) {
  571. $question->correctanswerformat[$currentchoice]='2';
  572. continue;
  573. }
  574. }
  575. if (sizeof($errors) > 0) {
  576. echo "<p>".get_string("errorsdetected", "qformat_webct", sizeof($errors))."</p><ul>";
  577. foreach($errors as $error) {
  578. echo "<li>$error</li>";
  579. }
  580. echo "</ul>";
  581. unset($questions); // no questions imported
  582. }
  583. if (sizeof($warnings) > 0) {
  584. echo "<p>".get_string("warningsdetected", "qformat_webct", sizeof($warnings))."</p><ul>";
  585. foreach($warnings as $warning) {
  586. echo "<li>$warning</li>";
  587. }
  588. echo "</ul>";
  589. }
  590. return $questions;
  591. }
  592. }
  593. ?>