2 ////////////////////////////////////////////////////////////////////
3 /// Class for importing course test manager questions. //
6 ////////////////////////////////////////////////////////////////////
8 // Based on format.php, included by ../../import.php
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() {
22 function importpreprocess($category) {
23 $this->category
= $category; // Important
27 function importprocess($filename) {
28 global $CFG,$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 . " ";
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);
52 $newfile = "$basedir/$cleanfilename";
53 if (move_uploaded_file($filename, $newfile)) {
54 chmod($newfile, 0666);
55 clam_log_upload($newfile,$course);
57 notify(get_string("uploadproblem", "", $filename));
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> </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> </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> </td></tr>";
84 echo "<tr><td> </td><td>";
85 echo " <input type=\"submit\" name=\"save\" value=\"Connect to Server\" />";
90 print_simple_box_end();
91 print_footer($course);
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);
114 notify(get_string("uploadproblem", "", $filename));
117 $filename = $newfile;
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> </td>";
147 echo "</tr><tr><td> </td><td>";
148 echo " <input type=\"submit\" name=\"save\" value=\"Import Questions\" />";
153 print_simple_box_end();
154 print_footer($course);
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);
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];
185 $ref = "Answer can be found in chapter ". $qrec[11] . ", page " . $qrec[12] . ".";
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
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;
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;
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;
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;
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
242 notify("Cannot use essay questions - skipping question ". $qrec[2] . " " . $ref);
246 notify("Misformatted Record. Question Skipped.");
250 $questions[] = $question;
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
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 if (!$question->id
= insert_record("question", $question)) {
265 error("Could not insert new question!");
267 $this->questionids
[] = $question->id
;
268 // Now to save all the answers and type-specific options
269 $result = save_question_options($question);
270 if (!empty($result->error
)) {
271 notify($result->error
);
272 $this->deletedatabase($filename);
275 if (!empty($result->notice
)) {
276 notify($result->notice
);
277 $this->deletedatabase($filename);
280 // Give the question a unique version stamp determined by question_hash()
281 set_field('question', 'version', question_hash($question), 'id', $question->id
);
283 $this->deletedatabase($filename);
287 function importpostprocess() {
291 function deletedatabase($filename) {
292 if (! $this->fulldelete($filename)) {
293 echo "<br />Error: Could not delete: $filename";
299 function getquestions($filename, $category, $mdapath="", $hostname="") {
300 if (($category == "allcategories") or ($category == "")) {
301 $sql = "SELECT * FROM TBQuestions";
303 $sql = "SELECT * FROM TBQuestions where module = '".$category."'";
305 if (PHP_OS
== "WINNT") {
306 $ldb =& $this->connect_win($filename);
307 $qset = $ldb->Execute("$sql");
308 if ( $qset->RecordCount() > 0 ) {
309 $records = $qset->GetAssoc(true);
311 $this->err("There were no records in the database.",$dsn);
316 } else { // if PHP_OS == WINNT
317 // we have a linux installation
318 $result = $this->query_linux($sql,$filename, $mdapath,$hostname);
319 if ( count($result) > 0 ) {
320 // get rid of the ID field in the first column.
321 for($i=0;$i<count($result);$i++
) {
322 foreach (array_keys($result[$i]) as $j) {
323 $records[$i][$j-1] = $result[$i][$j];
327 $this->err("There were no records in the database.",$dsn);
331 // xml test and connect
336 function getquestioncategories($filename, $mdapath="", $hostname="") {
337 global $CFG, $result;
338 $sql = "SELECT Distinct module FROM TBQuestions";
339 if (PHP_OS
== "WINNT") {
340 $ldb =& $this->connect_win($filename);
341 $qset = $ldb->Execute("$sql");
342 if ( $qset->RecordCount() > 0 ) {
343 $records = $qset->GetArray(true);
344 foreach ($records as $record) {
345 $categories[$record[0]] = $record[0];
347 } else { // if recordcount
348 $this->err("There were no records in the database.",$dsn);
353 } else { // if PHP_OS == WINNT
354 // we have a linux installation
355 $result = $this->query_linux($sql, $filename, $mdapath, $hostname);
356 for($i=0;$i<count($result);$i++
) {
357 $categories[$result[$i][0]] = $result[$i][0];
363 function query_linux($sql, $mdbpath, $mdapath, $hostname) {
365 include_once("odbcsocketserver.class.php");
366 // set up socket server object to connect to remote host
367 $oTest = new ODBCSocketServer
;
368 //Set the Hostname, port, and connection string
369 $oTest->sHostName
= $hostname;
370 $oTest->nPort
= 9628;
371 // $oTest->sConnectionString="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=C:\CTM\System.mda;DBQ=C:\CTM\of2K3\ctm.mdb;UID=Assess;PWD=VBMango;";
372 $oTest->sConnectionString
="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".
373 $mdapath.";DBQ=".$mdbpath.";UID=Assess;PWD=VBMango;";
374 // send and receive XML communication
375 $qResult = $oTest->ExecSQL($sql);
376 // set up XML parser to read the results
377 $xml_parser = xml_parser_create("US-ASCII");
378 xml_set_element_handler($xml_parser, "quiz_xmlstart", "quiz_xmlend");
379 xml_set_character_data_handler($xml_parser, "quiz_xmldata");
380 // parse the XML and get back the result set array
381 if (!xml_parse($xml_parser, $qResult)) {
382 $this->err("XML error: ".xml_error_string(xml_get_error_code($xml_parser))
383 ." at line ".xml_get_current_line_number($xml_parser),$oTest->sConnectionString
);
386 // echo("Successful XML parse. ");
387 // prepare the array for use in the pull-down
388 /* echo "<br />count of rows is ". count ($result);
390 $qResult = HtmlSpecialChars($qResult);
394 xml_parser_free($xml_parser);
395 // $sResult = HtmlSpecialChars($qResult);
404 function connect_win($filename) {
405 global $CFG, $systemdb;
406 // first, verify the location of System.mda
407 if (!isset($systemdb)) {
408 $systemdb=$this->findfile("System.mda");
411 $this->err("The system database System.mda cannot be found. Check that you've uploaded it to the course.",$dsn);
415 $ldb = &ADONewConnection('access');
416 $dsn="DRIVER=Microsoft Access Driver (*.mdb);SystemDB=".$systemdb.";DBQ=".$filename.";UID=Assess;PWD=VBMango;";
417 $dbconnected = $ldb->Connect($dsn);
418 if (! $dbconnected) {
419 $this->err("Moodle could not connect to the database.",$dsn);
425 function err($message, $dsn) {
426 echo "<font color=\"#990000\">";
427 echo "<p>Error: $message</p>";
428 echo "<p>ODBC File DSN: $dsn<br />";
432 function fulldelete($location) {
433 if (is_dir($location)) {
434 $currdir = opendir($location);
435 while ($file = readdir($currdir)) {
436 if ($file <> ".." && $file <> ".") {
437 $fullfile = $location."/".$file;
438 if (is_dir($fullfile)) {
439 if (!fulldelete($fullfile)) {
443 if (!unlink($fullfile)) {
450 if (! rmdir($location)) {
455 if (!unlink($location)) {
463 function findfile($filename) {
465 $dirs = $this->getcoursedirs();
466 $dirs[] = $CFG->dirroot
."\mod\quiz\format";
467 foreach ($dirs as $dir) {
468 $file = $dir . "\System.mda";
469 // look for System.mda
470 if (is_file($file)) return $file;
475 function getcoursedirs() {
477 // for every course in the system, find the root of the data directory
478 $courses = get_records_sql("select distinct id,fullname from ".$CFG->prefix
."course");
481 foreach ($courses as $course) {
482 $dir = $CFG->dataroot
. "/" . $course->id
;
492 //Handler for starting elements
493 function quiz_xmlstart($parser, $name, $attribs) {
494 global $result,$row, $col, $incolumn;
495 $name = strtolower($name);
508 //handler for the end of elements
509 function quiz_xmlend($parser, $name) {
510 global $result, $row, $col, $incolumn;
511 $name = strtolower($name);
526 //handler for character data
527 function quiz_xmldata($parser, $data) {
528 global $result, $row, $col, $incolumn;
530 $result[$row][$col] = $result[$row][$col] . $data;