MDL-69798 XML question export: excape special chars in idnumbers
authorTim Hunt <T.J.Hunt@open.ac.uk>
Thu, 1 Oct 2020 16:01:50 +0000 (17:01 +0100)
committerTim Hunt <T.J.Hunt@open.ac.uk>
Thu, 1 Oct 2020 16:10:28 +0000 (17:10 +0100)
question/format/xml/format.php
question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml [new file with mode: 0644]
question/format/xml/tests/qformat_xml_import_export_test.php

index b2b71ff..0e63bdf 100644 (file)
@@ -1196,6 +1196,8 @@ class qformat_xml extends qformat_default {
         // Check question type.
         $questiontype = $this->get_qtype($question->qtype);
 
         // Check question type.
         $questiontype = $this->get_qtype($question->qtype);
 
+        $idnumber = htmlspecialchars($question->idnumber);
+
         // Categories are a special case.
         if ($question->qtype == 'category') {
             $categorypath = $this->writetext($question->category);
         // Categories are a special case.
         if ($question->qtype == 'category') {
             $categorypath = $this->writetext($question->category);
@@ -1208,7 +1210,7 @@ class qformat_xml extends qformat_default {
             $expout .= "    <info {$infoformat}>\n";
             $expout .= "      {$categoryinfo}";
             $expout .= "    </info>\n";
             $expout .= "    <info {$infoformat}>\n";
             $expout .= "      {$categoryinfo}";
             $expout .= "    </info>\n";
-            $expout .= "    <idnumber>{$question->idnumber}</idnumber>\n";
+            $expout .= "    <idnumber>{$idnumber}</idnumber>\n";
             $expout .= "  </question>\n";
             return $expout;
         }
             $expout .= "  </question>\n";
             return $expout;
         }
@@ -1232,7 +1234,7 @@ class qformat_xml extends qformat_default {
         }
         $expout .= "    <penalty>{$question->penalty}</penalty>\n";
         $expout .= "    <hidden>{$question->hidden}</hidden>\n";
         }
         $expout .= "    <penalty>{$question->penalty}</penalty>\n";
         $expout .= "    <hidden>{$question->hidden}</hidden>\n";
-        $expout .= "    <idnumber>{$question->idnumber}</idnumber>\n";
+        $expout .= "    <idnumber>{$idnumber}</idnumber>\n";
 
         // The rest of the output depends on question type.
         switch($question->qtype) {
 
         // The rest of the output depends on question type.
         switch($question->qtype) {
diff --git a/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml b/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
new file mode 100644 (file)
index 0000000..cc1d376
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<quiz>
+<!-- question: 0  -->
+  <question type="category">
+    <category>
+      <text>$course$/Alpha</text>
+    </category>
+    <info format="moodle_auto_format">
+      <text>This is Alpha category for test</text>
+    </info>
+    <idnumber>The inequalities &lt; &amp; &gt;</idnumber>
+  </question>
+
+<!-- question: 91  -->
+  <question type="truefalse">
+    <name>
+      <text>Alpha Question</text>
+    </name>
+    <questiontext format="html">
+      <text><![CDATA[<p>Testing Alpha Question</p>]]></text>
+    </questiontext>
+    <generalfeedback format="html">
+      <text></text>
+    </generalfeedback>
+    <defaultgrade>1.0000000</defaultgrade>
+    <penalty>1.0000000</penalty>
+    <hidden>0</hidden>
+    <idnumber>T &amp; F</idnumber>
+    <answer fraction="100" format="moodle_auto_format">
+      <text>true</text>
+      <feedback format="html">
+        <text></text>
+      </feedback>
+    </answer>
+    <answer fraction="0" format="moodle_auto_format">
+      <text>false</text>
+      <feedback format="html">
+        <text></text>
+      </feedback>
+    </answer>
+  </question>
+
+</quiz>
index 4926bea..ebd9fcd 100644 (file)
@@ -426,6 +426,44 @@ class qformat_xml_import_export_test extends advanced_testcase {
         $this->assert_same_xml($expectedxml, $qformat->exportprocess());
     }
 
         $this->assert_same_xml($expectedxml, $qformat->exportprocess());
     }
 
+    /**
+     * Simple check for exporting a category.
+     */
+    public function test_export_category_with_special_chars() {
+        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
+        $this->resetAfterTest(true);
+        $course = $this->getDataGenerator()->create_course();
+        $this->setAdminUser();
+        // Note while this loads $qformat with all the 'right' data from the xml file,
+        // the call to setCategory, followed by exportprocess will actually only export data
+        // from the database (created by the generator).
+        $qformat = $this->create_qformat('export_category.xml', $course);
+
+        $category = $generator->create_question_category([
+                'name' => 'Alpha',
+                'contextid' => '2',
+                'info' => 'This is Alpha category for test',
+                'infoformat' => '0',
+                'idnumber' => 'The inequalities < & >',
+                'stamp' => make_unique_id_code(),
+                'parent' => '0',
+                'sortorder' => '999']);
+        $generator->create_question('truefalse', null, [
+                'category' => $category->id,
+                'name' => 'Alpha Question',
+                'questiontext' => ['format' => '1', 'text' => '<p>Testing Alpha Question</p>'],
+                'generalfeedback' => ['format' => '1', 'text' => ''],
+                'idnumber' => 'T & F',
+                'correctanswer' => '1',
+                'feedbacktrue' => ['format' => '1', 'text' => ''],
+                'feedbackfalse' => ['format' => '1', 'text' => ''],
+                'penalty' => '1']);
+        $qformat->setCategory($category);
+
+        $expectedxml = file_get_contents(__DIR__ . '/fixtures/html_chars_in_idnumbers.xml');
+        $this->assert_same_xml($expectedxml, $qformat->exportprocess());
+    }
+
     /**
      * Test that bad multianswer questions are not imported.
      */
     /**
      * Test that bad multianswer questions are not imported.
      */