MDL-73824 gradebook: Stricter float check to some gradelib functions

It has been detected that, right now, some localised floats are
being passed to those functions (say comma separator, say thousands)
and that's leading to all sort of problems later when comparing,
processing or storing those "wrong-floats" (user entered).

This just makes all those functions to be stricter, so any attempt
of passing to them a wrong float will fail with a clear TypeError.

Any existing case must be converted to a corrrect (X.Y) format, using
unformat_float() or PARAM_LOCALISEDFLOAT before any processing.

Localised floats cannot be used.

Also, fix all the places where those functions are called from
files having strict_types enabled because, with that, now float-like
strings are not accepted any more. Luckily, there is only case,
within the grade/classes/component_gradeitem.php file, and it has
been fixed by casting the float-like string coming from DB to float.
This commit is contained in:
Eloy Lafuente (stronk7) 2022-02-15 10:15:16 +01:00
parent 1d99ba19a2
commit e2821bf1ce
3 changed files with 28 additions and 17 deletions

View File

@ -405,6 +405,7 @@ abstract class component_gradeitem {
if ($grade = $this->get_grade_for_user($gradeduser, $grader)) {
$gradeitem = $this->get_grade_item();
if (!$this->is_using_scale()) {
$grade->grade = !is_null($grade->grade) ? (float)$grade->grade : null; // Cast non-null values, keeping nulls.
$grade->usergrade = grade_format_gradevalue($grade->grade, $gradeitem);
$grade->maxgrade = format_float($gradeitem->grademax, $gradeitem->get_decimals());
// If displaying the raw grade, also display the total value.

View File

@ -759,14 +759,14 @@ function grade_set_setting($courseid, $name, $value) {
/**
* Returns string representation of grade value
*
* @param float $value The grade value
* @param float|null $value The grade value
* @param object $grade_item Grade item object passed by reference to prevent scale reloading
* @param bool $localized use localised decimal separator
* @param int $displaytype type of display. For example GRADE_DISPLAY_TYPE_REAL, GRADE_DISPLAY_TYPE_PERCENTAGE, GRADE_DISPLAY_TYPE_LETTER
* @param int $decimals The number of decimal places when displaying float values
* @return string
*/
function grade_format_gradevalue($value, &$grade_item, $localized=true, $displaytype=null, $decimals=null) {
function grade_format_gradevalue(?float $value, &$grade_item, $localized=true, $displaytype=null, $decimals=null) {
if ($grade_item->gradetype == GRADE_TYPE_NONE or $grade_item->gradetype == GRADE_TYPE_TEXT) {
return '';
}
@ -830,13 +830,13 @@ function grade_format_gradevalue($value, &$grade_item, $localized=true, $display
/**
* Returns a float representation of a grade value
*
* @param float $value The grade value
* @param float|null $value The grade value
* @param object $grade_item Grade item object
* @param int $decimals The number of decimal places
* @param bool $localized use localised decimal separator
* @return string
*/
function grade_format_gradevalue_real($value, $grade_item, $decimals, $localized) {
function grade_format_gradevalue_real(?float $value, $grade_item, $decimals, $localized) {
if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
if (!$scale = $grade_item->load_scale()) {
return get_string('error');
@ -853,13 +853,13 @@ function grade_format_gradevalue_real($value, $grade_item, $decimals, $localized
/**
* Returns a percentage representation of a grade value
*
* @param float $value The grade value
* @param float|null $value The grade value
* @param object $grade_item Grade item object
* @param int $decimals The number of decimal places
* @param bool $localized use localised decimal separator
* @return string
*/
function grade_format_gradevalue_percentage($value, $grade_item, $decimals, $localized) {
function grade_format_gradevalue_percentage(?float $value, $grade_item, $decimals, $localized) {
$min = $grade_item->grademin;
$max = $grade_item->grademax;
if ($min == $max) {
@ -874,11 +874,11 @@ function grade_format_gradevalue_percentage($value, $grade_item, $decimals, $loc
* Returns a letter grade representation of a grade value
* The array of grade letters used is produced by {@link grade_get_letters()} using the course context
*
* @param float $value The grade value
* @param float|null $value The grade value
* @param object $grade_item Grade item object
* @return string
*/
function grade_format_gradevalue_letter($value, $grade_item) {
function grade_format_gradevalue_letter(?float $value, $grade_item) {
global $CFG;
$context = context_course::instance($grade_item->courseid, IGNORE_MISSING);
if (!$letters = grade_get_letters($context)) {
@ -1587,10 +1587,10 @@ function grade_course_reset($courseid) {
* Convert a number to 5 decimal point float, an empty string or a null db compatible format
* (we need this to decide if db value changed)
*
* @param mixed $number The number to convert
* @return mixed float or null
* @param float|null $number The number to convert
* @return float|null float or null
*/
function grade_floatval($number) {
function grade_floatval(?float $number) {
if (is_null($number) or $number === '') {
return null;
}
@ -1603,11 +1603,11 @@ function grade_floatval($number) {
* Compare two float numbers safely. Uses 5 decimals php precision using {@link grade_floatval()}. Nulls accepted too.
* Used for determining if a database update is required
*
* @param float $f1 Float one to compare
* @param float $f2 Float two to compare
* @param float|null $f1 Float one to compare
* @param float|null $f2 Float two to compare
* @return bool True if the supplied values are different
*/
function grade_floats_different($f1, $f2) {
function grade_floats_different(?float $f1, ?float $f2): bool {
// note: db rounding for 10,5 is different from php round() function
return (grade_floatval($f1) !== grade_floatval($f2));
}
@ -1619,11 +1619,11 @@ function grade_floats_different($f1, $f2) {
* different from php round() function.
*
* @since Moodle 2.0
* @param float $f1 Float one to compare
* @param float $f2 Float two to compare
* @param float|null $f1 Float one to compare
* @param float|null $f2 Float two to compare
* @return bool True if the values should be considered as the same grades
*/
function grade_floats_equal($f1, $f2) {
function grade_floats_equal(?float $f1, ?float $f2): bool {
return (grade_floatval($f1) === grade_floatval($f2));
}

View File

@ -2,6 +2,16 @@ This files describes API changes in core libraries and APIs,
information provided here is intended especially for developers.
=== 4.0 ===
* To better detect wrong floats (like, for example, unformatted, using local-dependent separators ones) a number of
gradebook functions now have stricter float type checking. All them will require now the "float" being passed to be
a correct float value (numeric or string). Usually, that's achieved by using unformat_float() or
PARAM_LOCALISEDFLOAT for all the user-entered grades before any processing on them. Functions affected are:
- grade_format_gradevalue(), $value param (keeping it as optional/nullable).
- grade_format_gradevalue_real(), $value param (keeping it as optional/nullable).
- grade_format_gradevalue_percentage(), $value param (keeping it as optional/nullable).
- grade_format_gradevalue_letter(), $value param (keeping it as optional/nullable).
- grade_floats_different(), $f1 and $f2 params (keeping them as optional/nullable).
- grade_floats_equal(), $f1 and $f2 params (keeping them as optional/nullable).
* The method action_menu->set_alignment() has been deprecated, please use action_menu->set_menu_left if you need a dropdown
to align to the left of the dropdown button.
* The $OUTPUT->should_display_main_logo() function has been deprecated and should no longer be used.