diff --git a/lib/tests/externallib_test.php b/lib/tests/externallib_test.php index cda9bd33c0d..f69df72f102 100644 --- a/lib/tests/externallib_test.php +++ b/lib/tests/externallib_test.php @@ -196,6 +196,7 @@ class core_externallib_testcase extends advanced_testcase { $correct = 'ENFR hi there%'; $this->assertSame($correct, external_format_string($test, $context->id, false, ['filter' => false])); + $this->assertSame("& < > \" '", format_string("& < > \" '", true, ['escape' => false])); $settings->set_raw($currentraw); $settings->set_filter($currentfilter); diff --git a/lib/tests/weblib_test.php b/lib/tests/weblib_test.php index 9092627769c..73165b37bb4 100644 --- a/lib/tests/weblib_test.php +++ b/lib/tests/weblib_test.php @@ -37,6 +37,7 @@ class core_weblib_testcase extends advanced_testcase { $this->assertSame("ANother & &&&&& Category", format_string("ANother & &&&&& Category")); $this->assertSame("ANother & &&&&& Category", format_string("ANother & &&&&& Category", true)); $this->assertSame("Nick's Test Site & Other things", format_string("Nick's Test Site & Other things", true)); + $this->assertSame("& < > \" '", format_string("& < > \" '", true, ['escape' => false])); // String entities. $this->assertSame(""", format_string(""")); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index a8cccd770e4..d4e9953324a 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -13,6 +13,7 @@ information provided here is intended especially for developers. - get_user_max_upload_file_size() * The following functions have been removed and should not be used any more: - file_modify_html_header() - See MDL-29738 for more information. +* New option 'escape' added to format_string. When true (default), escapes HTML entities from the string === 3.1 === diff --git a/lib/weblib.php b/lib/weblib.php index c86dc0ed240..9bc283de04c 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -1425,13 +1425,15 @@ function format_string($string, $striplinks = true, $options = null) { $options['filter'] = true; } + $options['escape'] = !isset($options['escape']) || $options['escape']; + if (!$options['context']) { // We did not find any context? weird. return $string = strip_tags($string); } // Calculate md5. - $md5 = md5($string.'<+>'.$striplinks.'<+>'.$options['context']->id.'<+>'.current_language()); + $md5 = md5($string.'<+>'.$striplinks.'<+>'.$options['context']->id.'<+>'.$options['escape'].'<+>'.current_language()); // Fetch from cache if possible. if (isset($strcache[$md5])) { @@ -1440,7 +1442,7 @@ function format_string($string, $striplinks = true, $options = null) { // First replace all ampersands not followed by html entity code // Regular expression moved to its own method for easier unit testing. - $string = replace_ampersands_not_followed_by_entity($string); + $string = $options['escape'] ? replace_ampersands_not_followed_by_entity($string) : $string; if (!empty($CFG->filterall) && $options['filter']) { $filtermanager = filter_manager::instance(); @@ -1450,8 +1452,11 @@ function format_string($string, $striplinks = true, $options = null) { // If the site requires it, strip ALL tags from this string. if (!empty($CFG->formatstringstriptags)) { - $string = str_replace(array('<', '>'), array('<', '>'), strip_tags($string)); - + if ($options['escape']) { + $string = str_replace(array('<', '>'), array('<', '>'), strip_tags($string)); + } else { + $string = strip_tags($string); + } } else { // Otherwise strip just links if that is required (default). if ($striplinks) {