Updated text conversion to read and store safe xml strings.
authorDarko Miletic <dmiletic@moodlerooms.com>
Sun, 6 Nov 2011 17:39:00 +0000 (14:39 -0300)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 14 Nov 2011 20:25:08 +0000 (21:25 +0100)
14 files changed:
backup/cc/cc2moodle.php
backup/cc/entities.class.php
backup/cc/entity.forum.class.php
backup/cc/entity.label.class.php
backup/cc/entity.quiz.class.php
backup/cc/entity.resource.class.php
backup/cc/entity11.basiclti.class.php
backup/cc/entity11.forum.class.php
backup/cc/entity11.lti.class.php
backup/cc/entity11.quiz.class.php
backup/cc/entity11.resource.class.php
backup/cc/validator.php
backup/converter/imscc1/lib.php
backup/converter/imscc11/lib.php

index b3c1a2f..a13362b 100644 (file)
@@ -257,9 +257,9 @@ class cc2moodle {
                            '[#date_now#]',
                            '[#section_count#]');
 
-        $replace_values = array(htmlentities($course_title),
-                                htmlentities($course_short_name),
-                                htmlentities($course_description),
+        $replace_values = array(entities::safexml($course_title),
+                                entities::safexml($course_short_name),
+                                entities::safexml($course_description),
                                 time(),
                                 $section_count);
 
@@ -565,7 +565,7 @@ class cc2moodle {
             }
 
             $replace_values = array($instances[$i - 1]['instance'],
-                                    htmlentities($instances[$i - 1]['title']),
+                                    entities::safexml($instances[$i - 1]['title']),
                                     $user_info);
 
             $instance .= str_replace($find_tags, $replace_values, $sheet);
index a221d2c..e61fe1e 100644 (file)
 defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
 
 class entities {
+    /**
+     *
+     * Prepares convert for inclusion into XML
+     * @param string $value
+     */
+    public static function safexml($value) {
+        $result = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'),
+                                   ENT_NOQUOTES,
+                                   'UTF-8',
+                                   false);
+        return $result;
+    }
 
     protected function prepare_content($content) {
         $result = $content;
@@ -31,13 +43,12 @@ class entities {
             return '';
         }
         $encoding = null;
+        $xml_error = new libxml_errors_mgr();
         $dom = new DOMDocument();
-        try {
-            if ($dom->loadHTML($content)) {
-                $encoding = $dom->xmlEncoding;
-            }
-        } catch(DOMException $e) {
-            //silence the exception if any
+        $dom->validateOnParse = false;
+        $dom->strictErrorChecking = false;
+        if ($dom->loadHTML($content)) {
+            $encoding = $dom->xmlEncoding;
         }
         if (empty($encoding)) {
             $encoding = mb_detect_encoding($content, 'auto', true);
@@ -223,6 +234,7 @@ class entities {
     }
 
     protected function get_all_files () {
+        global $CFG;
 
         $all_files = array();
 
index 143de30..828bca9 100644 (file)
@@ -99,8 +99,8 @@ class cc_forum extends entities {
 
             $replace_values = array($instance['instance'],
                                     //To be more true to the actual forum name we use only forum title
-                                    htmlentities($topic_data['title']),
-                                    htmlentities($topic_data['description']),
+                                    self::safexml($topic_data['title']),
+                                    self::safexml($topic_data['description']),
                                     time());
 
             $result = str_replace($find_tags, $replace_values, $sheet_mod_forum);
index cc43b95..6c27bf2 100644 (file)
@@ -54,8 +54,8 @@ class cc_label extends entities {
         $title = isset($instance['title']) && !empty($instance['title']) ? $instance['title'] : 'Untitled';
         $content = "<img src=\"$@FILEPHP@$$@SLASH@$"."folder.gif\" alt=\"Folder\" title=\"{$title}\" /> {$title}";
         $replace_values = array($instance['instance'],
-                                $title,
-                                htmlentities($content),
+                                self::safexml($title),
+                                self::safexml($content),
                                 time());
 
         return str_replace($find_tags, $replace_values, $sheet_mod_label);
index 79ff905..34e9b27 100644 (file)
@@ -140,10 +140,10 @@ class cc_quiz extends entities {
                            '[#node_questions_feedback#]');
 
         $replace_values = array($instance['id'],
-                                htmlentities($instance['title']),
-                                htmlentities($instance['title']),
-                                htmlentities($quiz_stamp),
-                                htmlentities($questions_strings),
+                                self::safexml($instance['title']),
+                                self::safexml($instance['title']),
+                                self::safexml($quiz_stamp),
+                                self::safexml($questions_strings),
                                 time(),
                                 $instance['options']['max_attempts'],
                                 $instance['options']['timelimit'],
@@ -256,7 +256,7 @@ class cc_quiz extends entities {
         $quiz_stamp = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 
         $replace_values = array($instance['id'],
-                                htmlentities($instance['title']),
+                                self::safexml($instance['title']),
                                 $quiz_stamp,
                                 $node_course_question_categories_questions);
 
@@ -304,10 +304,10 @@ class cc_quiz extends entities {
                 $question_type_node = ($question_moodle_type == MOODLE_QUIZ_SHORTANSWER) ? $this->create_node_course_question_categories_question_category_question_shortanswer($question) : $question_type_node;
 
                 $replace_values = array($question['id'],
-                                        htmlentities($this->truncate_text($question['title'], 255, true)),
-                                        htmlentities($question['title']),
+                                        self::safexml($this->truncate_text($question['title'], 255, true)),
+                                        self::safexml($question['title']),
                                         $question_moodle_type,
-                                        htmlentities($question['feedback']),
+                                        self::safexml($question['feedback']),
                                         time(),
                                         $question_type_node,
                                         $quiz_stamp,
@@ -764,7 +764,7 @@ class cc_quiz extends entities {
                            '[#is_single#]');
 
         $replace_values = array($node_course_question_categories_question_answer,
-                                htmlentities($answer_string),
+                                self::safexml($answer_string),
                                 $is_single);
 
         $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
@@ -819,8 +819,8 @@ class cc_quiz extends entities {
                            '[#use_case#]',
                            '[#node_course_question_categories_question_category_question_answer#]');
 
-        $replace_values = array(htmlentities($answers_string),
-                                htmlentities($use_case),
+        $replace_values = array(self::safexml($answers_string),
+                                self::safexml($use_case),
                                 $node_course_question_categories_question_answer);
 
 
@@ -866,7 +866,7 @@ class cc_quiz extends entities {
                            '[#false_answer_id#]');
 
         $replace_values = array($node_course_question_categories_question_answer,
-                                htmlentities($true_answer_id),
+                                $true_answer_id,
                                 $false_answer_id);
 
         $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
@@ -900,9 +900,9 @@ class cc_quiz extends entities {
                            '[#answer_feedback#]');
 
         $replace_values = array($answer['id'],
-                                htmlentities($answer['title']),
+                                self::safexml($answer['title']),
                                 $answer['score'],
-                                $answer['feedback']);
+                                self::safexml($answer['feedback']));
 
         $node_question_categories_question_answer = str_replace($find_tags, $replace_values, $sheet_question_categories_question_answer);
 
index 7c64b5c..b610011 100644 (file)
@@ -149,13 +149,13 @@ class cc_resource extends entities {
                         //silence the complaints
                     }
                     chdir($cdir);
-                    $mod_alltext = htmlspecialchars($mod_alltext, ENT_COMPAT, 'UTF-8', false);
+                    $mod_alltext = self::safexml($mod_alltext);
                 }
             }
         }
 
         $replace_values = array($instance['instance'],
-                                htmlspecialchars($instance['title']),
+                                self::safexml($instance['title']),
                                 $mod_type,
                                 $mod_reference,
                                 '',
index d15366b..c44c07c 100644 (file)
@@ -80,7 +80,7 @@ class cc11_basiclti extends entities11 {
     protected function getValue($node, $default = '') {
         $result = $default;
         if (is_object($node) && ($node->length > 0) && !empty($node->item(0)->nodeValue)) {
-            $result = htmlentities(trim($node->item(0)->nodeValue));
+            $result = htmlspecialchars(trim($node->item(0)->nodeValue), ENT_COMPAT, 'UTF-8', false);
         }
         return $result;
     }
index 970fae1..1fc3625 100644 (file)
@@ -98,8 +98,8 @@ class cc11_forum extends entities11 {
 
             $replace_values = array($instance['instance'],
             //To be more true to the actual forum name we use only forum title
-            htmlentities($topic_data['title']),
-            htmlentities($topic_data['description']),
+            self::safexml($topic_data['title']),
+            self::safexml($topic_data['description']),
             time());
 
             $result = str_replace($find_tags, $replace_values, $sheet_mod_forum);
index d3cfd72..7fad712 100644 (file)
@@ -75,7 +75,7 @@ class cc11_lti extends entities11 {
     protected function getValue($node, $default = '') {
         $result = $default;
         if (is_object($node) && ($node->length > 0) && !empty($node->item(0)->nodeValue)) {
-            $result = htmlentities(trim($node->item(0)->nodeValue));
+            $result = htmlspecialchars(trim($node->item(0)->nodeValue), ENT_COMPAT, 'UTF-8', false);
         }
         return $result;
     }
index a56fe2d..83e50d1 100644 (file)
@@ -140,10 +140,10 @@ class cc11_quiz extends entities11 {
                            '[#node_questions_feedback#]');
 
         $replace_values = array($instance['id'],
-                                htmlentities($instance['title']),
-                                htmlentities($instance['title']),
-                                htmlentities($quiz_stamp),
-                                htmlentities($questions_strings),
+                                self::safexml($instance['title']),
+                                self::safexml($instance['title']),
+                                self::safexml($quiz_stamp),
+                                self::safexml($questions_strings),
                                 time(),
                                 $instance['options']['max_attempts'],
                                 $instance['options']['timelimit'],
@@ -256,7 +256,7 @@ class cc11_quiz extends entities11 {
         $quiz_stamp = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 
         $replace_values = array($instance['id'],
-                                htmlentities($instance['title']),
+                                self::safexml($instance['title']),
                                 $quiz_stamp,
                                 $node_course_question_categories_questions);
 
@@ -304,10 +304,10 @@ class cc11_quiz extends entities11 {
                 $question_type_node = ($question_moodle_type == MOODLE_QUIZ_SHORTANSWER) ? $this->create_node_course_question_categories_question_category_question_shortanswer($question) : $question_type_node;
 
                 $replace_values = array($question['id'],
-                                        htmlentities($this->truncate_text($question['title'], 255, true)),
-                                        htmlentities($question['title']),
+                                        self::safexml($this->truncate_text($question['title'], 255, true)),
+                                        self::safexml($question['title']),
                                         $question_moodle_type,
-                                        htmlentities($question['feedback']),
+                                        self::safexml($question['feedback']),
                                         time(),
                                         $question_type_node,
                                         $quiz_stamp,
@@ -764,7 +764,7 @@ class cc11_quiz extends entities11 {
                            '[#is_single#]');
 
         $replace_values = array($node_course_question_categories_question_answer,
-                                htmlentities($answer_string),
+                                self::safexml($answer_string),
                                 $is_single);
 
         $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
@@ -819,8 +819,8 @@ class cc11_quiz extends entities11 {
                            '[#use_case#]',
                            '[#node_course_question_categories_question_category_question_answer#]');
 
-        $replace_values = array(htmlentities($answers_string),
-                                htmlentities($use_case),
+        $replace_values = array(self::safexml($answers_string),
+                                self::safexml($use_case),
                                 $node_course_question_categories_question_answer);
 
 
@@ -866,7 +866,7 @@ class cc11_quiz extends entities11 {
                            '[#false_answer_id#]');
 
         $replace_values = array($node_course_question_categories_question_answer,
-                                htmlentities($true_answer_id),
+                                $true_answer_id,
                                 $false_answer_id);
 
         $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
@@ -900,9 +900,9 @@ class cc11_quiz extends entities11 {
                            '[#answer_feedback#]');
 
         $replace_values = array($answer['id'],
-                                htmlentities($answer['title']),
+                                self::safexml($answer['title']),
                                 $answer['score'],
-                                $answer['feedback']);
+                                self::safexml($answer['feedback']));
 
         $node_question_categories_question_answer = str_replace($find_tags, $replace_values, $sheet_question_categories_question_answer);
 
index 4d9544d..adadce0 100644 (file)
@@ -157,13 +157,13 @@ class cc11_resource extends entities11 {
                         //silence the complaints
                     }
                     chdir($cdir);
-                    $mod_alltext = htmlspecialchars($mod_alltext, ENT_COMPAT, 'UTF-8', false);
+                    $mod_alltext = self::safexml($mod_alltext);
                 }
             }
         }
 
         $replace_values = array($instance['instance'],
-                                htmlspecialchars($instance['title']),
+                                self::safexml($instance['title']),
                                 $mod_type,
                                 $mod_reference,
                                 '',
index 43de903..ba12554 100644 (file)
@@ -109,7 +109,14 @@ final class libxml_errors_mgr {
      * @var boolean
      */
     private $previous = false;
-    public function __construct(){
+
+    /**
+     * @param boolean $reset
+     */
+    public function __construct($reset=false){
+        if ($reset) {
+            error_messages::instance()->reset();
+        }
         $this->previous = libxml_use_internal_errors(true);
         libxml_clear_errors();
     }
@@ -146,6 +153,10 @@ final class libxml_errors_mgr {
             libxml_use_internal_errors($this->previous);
         }
     }
+
+    public function collect() {
+        $this->collect_errors();
+    }
 }
 
 
index 86694fc..6b780a4 100644 (file)
@@ -103,12 +103,18 @@ class imscc1_converter extends base_converter {
         }
         $status = $cc2moodle->generate_moodle_xml();
         //Final cleanup
+        $xml_error = new libxml_errors_mgr(true);
         $mdoc = new DOMDocument();
         $mdoc->preserveWhiteSpace = false;
         $mdoc->formatOutput = true;
         $mdoc->validateOnParse = false;
+        $mdoc->strictErrorChecking = false;
         if ($mdoc->load($manifestdir.'/moodle.xml', LIBXML_NONET)) {
             $mdoc->save($this->get_workdir_path().'/moodle.xml', LIBXML_NOEMPTYTAG);
+        } else {
+            $xml_error->collect();
+            $this->log('validation error(s): '.PHP_EOL.error_messages::instance(), backup::LOG_DEBUG, null, 2);
+            throw new imscc1_convert_exception(error_messages::instance()->to_string(true));
         }
         //Move the files to the workdir
         rename($manifestdir.'/course_files', $this->get_workdir_path().'/course_files');
index 15ddace..3ca8267 100644 (file)
@@ -103,12 +103,18 @@ class imscc11_converter extends base_converter {
         }
         $status = $cc112moodle->generate_moodle_xml();
         //Final cleanup
+        $xml_error = new libxml_errors_mgr(true);
         $mdoc = new DOMDocument();
         $mdoc->preserveWhiteSpace = false;
         $mdoc->formatOutput = true;
         $mdoc->validateOnParse = false;
+        $mdoc->strictErrorChecking = false;
         if ($mdoc->load($manifestdir.'/moodle.xml', LIBXML_NONET)) {
             $mdoc->save($this->get_workdir_path().'/moodle.xml', LIBXML_NOEMPTYTAG);
+        } else {
+            $xml_error->collect();
+            $this->log('validation error(s): '.PHP_EOL.error_messages::instance(), backup::LOG_DEBUG, null, 2);
+            throw new imscc11_convert_exception(error_messages::instance()->to_string(true));
         }
         //Move the files to the workdir
         rename($manifestdir.'/course_files', $this->get_workdir_path().'/course_files');