From 19e911a251f00d35c08313c1ecbef00c3db00d6b Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Wed, 18 May 2011 14:12:34 +0100 Subject: [PATCH] MDL-27410 qtype_calculated better errorhandling for invalid expressions. Better method names. --- question/type/calculated/question.php | 42 ++++++++++++------- .../simpletest/testvariablesubstituter.php | 11 ++++- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/question/type/calculated/question.php b/question/type/calculated/question.php index f613ff020fff1..a113ef4f67dbd 100644 --- a/question/type/calculated/question.php +++ b/question/type/calculated/question.php @@ -103,7 +103,7 @@ class qtype_calculated_dataset_loader { protected $questionid; /** @var int the id of the question we are helping. */ - protected $setsavailable = null; + protected $itemsavailable = null; /** * Constructor @@ -113,33 +113,39 @@ public function __construct($questionid) { $this->questionid = $questionid; } - public function get_number_of_datasets() { + /** + * Get the number of items (different values) in each dataset used by this + * question. This is the minimum number of items in any dataset used by this + * question. + * @return int the number of items available. + */ + public function get_number_of_items() { global $DB; - if (is_null($this->setsavailable)) { - $this->setsavailable = $DB->get_field_sql(' + if (is_null($this->itemsavailable)) { + $this->itemsavailable = $DB->get_field_sql(' SELECT MIN(qdd.itemcount) FROM {question_dataset_definitions} qdd JOIN {question_datasets} qd ON qdd.id = qd.datasetdefinition WHERE qd.question = ? - ', array($question->id), MUST_EXIST); + ', array($this->questionid), MUST_EXIST); } - return $this->setsavailable; + return $this->itemsavailable; } /** - * Load a particular data set. - * @param int $setnumber which set of values to load. - * 0 <= $setnumber < {@link get_number_of_datasets()}. + * Load a particular set of values for each dataset used by this question. + * @param int $itemnumber which set of values to load. + * 0 < $itemnumber <= {@link get_number_of_items()}. * @return qtype_calculated_variable_substituter with the correct variable * -> value substitutions set up. */ - public function load_dataset($setnumber) { - if ($setnumber <= 0 || $setnumber > $this->get_number_of_datasets()) { + public function load_values($itemnumber) { + if ($itemnumber <= 0 || $itemnumber > $this->get_number_of_items()) { $a = new stdClass(); - $a->id = $question->id; - $a->item = $datasetitem; + $a->id = $this->questionid; + $a->item = $itemnumber; throw new moodle_exception('cannotgetdsfordependent', 'question', '', $a); } @@ -150,7 +156,7 @@ public function load_dataset($setnumber) { JOIN {question_datasets} qd ON qdd.id = qd.datasetdefinition WHERE qd.question = ? AND qdi.itemnumber = ? - ', array($question->id, $setnumber)); + ', array($this->questionid, $itemnumber)); return new qtype_calculated_variable_substituter($values); } @@ -222,8 +228,12 @@ public function get_values() { * @return float the computed result. */ public function calculate($expression) { - eval('$str = ' . $this->substitute_values($expression) . ';'); - return $str; + $exp = $this->substitute_values($expression); + // This validation trick from http://php.net/manual/en/function.eval.php + if (!@eval('return true; $result = ' . $exp . ';')) { + throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '', $expression); + } + return eval('return ' . $exp . ';'); } /** diff --git a/question/type/calculated/simpletest/testvariablesubstituter.php b/question/type/calculated/simpletest/testvariablesubstituter.php index 2a0be48be5af9..37729628d9c97 100644 --- a/question/type/calculated/simpletest/testvariablesubstituter.php +++ b/question/type/calculated/simpletest/testvariablesubstituter.php @@ -36,12 +36,12 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class qtype_calculated_variable_substituter_test extends UnitTestCase { - public function test_simple_equation() { + public function test_simple_expression() { $vs = new qtype_calculated_variable_substituter(array('a' => 1, 'b' => 2)); $this->assertEqual(3, $vs->calculate('{a} + {b}')); } - public function test_simple_equation_negatives() { + public function test_simple_expression_negatives() { $vs = new qtype_calculated_variable_substituter(array('a' => -1, 'b' => -2)); $this->assertEqual(1, $vs->calculate('{a}-{b}')); } @@ -50,4 +50,11 @@ public function test_cannot_use_nonnumbers() { $this->expectException(); $vs = new qtype_calculated_variable_substituter(array('a' => 'frog', 'b' => -2)); } + + public function test_invalid_expression() { + $this->expectException(); + $vs = new qtype_calculated_variable_substituter(array('a' => 1, 'b' => 2)); + $vs->calculate('{a} + {b}?'); + } + }