Merge commit 'catalyst/MOODLE_19_STABLE' into mdl19-linuxchix
[moodle-linuxchix.git] / question / format / coursetestmanager / format.php
blobf5676bb2e9f9182f47097038582dca4078dd8113
1 <?php // $Id$
2 ////////////////////////////////////////////////////////////////////
3 /// Class for importing course test manager questions. //
4 /// //
5 /// //
6 ////////////////////////////////////////////////////////////////////
8 // Based on format.php, included by ../../import.php
9 /**
10 * @package questionbank
11 * @subpackage importexport
14 require_once($CFG->dirroot.'/lib/uploadlib.php');
16 class qformat_coursetestmanager extends qformat_default {
18 function provide_import() {
19 return true;
22 function importpreprocess($category) {
23 $this->category = $category; // Important
24 return true;
27 function importprocess($filename) {
28 global $CFG, $USER, $strimportquestions,$form,$question_category,$category,$COURSE,
29 $hostname, $mdapath, $mdbpath;
30 if ((PHP_OS == "Linux") and isset($hostname)) {
31 $hostname = trim($hostname);
32 // test the ODBC socket server connection
33 // if failure, unset hostname and set hostname_access_error
34 $question_categories = $this->getquestioncategories($mdbpath, $mdapath, $hostname);
35 if (!$question_categories) {
36 $hostname_access_error = $hostname . " ";
37 unset($hostname);
38 } else {
39 $hostname_access_error = 0;
43 if ((PHP_OS == "Linux") and !isset($hostname)) {
44 // copy the file to a semi-permanent location
45 if (! $basedir = make_upload_directory("$COURSE->id")) {
46 error("The site administrator needs to fix the file permissions for the data directory");
48 if (!isset($hostname_access_error)) {
49 $bname=basename($filename);
50 $cleanfilename = clean_filename($bname);
51 if ($cleanfilename) {
52 $newfile = "$basedir/$cleanfilename";
53 if (move_uploaded_file($filename, $newfile)) {
54 chmod($newfile, 0666);
55 clam_log_upload($newfile,$COURSE);
56 } else {
57 notify(get_string("uploadproblem", "", $filename));
60 $filename = $newfile;
62 print_heading_with_help($strimportquestions, "import", "quiz");
63 print_simple_box_start("center");
64 if ($hostname_access_error) { notify("couldn't connect to ODBC Socket Server on " . $hostname_access_error); }
65 echo "<form method=\"post\" action=\"import.php\">";
66 echo '<fieldset class="invisiblefieldset">';
67 echo "<table cellpadding=\"5\">";
69 echo "<tr><td align=\"right\">";
70 echo "What is the hostname or IP address of the ODBC Socket Server:</td><td>";
71 echo " <input name=\"hostname\" type=\"text\" size=\"50\" value=\"".stripslashes($hostname_access_error)."\" />";
72 echo " <input name=\"filename\" type=\"hidden\" value=\"".$filename."\" />";
73 echo " <input name=\"category\" type=\"hidden\" value=\"".$category->id."\" />";
74 echo " <input name=\"format\" type=\"hidden\" value=\"".$form->format."\" />";
75 echo "</td><td>&nbsp;</td></tr>";
76 echo "<tr><td align=\"right\">";
77 echo "What is the location of the database (.mdb file) on the Socket Server:</td><td>";
78 echo " <input name=\"mdbpath\" type=\"text\" size=\"50\" value=\"".stripslashes($mdbpath)."\" />";
79 echo "</td><td>&nbsp;</td></tr>";
80 echo "<tr><td align=\"right\">";
81 echo "What is the location of the system database (System.mda file) on the Socket Server:</td><td>";
82 echo " <input name=\"mdapath\" type=\"text\" size=\"50\" value=\"".stripslashes($mdapath)."\" />";
83 echo "</td><td>&nbsp;</td></tr>";
84 echo "<tr><td>&nbsp;</td><td>";
85 echo " <input type=\"submit\" name=\"save\" value=\"Connect to Server\" />";
86 echo "</td></tr>";
87 echo "</table>";
88 echo '</fieldset>';
89 echo "</form>";
90 print_simple_box_end();
91 print_footer($COURSE);
92 exit;
95 // we get here if running windows or after connect to ODBC socket server on linux
97 // this generates the page to choose categories of questions to import
99 if (!isset($question_category)) {
101 if (PHP_OS == "WINNT") {
102 // copy the file to a semi-permanent location
103 if (! $basedir = make_upload_directory("$COURSE->id")) {
104 error("The site administrator needs to fix the file permissions for the data directory");
106 $bname=basename($filename);
107 $cleanfilename = clean_filename($bname);
108 if ($cleanfilename) {
109 $newfile = "$basedir/$cleanfilename";
110 if (move_uploaded_file($filename, $newfile)) {
111 chmod($newfile, 0666);
112 clam_log_upload($newfile,$COURSE);
113 } else {
114 notify(get_string("uploadproblem", "", $filename));
117 $filename = $newfile;
119 // end of file copy
121 // don't have to do this on linux, since it's alreay been done in the test above
122 if (PHP_OS == "WINNT") {
123 $question_categories = $this->getquestioncategories($filename);
125 // print the intermediary form
126 if (!$categories = question_category_options($COURSE->id, true)) {
127 error("No categories!");
129 print_heading_with_help($strimportquestions, "import", "quiz");
130 print_simple_box_start("center");
131 echo "<form method=\"post\" action=\"import.php\">";
132 echo '<fieldset class="invisiblefieldset">';
133 echo "<table cellpadding=\"5\">";
134 echo "<tr><td align=\"right\">";
135 echo "Choose a category of questions to import:</td><td>";
136 asort($question_categories);
137 choose_from_menu($question_categories, "question_category","All Categories","All Categories", "", "allcategories");
138 echo " <input name=\"filename\" type=\"hidden\" value=\"".$filename."\" />";
139 echo " <input name=\"category\" type=\"hidden\" value=\"".$category->id."\" />";
140 echo " <input name=\"format\" type=\"hidden\" value=\"".$form->format."\" />";
141 if (PHP_OS == "Linux") {
142 echo " <input name=\"hostname\" type=\"hidden\" value=\"".stripslashes(trim($hostname))."\" />";
143 echo " <input name=\"mdbpath\" type=\"hidden\" value=\"".stripslashes($mdbpath)."\" />";
144 echo " <input name=\"mdapath\" type=\"hidden\" value=\"".stripslashes($mdapath)."\" />";
146 echo "</td><td>&nbsp;</td>";
147 echo "</tr><tr><td>&nbsp;</td><td>";
148 echo " <input type=\"submit\" name=\"save\" value=\"Import Questions\" />";
149 echo "</td></tr>";
150 echo "</table>";
151 echo '</fieldset>';
152 echo "</form>";
153 print_simple_box_end();
154 print_footer($COURSE);
155 exit;
158 // this is the main import section
160 notify("Importing questions");
161 if (PHP_OS == "Linux") {
162 $hostname = trim($hostname);
163 $records = $this->getquestions($mdbpath,$question_category,$mdapath, $hostname);
164 } else {
165 $records = $this->getquestions($filename,$question_category);
167 foreach ($records as $qrec) {
168 $question = $this->defaultquestion();
169 if ($qrec[9] != "") {
170 $question->image = $qrec[9];
172 // 0 Selected
173 // 1 PracticeTestOK?
174 // 2 QuestionText
175 // 3 QuestionType
176 // 4 Option1Text
177 // 5 Option2Text
178 // 6 Option3Text
179 // 7 Option4Text
180 // 8 CorrectAnswer
181 // 9 Graphic
182 // 10 Module
183 // 11 ChapterNumber
184 // 12 PageNumber
185 $ref = "Answer can be found in chapter ". $qrec[11] . ", page " . $qrec[12] . ".";
186 switch ($qrec[3]) {
187 case 1:
188 $question->qtype = MULTICHOICE; // MULTICHOICE, SHORTANSWER, TRUEFALSE
189 // echo "<pre>";echo htmlspecialchars($qrec[2]); echo "</pre>";
190 $question->questiontext = addslashes(trim($qrec[2]));
191 // echo "<pre>";echo $question->questiontext; echo "</pre>";
192 $question->name = preg_replace("/<br />/", "", $question->questiontext);
193 $question->single = 1; // Only one answer is allowed -- used for multiple choicers
194 $fractionset = 0;
195 for ($i=4;$i<=7;$i++) {
196 if ($qrec[$i] != "") {
197 $question->answer[$i-3]=addslashes($qrec[$i]);
198 if ($qrec[8] == $i-3) { // if this is the index of CorrectAnswer
199 $question->fraction[$i-3] = 1;
200 $fractionset = 1;
201 } else {
202 $question->fraction[$i-3] = 0;
204 $question->feedback[$i-3] = (($qrec[8] == $i-3)?"Correct. ":"Incorrect. ") . $ref;
207 if ($fractionset == 0) {
208 $question->fraction[1] = 1;
210 break;
211 case 2: // TRUE FALSE
212 $question->qtype = TRUEFALSE;
213 $question->questiontext = addslashes(trim($qrec[2]));
214 $question->name = preg_replace("/<br />/", "", $question->questiontext);
215 // for TF, $question->answer should be 1 for true, 0 for false
216 if ($qrec[8] == "T") {
217 $question->answer =1;
218 } else {
219 $question->answer = 0;
221 // for TF, use $question->feedbacktrue and feedbackfalse
222 $question->feedbacktrue = (($qrec[8] =="T")?"Correct. ":"Incorrect. ") . $ref;
223 $question->feedbackfalse = (($qrec[8] =="F")?"Correct. ":"Incorrect. ") . $ref;
224 break;
225 case 3:
226 $question->qtype = SHORTANSWER;
227 $question->questiontext = addslashes(trim($qrec[2]));
228 // echo "<pre>";echo $question->questiontext; echo "</pre>";
229 $question->name = preg_replace("/<br />/", "", $question->questiontext);
230 $question->usecase=0; // Ignore case -- for SHORT ANSWER questions
231 $answers = explode("~", $qrec[8]);
232 $question->answer[0]=" ";
233 $question->fraction[0]=1;
234 for ($i=0;$i<count($answers);$i++) {
235 $question->answer[$i] = addslashes(trim($answers[$i]));
236 $question->feedback[$i] = $ref;
237 $question->fraction[$i] = 1; // 1 for 100%, 0 for none or somewhere in between
239 break;
240 case 4:
241 $question = 0;
242 notify("Cannot use essay questions - skipping question ". $qrec[2] . " " . $ref);
243 break;
244 default:
245 $question = 0;
246 notify("Misformatted Record. Question Skipped.");
247 break;
249 if ($question) {
250 $questions[] = $question;
253 $count = 0;
254 // process all the questions
255 if (PHP_OS == "WINNT") {
256 $filename = str_replace("\\\\","\\",$filename);
257 $filename = str_replace("/","\\",$filename);
259 foreach ($questions as $question) { // Process and store each question
260 $count++;
261 echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
262 $question->category = $this->category->id;
263 $question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
264 $question->createdby = $USER->id;
265 $question->timecreated = time();
266 if (!$question->id = insert_record("question", $question)) {
267 error("Could not insert new question!");
269 $this->questionids[] = $question->id;
270 // Now to save all the answers and type-specific options
271 $result = save_question_options($question);
272 if (!empty($result->error)) {
273 notify($result->error);
274 $this->deletedatabase($filename);
275 return false;
277 if (!empty($result->notice)) {
278 notify($result->notice);
279 $this->deletedatabase($filename);
280 return true;
282 // Give the question a unique version stamp determined by question_hash()
283 set_field('question', 'version', question_hash($question), 'id', $question->id);
285 $this->deletedatabase($filename);
286 return true;
289 function importpostprocess() {
290 return true;
293 function deletedatabase($filename) {
294 if (! $this->fulldelete($filename)) {
295 echo "<br />Error: Could not delete: $filename";
296 return false;
298 return true;
301 function getquestions($filename, $category, $mdapath="", $hostname="") {
302 if (($category == "allcategories") or ($category == "")) {
303 $sql = "SELECT * FROM TBQuestions";
304 } else {
305 $sql = "SELECT * FROM TBQuestions where module = '".$category."'";
307 if (PHP_OS == "WINNT") {
308 $ldb =& $this->connect_win($filename);
309 $qset = $ldb->Execute("$sql");
310 if ( !$qset->EOF ) {
311 $records = $qset->GetAssoc(true);
312 } else {
313 $this->err("There were no records in the database.",$dsn);
314 $ldb->Close();
315 return false;
317 $ldb->Close();
318 } else { // if PHP_OS == WINNT
319 // we have a linux installation
320 $result = $this->query_linux($sql,$filename, $mdapath,$hostname);
321 if ( count($result) > 0 ) {
322 // get rid of the ID field in the first column.
323 for($i=0;$i<count($result);$i++) {
324 foreach (array_keys($result[$i]) as $j) {
325 $records[$i][$j-1] = $result[$i][$j];
328 } else {
329 $this->err("There were no records in the database.",$dsn);
330 $ldb->Close();
331 return false;
333 // xml test and connect
334 } // PHP_OS TEST
335 return $records;
338 function getquestioncategories($filename, $mdapath="", $hostname="") {
339 global $CFG, $result;
340 $sql = "SELECT Distinct module FROM TBQuestions";
341 if (PHP_OS == "WINNT") {
342 $ldb =& $this->connect_win($filename);
343 $qset = $ldb->Execute("$sql");
344 if ( !$qset->EOF ) {
345 $records = $qset->GetArray(true);
346 foreach ($records as $record) {
347 $categories[$record[0]] = $record[0];
349 } else { // if recordcount
350 $this->err("There were no records in the database.",$dsn);
351 $ldb->Close();
352 return false;
354 $ldb->Close();
355 } else { // if PHP_OS == WINNT
356 // we have a linux installation
357 $result = $this->query_linux($sql, $filename, $mdapath, $hostname);
358 for($i=0;$i<count($result);$i++) {
359 $categories[$result[$i][0]] = $result[$i][0];
361 } // PHP_OS TEST
362 return $categories;
365 function query_linux($sql, $mdbpath, $mdapath, $hostname) {
366 global $result;
367 include_once("odbcsocketserver.class.php");
368 // set up socket server object to connect to remote host
369 $oTest = new ODBCSocketServer;
370 //Set the Hostname, port, and connection string
371 $oTest->sHostName = $hostname;
372 $oTest->nPort = 9628;
373 // $oTest->sConnectionString="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=C:\CTM\System.mda;DBQ=C:\CTM\of2K3\ctm.mdb;UID=Assess;PWD=VBMango;";
374 $oTest->sConnectionString="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".
375 $mdapath.";DBQ=".$mdbpath.";UID=Assess;PWD=VBMango;";
376 // send and receive XML communication
377 $qResult = $oTest->ExecSQL($sql);
378 // set up XML parser to read the results
379 $xml_parser = xml_parser_create("US-ASCII");
380 xml_set_element_handler($xml_parser, "quiz_xmlstart", "quiz_xmlend");
381 xml_set_character_data_handler($xml_parser, "quiz_xmldata");
382 // parse the XML and get back the result set array
383 if (!xml_parse($xml_parser, $qResult)) {
384 $this->err("XML error: ".xml_error_string(xml_get_error_code($xml_parser))
385 ." at line ".xml_get_current_line_number($xml_parser),$oTest->sConnectionString);
386 return false;
387 } else {
388 // echo("Successful XML parse. ");
389 // prepare the array for use in the pull-down
390 /* echo "<br />count of rows is ". count ($result);
391 echo "<pre>\n";
392 $qResult = HtmlSpecialChars($qResult);
393 echo $qResult;
394 echo "\n</pre>";
396 xml_parser_free($xml_parser);
397 // $sResult = HtmlSpecialChars($qResult);
398 //echo("<pre>");
399 // echo($sResult);
400 // echo("</pre>");
402 return $result;
406 function connect_win($filename) {
407 global $CFG, $systemdb;
408 // first, verify the location of System.mda
409 if (!isset($systemdb)) {
410 $systemdb=$this->findfile("System.mda");
412 if (! $systemdb) {
413 $this->err("The system database System.mda cannot be found. Check that you've uploaded it to the course.",$dsn);
414 die;
417 $ldb = &ADONewConnection('access');
418 $dsn="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".$systemdb.";DBQ=".$filename.";UID=Assess;PWD=VBMango;";
419 $dbconnected = $ldb->Connect($dsn);
420 if (! $dbconnected) {
421 $this->err("Moodle could not connect to the database.",$dsn);
422 die;
424 return $ldb;
427 function err($message, $dsn) {
428 echo "<font color=\"#990000\">";
429 echo "<p>Error: $message</p>";
430 echo "<p>ODBC File DSN: $dsn<br />";
431 echo "</font>";
434 function fulldelete($location) {
435 if (is_dir($location)) {
436 $currdir = opendir($location);
437 while (false !== ($file = readdir($currdir))) {
438 if ($file <> ".." && $file <> ".") {
439 $fullfile = $location."/".$file;
440 if (is_dir($fullfile)) {
441 if (!fulldelete($fullfile)) {
442 return false;
444 } else {
445 if (!unlink($fullfile)) {
446 return false;
451 closedir($currdir);
452 if (! rmdir($location)) {
453 return false;
456 } else {
457 if (!unlink($location)) {
458 return false;
461 return true;
465 function findfile($filename) {
466 global $CFG;
467 $dirs = $this->getcoursedirs();
468 $dirs[] = $CFG->dirroot."\mod\quiz\format";
469 foreach ($dirs as $dir) {
470 $file = $dir . "\System.mda";
471 // look for System.mda
472 if (is_file($file)) return $file;
474 return false;
477 function getcoursedirs() {
478 global $CFG;
479 // for every course in the system, find the root of the data directory
480 $courses = get_records_sql("select distinct id,fullname from ".$CFG->prefix."course");
481 $dirs = array();
482 if ($courses) {
483 foreach ($courses as $course) {
484 $dir = $CFG->dataroot . "/" . $course->id;
485 if (is_dir($dir)) {
486 $dirs[] = $dir;
490 return $dirs;
492 } // END OF CLASS
494 //Handler for starting elements
495 function quiz_xmlstart($parser, $name, $attribs) {
496 global $result,$row, $col, $incolumn;
497 $name = strtolower($name);
498 switch ($name) {
499 case "row":
500 $col=0;break;
501 case "column":
502 $incolumn = 1;break;
503 case "error":
504 break;
505 case "result":
506 $row = 0; break;
507 } // switch
510 //handler for the end of elements
511 function quiz_xmlend($parser, $name) {
512 global $result, $row, $col, $incolumn;
513 $name = strtolower($name);
514 switch ($name) {
515 case "row":
516 $row++;break;
517 case "column":
518 $incolumn = 0;
519 $col++;
520 break;
521 case "error":
522 break;
523 case "result":
524 break;
525 } // switch
526 } // function
528 //handler for character data
529 function quiz_xmldata($parser, $data) {
530 global $result, $row, $col, $incolumn;
531 if ($incolumn) {
532 $result[$row][$col] = $result[$row][$col] . $data;