From f62ab50109a41ba8a3a2905a6742c7d3fbe2bf35 Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Tue, 9 Apr 2019 03:13:57 +0200 Subject: [PATCH] MDL-65308 core: change a couple of unsafe preg_quote() cases With PHP 7.3, the hash (#) is being escaped by preg_quote(). While normally that doesnt have much impact and normal operations continue working perfectly... when the results of the function are used to match against the same string... they don't match anymore. Have found a couple of there double-uses in core and this commit fixes them. Covered with tests. --- backup/util/helper/restore_log_rule.class.php | 4 ++-- .../util/helper/tests/restore_log_rule_test.php | 16 ++++++++++++++++ mod/lesson/pagetypes/shortanswer.php | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/backup/util/helper/restore_log_rule.class.php b/backup/util/helper/restore_log_rule.class.php index 6e182c019b1..9d3f61310c5 100644 --- a/backup/util/helper/restore_log_rule.class.php +++ b/backup/util/helper/restore_log_rule.class.php @@ -238,12 +238,12 @@ class restore_log_rule implements processable { protected function build_regexp($expression, $tokens) { // Replace to temp (and preg_quote() safe) placeholders foreach ($tokens as $token) { - $expression = preg_replace('~' . preg_quote($token, '~') . '~', '#@@#@@#', $expression, 1); + $expression = preg_replace('~' . preg_quote($token, '~') . '~', '%@@%@@%', $expression, 1); } // quote the expression $expression = preg_quote($expression, '~'); // Replace all the placeholders - $expression = preg_replace('~#@@#@@#~', '(.*)', $expression); + $expression = preg_replace('~%@@%@@%~', '(.*)', $expression); return '~' . $expression . '~'; } } diff --git a/backup/util/helper/tests/restore_log_rule_test.php b/backup/util/helper/tests/restore_log_rule_test.php index 03d016b0216..24d549bf134 100644 --- a/backup/util/helper/tests/restore_log_rule_test.php +++ b/backup/util/helper/tests/restore_log_rule_test.php @@ -49,4 +49,20 @@ class backup_restore_log_rule_testcase extends basic_testcase { // But the original log has been kept unmodified by the process() call. $this->assertEquals($originallog, $log); } + + public function test_build_regexp() { + $original = 'Any (string) with [placeholders] like {this} and {this}. [end].'; + $expectation = '~Any \(string\) with (.*) like (.*) and (.*)\. (.*)\.~'; + + $lr = new restore_log_rule('this', 'doesnt', 'matter', 'here'); + $class = new ReflectionClass('restore_log_rule'); + + $method = $class->getMethod('extract_tokens'); + $method->setAccessible(true); + $tokens = $method->invoke($lr, $original); + + $method = $class->getMethod('build_regexp'); + $method->setAccessible(true); + $this->assertSame($expectation, $method->invoke($lr, $original, $tokens)); + } } diff --git a/mod/lesson/pagetypes/shortanswer.php b/mod/lesson/pagetypes/shortanswer.php index 6f6d6b9d6b6..4b23f65dd9b 100644 --- a/mod/lesson/pagetypes/shortanswer.php +++ b/mod/lesson/pagetypes/shortanswer.php @@ -103,9 +103,9 @@ class lesson_page_type_shortanswer extends lesson_page { $ignorecase = 'i'; } } else { - $expectedanswer = str_replace('*', '#####', $expectedanswer); + $expectedanswer = str_replace('*', '%@@%@@%', $expectedanswer); $expectedanswer = preg_quote($expectedanswer, '/'); - $expectedanswer = str_replace('#####', '.*', $expectedanswer); + $expectedanswer = str_replace('%@@%@@%', '.*', $expectedanswer); } // see if user typed in any of the correct answers if ((!$this->lesson->custom && $this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) or ($this->lesson->custom && $answer->score > 0) ) {