* be present. */ require_once '../../../config.php'; require_once "{$CFG->dirroot}/question/type/algebra/parser.php"; $p = new qtype_algebra_parser(); try { $query = urldecode($_SERVER['QUERY_STRING']); $m = array(); if (!preg_match('/vars=([^&]*)&expr=(.*)$/A', $query, $m)) { throw new Exception('Invalid query string received from http server!'); } $vars = explode(',', $m[1]); if (empty($m[2])) { $texexp = ''; } else { $exp = $p->parse($m[2], $vars); $texexp = '$$' . $exp->tex() . '$$'; } } catch (Exception $e) { $texexp = get_string('parseerror', 'qtype_algebra', $e->getMessage()); } $text = format_text($texexp); ?> <html> <head> <title>Formula</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> </head> <body bgcolor="#FFFFFF"> <?php echo $text;
/** * Parses the given expression with the parser if required. * * This method will check to see if the argument it is given is already a parsed * expression and if not will attempt to parse it. * * @param $expr expression which will be parsed * @param $question question containing the expression or null if none * @return top term of the parse tree or a string if an exception is thrown */ function parse_expression($expr, &$question = null) { // Check to see if this is already a parsed expression if (is_a($expr, 'qtype_algebra_parser_term')) { // It is a parsed expression so simply return it return $expr; } // Check whether we have a state object or a simple string. If a state // then replace it with the response string if (isset($expr->responses[''])) { $expr = $expr->responses['']; } // Create an array of variable names for the parser from the question if defined $varnames = array(); if ($question and isset($question->options->variables)) { foreach ($question->options->variables as $var) { $varnames[] = $var->name; } } // We now assume that we have a string to parse. Create a parser instance to // to this and return the parser expression at the top of the parse tree $p = new qtype_algebra_parser(); // Perform the actual parsing inside a try-catch block so that any exceptions // can be caught and converted into errors try { return $p->parse($expr, $varnames); } catch (Exception $e) { // If the expression cannot be parsed then return a null term. This will // make Moodle treat the answer as wrong. // TODO: Would be nice to have support for 'invalid answer' in the quiz // engine since an unparseable response is usually caused by a silly typo return new qtype_algebra_parser_nullterm(); } }
/** * Validates the form data ensuring there are no obvious errors in the submitted data. * * This method performs some basic sanity checks on the form data before it gets converted * into a database record. * * @param $data the data from the form which needs to be checked * @param $files some files - I don't know what this is for! - files defined in the form?? */ function validation($data, $files) { // Call the base class validation method and keep any errors it generates $errors = parent::validation($data, $files); // Regular expression string to match a number $renumber = '/([+-]*(([0-9]+\\.[0-9]*)|([0-9]+)|(\\.[0-9]+))|' . '(([0-9]+\\.[0-9]*)|([0-9]+)|(\\.[0-9]+))E([-+]?\\d+))/A'; // Perform sanity checks on the variables. $vars = $data['variable']; // Create an array of defined variables $varlist = array(); foreach ($vars as $key => $var) { $trimvar = trim($var); $trimmin = trim($data['varmin'][$key]); $trimmax = trim($data['varmax'][$key]); // Check that there is a valid variable name otherwise skip if ($trimvar == '') { continue; } // Check that this variable does not have the same name as a function if (in_array($trimvar, qtype_algebra_parser::$functions) or in_array($trimvar, qtype_algebra_parser::$specials)) { $errors['variable[' . $key . ']'] = get_string('illegalvarname', 'qtype_algebra', $trimvar); } // Check that this variable has not been defined before if (in_array($trimvar, $varlist)) { $errors['variable[' . $key . ']'] = get_string('duplicatevar', 'qtype_algebra'); } else { // Add the variable to the list of defined variables $varlist[] = $trimvar; } // If the comparison algorithm selected is evaluate then ensure that each variable // has a valid minimum and maximum defined. For the other types of comparison we can // ignore the range if ($data['compareby'] == 'eval') { // Check that a minimum has been defined if ($trimmin == '') { $errors['varmin[' . $key . ']'] = get_string('novarmin', 'qtype_algebra'); } else { if (!preg_match($renumber, $trimmin)) { $errors['varmin[' . $key . ']'] = get_string('notanumber', 'qtype_algebra'); } } if ($trimmax == '') { $errors['varmax[' . $key . ']'] = get_string('novarmax', 'qtype_algebra'); } else { if (!preg_match($renumber, $trimmax)) { $errors['varmax[' . $key . ']'] = get_string('notanumber', 'qtype_algebra'); } } // Check that the minimum is less that the maximum! if ((double) $trimmin > (double) $trimmax) { $errors['varmin[' . $key . ']'] = get_string('varmingtmax', 'qtype_algebra'); } } // end check for eval type } // end loop over variables // Check that at least one variable is defined if (count($varlist) == 0) { $errors['variable[0]'] = get_string('notenoughvars', 'qtype_algebra'); } // Now perform the sanity checks on the answers // Create a parser which we will use to check that the answers are understandable $p = new qtype_algebra_parser(); $answers = $data['answer']; $answercount = 0; $maxgrade = false; // Create an empty array to store the used variables $ansvars = array(); // Create an empty array to store the used functions $ansfuncs = array(); // Loop over all the answers in the form foreach ($answers as $key => $answer) { // Try to parse the answer string using the parser. If this fails it will // throw an exception which we catch to generate the associated error string // for the expression try { $expr = $p->parse($answer); // Add any new variables to the list we are keeping. First we get the list // of variables in this answer. Then we get the array of variables which are // in this answer that are not in any previous answer (using array_diff). // Finally we merge this difference array with the list of all variables so far $tmpvars = $expr->get_variables(); $ansvars = array_merge($ansvars, array_diff($tmpvars, $ansvars)); // Check that all the variables in this answer have been declared // Do this by looking for a non-empty array to be returned from the array_diff // between the list of all declared variables and the variables in this answer if ($d = array_diff($tmpvars, $varlist)) { $errors['answer[' . $key . ']'] = get_string('undefinedvar', 'qtype_algebra', "'" . implode("', '", $d) . "'"); } // Do the same for functions which we did for variables $ansfuncs = array_merge($ansfuncs, array_diff($expr->get_functions(), $ansfuncs)); // Check that this is not an empty answer if (!is_a($expr, "qtype_algebra_parser_nullterm")) { // Increase the number of answers $answercount++; // Check to see if the answer has the maximum grade if ($data['fraction'][$key] == 1) { $maxgrade = true; } } } catch (Exception $e) { $errors['answer[' . $key . ']'] = $e->getMessage(); // Return here because subsequent errors may be wrong due to not counting the answer // which just failed to parse return $errors; } } // Check that we have at least one answer! if ($answercount == 0) { $errors['answer[0]'] = get_string('notenoughanswers', 'quiz', 1); } // Check that at least one question has the maximum possible grade if ($maxgrade == false) { $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); } // Check for variables which are defined but never used. // Do this by looking for a non-empty array to be returned from array_diff. if ($d = array_diff($varlist, $ansvars)) { // Loop over all the variables in the form foreach ($vars as $key => $var) { $trimvar = trim($var); // If the variable is in the unused array then add the error message to that variable if (in_array($trimvar, $d)) { $errors['variable[' . $key . ']'] = get_string('unusedvar', 'qtype_algebra'); } } } // Check that the tolerance is greater than or equal to zero if ($data['tolerance'] < 0) { $errors['tolerance'] = get_string('toleranceltzero', 'qtype_algebra'); } return $errors; }