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, $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 . " ";
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 $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);
277 if (!empty($result->notice
)) {
278 notify($result->notice
);
279 $this->deletedatabase($filename);
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);
289 function importpostprocess() {
293 function deletedatabase($filename) {
294 if (! $this->fulldelete($filename)) {
295 echo "<br />Error: Could not delete: $filename";
301 function getquestions($filename, $category, $mdapath="", $hostname="") {
302 if (($category == "allcategories") or ($category == "")) {
303 $sql = "SELECT * FROM TBQuestions";
305 $sql = "SELECT * FROM TBQuestions where module = '".$category."'";
307 if (PHP_OS
== "WINNT") {
308 $ldb =& $this->connect_win($filename);
309 $qset = $ldb->Execute("$sql");
311 $records = $qset->GetAssoc(true);
313 $this->err("There were no records in the database.",$dsn);
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];
329 $this->err("There were no records in the database.",$dsn);
333 // xml test and connect
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");
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);
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];
365 function query_linux($sql, $mdbpath, $mdapath, $hostname) {
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
);
388 // echo("Successful XML parse. ");
389 // prepare the array for use in the pull-down
390 /* echo "<br />count of rows is ". count ($result);
392 $qResult = HtmlSpecialChars($qResult);
396 xml_parser_free($xml_parser);
397 // $sResult = HtmlSpecialChars($qResult);
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");
413 $this->err("The system database System.mda cannot be found. Check that you've uploaded it to the course.",$dsn);
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);
427 function err($message, $dsn) {
428 echo "<font color=\"#990000\">";
429 echo "<p>Error: $message</p>";
430 echo "<p>ODBC File DSN: $dsn<br />";
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)) {
445 if (!unlink($fullfile)) {
452 if (! rmdir($location)) {
457 if (!unlink($location)) {
465 function findfile($filename) {
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;
477 function getcoursedirs() {
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");
483 foreach ($courses as $course) {
484 $dir = $CFG->dataroot
. "/" . $course->id
;
494 //Handler for starting elements
495 function quiz_xmlstart($parser, $name, $attribs) {
496 global $result,$row, $col, $incolumn;
497 $name = strtolower($name);
510 //handler for the end of elements
511 function quiz_xmlend($parser, $name) {
512 global $result, $row, $col, $incolumn;
513 $name = strtolower($name);
528 //handler for character data
529 function quiz_xmldata($parser, $data) {
530 global $result, $row, $col, $incolumn;
532 $result[$row][$col] = $result[$row][$col] . $data;