MDL-64975 moodlelib: fix float formatting if decsep is ~ (tilde)

Commit 637da99edbd7258fae20374ed8c890a167f40d30 has introduced changes
for removing trailing zeroes from the output of function format_float.
Due to a small omission, the function causes a PHP warning when the
string decsep is set to a tilde character ('~'). This is rarely the
case.

The bug lies in using PHP function preg_replace with a string that
contains external input (in this case, including decsep), but without
escaping it for PCRE processing.

This commit fixes the function to also support a tilde character in
string decsep. It also adds tests for having tilde as decimal separator.

Thanks-To:  Jake Dallimore <jake@moodle.com>
This commit is contained in:
Nicolas Roeser 2019-04-08 13:58:30 +02:00
parent 5dae8c0515
commit 76a3cf95b7
2 changed files with 18 additions and 4 deletions

View File

@ -8618,7 +8618,7 @@ function format_float($float, $decimalpoints=1, $localized=true, $stripzeros=fal
$result = number_format($float, $decimalpoints, $separator, '');
if ($stripzeros) {
// Remove zeros and final dot if not needed.
$result = preg_replace('~(' . preg_quote($separator) . ')?0+$~', '', $result);
$result = preg_replace('~(' . preg_quote($separator, '~') . ')?0+$~', '', $result);
}
return $result;
}

View File

@ -36,18 +36,24 @@ class core_moodlelib_testcase extends advanced_testcase {
* It is not possible to directly change the result of get_string in
* a unit test. Instead, we create a language pack for language 'xx' in
* dataroot and make langconfig.php with the string we need to change.
* The example separator used here is 'X'; on PHP 5.3 and before this
* The default example separator used here is 'X'; on PHP 5.3 and before this
* must be a single byte character due to PHP bug/limitation in
* number_format, so you can't use UTF-8 characters.
*
* @param string $decsep Separator character. Defaults to `'X'`.
*/
protected function define_local_decimal_separator() {
protected function define_local_decimal_separator(string $decsep = 'X') {
global $SESSION, $CFG;
$SESSION->lang = 'xx';
$langconfig = "<?php\n\$string['decsep'] = 'X';";
$langconfig = "<?php\n\$string['decsep'] = '$decsep';";
$langfolder = $CFG->dataroot . '/lang/xx';
check_dir_exists($langfolder);
file_put_contents($langfolder . '/langconfig.php', $langconfig);
// Ensure the new value is picked up and not taken from the cache.
$stringmanager = get_string_manager();
$stringmanager->reset_caches(true);
}
public function test_cleanremoteaddr() {
@ -2257,6 +2263,14 @@ class core_moodlelib_testcase extends advanced_testcase {
// Localisation off.
$this->assertEquals('5.43000', format_float(5.43, 5, false));
$this->assertEquals('5.43', format_float(5.43, 5, false, true));
// Tests with tilde as localised decimal separator.
$this->define_local_decimal_separator('~');
// Must also work for '~' as decimal separator.
$this->assertEquals('5', format_float(5.0001, 3, true, true));
$this->assertEquals('5~43000', format_float(5.43, 5));
$this->assertEquals('5~43', format_float(5.43, 5, true, true));
}
/**