diff --git a/lang/en_utf8/debug.php b/lang/en_utf8/debug.php index 43f630bb504..3f7bf2b6f3c 100644 --- a/lang/en_utf8/debug.php +++ b/lang/en_utf8/debug.php @@ -15,6 +15,7 @@ $string['erroroccur'] = 'An error has occurred during this process'; $string['fixsetting'] = 'Please fix your settings in config.php: <p>You have:</p> <p>\$CFG->dirroot = \'$a->current\';</p> <p>but it should be:</p> <p>\$CFG->dirroot = \'$a->found\';</p>'; $string['invalideventdata'] = 'Incorrect eventadata submitted: $a'; $string['invalidarraysize'] = 'Incorrect size of arrays in params of $a'; +$string['invalidparameter'] = 'Invalid parameter value detected, execution can not continue.'; $string['missingconfigversion'] = 'Config table does not contain version, can not continue, sorry.'; $string['mustbeoveride'] = 'Abstract $a method must be overriden.'; $string['morethanonerecordinfetch'] = 'Found more than one record in fetch() !'; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index edf5400bbcc..ec7d6dc8771 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -374,6 +374,40 @@ function optional_param($parname, $default=NULL, $type=PARAM_CLEAN) { return clean_param($param, $type); } +/** + * Strict validation of parameter values, the values are only converted + * to requested PHP type. Internally it is using clean_param, the values + * before and after cleaning must be equal - otherwise + * an invalid_parameter_exception is thrown. + * Onjects and classes are not accepted. + * + * @param mixed $param + * @param int $type PARAM_ constant + * @param bool $allownull are nulls valid value? + * @param string $debuginfo optional debug information + * @return mixed the $param value converted to PHP type or invalid_parameter_exception + */ +function validate_param($param, $type, $allownull=true, $debuginfo='') { + if (is_null($param)) { + if ($allownull) { + return null; + } else { + throw new invalid_parameter_exception($debuginfo); + } + } + if (is_array($param) or is_object($param)) { + throw new invalid_parameter_exception($debuginfo); + } + + $cleaned = clean_param($param, $type); + if ((string)$param !== (string)$cleaned) { + // conversion to string is usually lossless + throw new invalid_parameter_exception($debuginfo); + } + + return $cleaned; +} + /** * Used by {@link optional_param()} and {@link required_param()} to * clean the variables and/or cast to specific types, based on diff --git a/lib/setuplib.php b/lib/setuplib.php index 791f3f28b9f..5f3a5db3ec9 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -121,6 +121,22 @@ class coding_exception extends moodle_exception { } } +/** + * Exception indicating malformed parameter problem. + * This exception is not supposed to be thrown when processing + * user submitted data in forms. It is more suitable + * for WS and other low level stuff. + */ +class invalid_parameter_exception extends moodle_exception { + /** + * Constructor + * @param string $debuginfo some detailed information + */ + function __construct($debuginfo=null) { + parent::__construct('invalidparameter', 'debug', '', null, $debuginfo); + } +} + /** * An exception that indicates something really weird happended. For example, * if you do switch ($context->contextlevel), and have one case for each diff --git a/lib/simpletest/testmoodlelib.php b/lib/simpletest/testmoodlelib.php index 76a7717cd98..af3384d8779 100644 --- a/lib/simpletest/testmoodlelib.php +++ b/lib/simpletest/testmoodlelib.php @@ -228,8 +228,7 @@ class moodlelib_test extends UnitTestCase { $this->assertEqual(array('gecko', 'gecko19'), get_browser_version_classes()); } - function test_optional_param() - { + function test_optional_param() { $_POST['username'] = 'post_user'; $_GET['username'] = 'get_user'; $this->assertEqual(optional_param('username', 'default_user', PARAM_CLEAN), 'post_user'); @@ -271,8 +270,7 @@ class moodlelib_test extends UnitTestCase { * @param int $type expected format of param after cleaning. * @return mixed */ - function test_clean_param() - { + function test_clean_param() { global $CFG; // Test unknown parameter type @@ -299,6 +297,45 @@ class moodlelib_test extends UnitTestCase { $this->assertEqual(clean_param('course/view.php?id=3', PARAM_LOCALURL), 'course/view.php?id=3'); } + function test_validate_param() { + try { + $param = validate_param('11a', PARAM_INT); + $this->fail('invalid_parameter_exception expected'); + } catch (invalid_parameter_exception $ex) { + $this->assertTrue(true); + } + try { + $param = validate_param('11', PARAM_INT); + $this->assertEqual($param, 11); + } catch (invalid_parameter_exception $ex) { + $this->fail('invalid_parameter_exception not expected'); + } + try { + $param = validate_param(null, PARAM_INT, false); + $this->fail('invalid_parameter_exception expected'); + } catch (invalid_parameter_exception $ex) { + $this->assertTrue(true); + } + try { + $param = validate_param(null, PARAM_INT, true); + $this->assertTrue($param===null); + } catch (invalid_parameter_exception $ex) { + $this->fail('invalid_parameter_exception expected'); + } + try { + $param = validate_param(array(), PARAM_INT); + $this->fail('invalid_parameter_exception expected'); + } catch (invalid_parameter_exception $ex) { + $this->assertTrue(true); + } + try { + $param = validate_param(new stdClass, PARAM_INT); + $this->fail('invalid_parameter_exception expected'); + } catch (invalid_parameter_exception $ex) { + $this->assertTrue(true); + } + } + function test_make_user_directory() { global $CFG;