MDL-54627 search: Ensure that all format_string strings are text.
authorDavid Monllao <davidm@moodle.com>
Wed, 18 May 2016 08:28:18 +0000 (16:28 +0800)
committerDavid Monllao <davidm@moodle.com>
Thu, 19 May 2016 05:16:01 +0000 (13:16 +0800)
All user input that is usually displayed through format_strings with
filters like mulitlang applied should be converted to text as well.

course/classes/search/mycourse.php
course/tests/search_test.php
lib/tests/weblib_test.php
lib/weblib.php
mod/book/classes/search/chapter.php
mod/forum/classes/search/post.php
mod/glossary/classes/search/entry.php
mod/page/classes/search/activity.php
mod/wiki/classes/search/collaborative_page.php
search/classes/area/base_activity.php
search/classes/document.php

index db136cd..7a5f30b 100644 (file)
@@ -70,7 +70,7 @@ class mycourse extends \core_search\area\base {
         }
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->fullname);
+        $doc->set('title', content_to_text($record->fullname, false));
         $doc->set('content', content_to_text($record->summary, $record->summaryformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->id);
index 6750fbf..5512e07 100644 (file)
@@ -123,7 +123,7 @@ class course_search_testcase extends advanced_testcase {
         $this->assertEquals($course->fullname, $doc->get('title'));
 
         // Not nice. Applying \core_search\document::set line breaks clean up.
-        $summary = preg_replace("/\s+/", ' ', trim(content_to_text($course->summary, $course->summaryformat), "\r\n"));
+        $summary = preg_replace("/\s+/", " ", content_to_text($course->summary, $course->summaryformat));
         $this->assertEquals($summary, $doc->get('content'));
         $this->assertEquals($course->shortname, $doc->get('description1'));
     }
index ba2d2be..9092627 100644 (file)
@@ -600,4 +600,41 @@ EXPECTED;
 
     }
 
+    /**
+     * Tests for content_to_text.
+     *
+     * @param string    $content   The content
+     * @param int|false $format    The content format
+     * @param string    $expected  Expected value
+     * @dataProvider provider_content_to_text
+     */
+    public function test_content_to_text($content, $format, $expected) {
+        $content = content_to_text($content, $format);
+        $this->assertEquals($expected, $content);
+    }
+
+    /**
+     * Data provider for test_content_to_text.
+     */
+    public static function provider_content_to_text() {
+        return array(
+            array('asd', false, 'asd'),
+            // Trim '\r\n '.
+            array("Note that:\n\n3 > 1 ", FORMAT_PLAIN, "Note that:\n\n3 > 1"),
+            array("Note that:\n\n3 > 1\r\n", FORMAT_PLAIN, "Note that:\n\n3 > 1"),
+            // Multiple spaces to one.
+            array('<span class="eheh">京都</span>  ->  hehe', FORMAT_HTML, '京都 -> hehe'),
+            array('<span class="eheh">京都</span>  ->  hehe', false, '京都 -> hehe'),
+            array('asd    asd', false, 'asd asd'),
+            // From markdown to html and html to text.
+            array('asd __lera__ con la', FORMAT_MARKDOWN, 'asd LERA con la'),
+            // HTML to text.
+            array('<p class="frogs">This is a <strong class=\'fishes\'>test</strong></p>', FORMAT_HTML, 'This is a TEST'),
+            array("<span lang='en' class='multilang'>english</span>
+<span lang='ca' class='multilang'>català</span>
+<span lang='es' class='multilang'>español</span>
+<span lang='fr' class='multilang'>français</span>", FORMAT_HTML, "english català español français")
+        );
+    }
+
 }
index 468bf4d..fe5b2c3 100644 (file)
@@ -1918,24 +1918,35 @@ function html_to_text($html, $width = 75, $dolinks = true) {
 }
 
 /**
- * Converts content introduced in an editor to plain text.
+ * Converts texts or strings to plain text.
+ *
+ * - When used to convert user input introduced in an editor the text format needs to be passed in $contentformat like we usually
+ *   do in format_text.
+ * - When this function is used for strings that are usually passed through format_string before displaying them
+ *   we need to set $contentformat to false. This will execute html_to_text as these strings can contain multilang tags if
+ *   multilang filter is applied to headings.
  *
  * @param string $content The text as entered by the user
- * @param int $contentformat The text format: FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN or FORMAT_MARKDOWN
+ * @param int|false $contentformat False for strings or the text format: FORMAT_MOODLE/FORMAT_HTML/FORMAT_PLAIN/FORMAT_MARKDOWN
  * @return string Plain text.
  */
 function content_to_text($content, $contentformat) {
 
     switch ($contentformat) {
         case FORMAT_PLAIN:
-            return $content;
+            // Nothing here.
+            break;
         case FORMAT_MARKDOWN:
-            $html = markdown_to_html($content);
-            return html_to_text($html, 75, false);
+            $content = markdown_to_html($content);
+            $content = html_to_text($content, 75, false);
+            break;
         default:
-            // FORMAT_HTML and FORMAT_MOODLE.
-            return html_to_text($content, 75, false);
+            // FORMAT_HTML, FORMAT_MOODLE and $contentformat = false, the later one are strings usually formatted through
+            // format_string, we need to convert them from html because they can contain HTML (multilang filter).
+            $content = html_to_text($content, 75, false);
     }
+
+    return trim($content, "\r\n ");
 }
 
 /**
index da0be81..120b0a6 100644 (file)
@@ -79,7 +79,7 @@ class chapter extends \core_search\area\base_mod {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->title);
+        $doc->set('title', content_to_text($record->title, false));
         $doc->set('content', content_to_text($record->content, $record->contentformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->courseid);
index 5836723..b17dfcd 100644 (file)
@@ -94,7 +94,7 @@ class post extends \core_search\area\base_mod {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->subject);
+        $doc->set('title', content_to_text($record->subject, false));
         $doc->set('content', content_to_text($record->message, $record->messageformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->courseid);
index 40e223f..e030e4e 100644 (file)
@@ -90,7 +90,7 @@ class entry extends \core_search\area\base_mod {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($entry->id, $this->componentname, $this->areaname);
-        $doc->set('title', $entry->concept);
+        $doc->set('title', content_to_text($entry->concept, false));
         $doc->set('content', content_to_text($entry->definition, $entry->definitionformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $entry->course);
@@ -106,6 +106,7 @@ class entry extends \core_search\area\base_mod {
 
         // Adding keywords as extra info.
         if ($keywords) {
+            // No need to pass through content_to_text here as this is just a list of keywords.
             $doc->set('description1', implode(' ' , $keywords));
         }
 
index c37a393..470c3be 100644 (file)
@@ -64,7 +64,7 @@ class activity extends \core_search\area\base_activity {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->name);
+        $doc->set('title', content_to_text($record->name, false));
         $doc->set('content', content_to_text($record->content, $record->contentformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->course);
index cbf2d95..fac4ca4 100644 (file)
@@ -98,7 +98,7 @@ class collaborative_page extends \core_search\area\base_mod {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->title);
+        $doc->set('title', content_to_text($record->title, false));
         $doc->set('content', $content);
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->courseid);
index 18254fd..0970f6e 100644 (file)
@@ -94,7 +94,7 @@ abstract class base_activity extends base_mod {
 
         // Prepare associative array with data from DB.
         $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
-        $doc->set('title', $record->name);
+        $doc->set('title', content_to_text($record->name, false));
         $doc->set('content', content_to_text($record->intro, $record->introformat));
         $doc->set('contextid', $context->id);
         $doc->set('courseid', $record->course);
index c7cdb6d..61658f5 100644 (file)
@@ -276,8 +276,8 @@ class document implements \renderable, \templatable {
         if ($fielddata['type'] === 'int' || $fielddata['type'] === 'tdate') {
             $this->data[$fieldname] = intval($value);
         } else {
-            // Clean up line breaks and extra spaces.
-            $this->data[$fieldname] = preg_replace("/\s+/", ' ', trim($value, "\r\n"));
+            // Replace all groups of line breaks and spaces by single spaces.
+            $this->data[$fieldname] = preg_replace("/\s+/", " ", $value);
         }
 
         return $this->data[$fieldname];