From 505ce88467ca9eafeb2469e10afe87b77d7fb718 Mon Sep 17 00:00:00 2001 From: David Monllao Date: Wed, 18 May 2016 16:28:18 +0800 Subject: [PATCH] MDL-54627 search: Ensure that all format_string strings are text. 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 | 2 +- course/tests/search_test.php | 2 +- lib/tests/weblib_test.php | 37 +++++++++++++++++++ lib/weblib.php | 25 +++++++++---- mod/book/classes/search/chapter.php | 2 +- mod/forum/classes/search/post.php | 2 +- mod/glossary/classes/search/entry.php | 3 +- mod/page/classes/search/activity.php | 2 +- .../classes/search/collaborative_page.php | 2 +- search/classes/area/base_activity.php | 2 +- search/classes/document.php | 4 +- 11 files changed, 66 insertions(+), 17 deletions(-) diff --git a/course/classes/search/mycourse.php b/course/classes/search/mycourse.php index db136cd2ca0..7a5f30be2b7 100644 --- a/course/classes/search/mycourse.php +++ b/course/classes/search/mycourse.php @@ -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); diff --git a/course/tests/search_test.php b/course/tests/search_test.php index 6750fbfb1bb..5512e07814c 100644 --- a/course/tests/search_test.php +++ b/course/tests/search_test.php @@ -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')); } diff --git a/lib/tests/weblib_test.php b/lib/tests/weblib_test.php index ba2d2be26df..9092627769c 100644 --- a/lib/tests/weblib_test.php +++ b/lib/tests/weblib_test.php @@ -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('京都 -> hehe', FORMAT_HTML, '京都 -> hehe'), + array('京都 -> 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('

This is a test

', FORMAT_HTML, 'This is a TEST'), + array("english +català +español +français", FORMAT_HTML, "english català español français") + ); + } + } diff --git a/lib/weblib.php b/lib/weblib.php index 468bf4dbcb2..fe5b2c35515 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -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 "); } /** diff --git a/mod/book/classes/search/chapter.php b/mod/book/classes/search/chapter.php index da0be812a2a..120b0a61622 100644 --- a/mod/book/classes/search/chapter.php +++ b/mod/book/classes/search/chapter.php @@ -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); diff --git a/mod/forum/classes/search/post.php b/mod/forum/classes/search/post.php index 58367233fe4..b17dfcd60db 100644 --- a/mod/forum/classes/search/post.php +++ b/mod/forum/classes/search/post.php @@ -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); diff --git a/mod/glossary/classes/search/entry.php b/mod/glossary/classes/search/entry.php index 40e223f16c2..e030e4eba42 100644 --- a/mod/glossary/classes/search/entry.php +++ b/mod/glossary/classes/search/entry.php @@ -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)); } diff --git a/mod/page/classes/search/activity.php b/mod/page/classes/search/activity.php index c37a393e6a7..470c3beb200 100644 --- a/mod/page/classes/search/activity.php +++ b/mod/page/classes/search/activity.php @@ -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); diff --git a/mod/wiki/classes/search/collaborative_page.php b/mod/wiki/classes/search/collaborative_page.php index cbf2d95d166..fac4ca46af7 100644 --- a/mod/wiki/classes/search/collaborative_page.php +++ b/mod/wiki/classes/search/collaborative_page.php @@ -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); diff --git a/search/classes/area/base_activity.php b/search/classes/area/base_activity.php index 18254fd5fba..0970f6ee457 100644 --- a/search/classes/area/base_activity.php +++ b/search/classes/area/base_activity.php @@ -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); diff --git a/search/classes/document.php b/search/classes/document.php index c7cdb6df1eb..61658f5b2eb 100644 --- a/search/classes/document.php +++ b/search/classes/document.php @@ -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];