Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added support for some PHP style mathematical functions in the correc…

…t answer formula for calculated questions

Documentation on the functions can be found at
http://uk.php.net/manual/en/ref.math.php
  • Loading branch information...
commit 39fbd5c81807a4f0565e1a674033c3a03a1ce3dc 1 parent dcf633e
kaipe authored
View
6 lang/en/quiz.php
@@ -103,6 +103,11 @@
$string['forceregeneration'] = 'force regeneration';
$string['fractionsaddwrong'] = 'The positive grades you have chosen do not add up to 100%%<BR>Instead, they add up to $a%%<BR>Do you want to go back and fix this question?';
$string['fractionsnomax'] = 'One of the answers should be 100%%, so that it is<BR>possible to get a full grade for this question.<BR>Do you want to go back and fix this question?';
+$string['functiontakesatleasttwo'] = 'The function $a must have at least two arguments';
+$string['functiontakesnoargs'] = 'The function $a does not take any arguments';
+$string['functiontakesonearg'] = 'The function $a must have exactly one argument';
+$string['functiontakesoneortwoargs'] = 'The function $a must have either one or two arguments';
+$string['functiontakestwoargs'] = 'The function $a must have exactly two arguments';
$string['generatevalue'] = 'Generate a new value between';
$string['geometric'] = 'Geometric';
$string['gift'] = 'GIFT format';
@@ -252,6 +257,7 @@
$string['uniform'] = 'decimals, from a uniform distribution';
$string['unit'] = 'Unit';
$string['unknowntype'] = 'Question type not supported at line $a. The question will be ignored';
+$string['unsupportedformulafunction'] = 'The function $a is not supported';
$string['viewallanswers'] = 'View $a completed quizzes';
$string['viewallreports'] = 'View reports for $a attempts';
$string['warningsdetected'] = '$a warning(s) detected';
View
87 mod/quiz/questiontypes/calculated/questiontype.php
@@ -426,8 +426,8 @@ function quiz_qtype_calculated_calculate_answer($formula, $individualdata,
$calculated->answer = $calculated->min = $calculated->max = '';
return $calculated;
- } else if (ereg('^(.*([^- 0-9+*./()eE])).*$', $formula, $regs)) {
- $calculated->answer = get_string('syntaxerror', 'quiz', $regs[1]);
+ } else if ($error = quiz_qtype_calculated_find_formula_errors($formula)) {
+ $calculated->answer = $error;
$calculated->min = $calculated->max = '';
return $calculated;
}
@@ -526,6 +526,7 @@ function quiz_qtype_calculated_calculate_answer($formula, $individualdata,
return $calculated;
}
+
function quiz_qtype_calculated_find_formula_errors($formula) {
/// Validates the formula submitted from the question edit page.
/// Returns false if everything is alright.
@@ -536,14 +537,84 @@ function quiz_qtype_calculated_find_formula_errors($formula) {
$formula = str_replace($regs[0], '1', $formula);
}
+ // Strip away empty space
+ $formula = str_replace(' ', '', $formula);
- if (!ereg('[^- 0-9+*/:.(>?)!e=|<E&]+', $formula, $regs)) {
- // Need to work more on this check -
- // It is too strict and still not very effetive...
- return false; // Need to work more on this one
-
- } else {
+ $safeoperatorchar = '-+/*%>:^~<?=&|!';
+ $operatorornumber = "[$safeoperatorchar.0-9eE]";
+
+ while (ereg("(^|[$safeoperatorchar,(])([a-z0-9_]*)\\(($operatorornumber+(,$operatorornumber+((,$operatorornumber+)+)?)?)?\\)",
+ $formula, $regs)) {
+
+ switch ($regs[2]) {
+ // Simple parenthesis
+ case '':
+ if ($regs[4] || empty($regs[3])) {
+ return get_string('illegalformulasyntax', 'quiz', $regs[0]);
+ }
+ break;
+
+ // Zero argument functions
+ case 'pi':
+ if ($regs[3]) {
+ return get_string('functiontakesnoargs', 'quiz', $regs[2]);
+ }
+ break;
+
+ // Single argument functions (the most common case)
+ case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh':
+ case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos':
+ case 'cosh': case 'decbin': case 'decoct': case 'deg2rad':
+ case 'exp': case 'expm1': case 'floor': case 'is_finite':
+ case 'is_infinite': case 'is_nan': case 'log10': case 'log1p':
+ case 'octdec': case 'rad2deg': case 'sin': case 'sinh': case 'sqrt':
+ case 'tan': case 'tanh':
+ if ($regs[4] || empty($regs[3])) {
+ return get_string('functiontakesonearg','quiz',$regs[2]);
+ }
+ break;
+
+ // Functions that take one or two arguments
+ case 'log': case 'round':
+ if ($regs[5] || empty($regs[3])) {
+ return get_string('functiontakesoneortwoargs','quiz',$regs[2]);
+ }
+ break;
+
+ // Functions that must have two arguments
+ case 'atan2': case 'fmod': case 'pow':
+ if ($regs[5] || empty($regs[4])) {
+ return get_string('functiontakestwoargs', 'quiz', $regs[2]);
+ }
+ break;
+
+ // Functions that take two or more arguments
+ case 'min': case 'max':
+ if (empty($regs[4])) {
+ return get_string('functiontakesatleasttwo','quiz',$regs[2]);
+ }
+ break;
+
+ default:
+ return get_string('unsupportedformulafunction','quiz',$regs[2]);
+ }
+
+ // Exchange the function call with '1' and then chack for
+ // another function call...
+ if ($regs[1]) {
+ // The function call is proceeded by an operator
+ $formula = str_replace($regs[0], $regs[1] . '1', $formula);
+ } else {
+ // The function call starts the formula
+ $formula = ereg_replace("^$regs[2]\\([^)]*\\)", '1', $formula);
+ }
+ }
+
+ if (ereg("[^$safeoperatorchar.0-9eE]+", $formula, $regs)) {
return get_string('illegalformulasyntax', 'quiz', $regs[0]);
+ } else {
+ // Formula just might be valid
+ return false;
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.