From ed63f7f883af8030b2670476c51d56d99856385b Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sat, 12 May 2012 16:40:11 +0200 Subject: [PATCH] MDL-32907 prevent sql_like() backslash quoting problems in PostgreSQL --- lib/dml/pgsql_native_moodle_database.php | 8 ++++++-- lib/dml/tests/dml_test.php | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/dml/pgsql_native_moodle_database.php b/lib/dml/pgsql_native_moodle_database.php index 31bf35304cae9..57a007a9cd773 100644 --- a/lib/dml/pgsql_native_moodle_database.php +++ b/lib/dml/pgsql_native_moodle_database.php @@ -1118,7 +1118,11 @@ public function sql_like($fieldname, $param, $casesensitive = true, $accentsensi if (strpos($param, '%') !== false) { debugging('Potential SQL injection detected, sql_like() expects bound parameters (? or :named)'); } - $escapechar = pg_escape_string($this->pgsql, $escapechar); // prevents problems with C-style escapes of enclosing '\' + if ($escapechar === '\\') { + // Prevents problems with C-style escapes of enclosing '\', + // E'... bellow prevents compatibility warnings. + $escapechar = '\\\\'; + } // postgresql does not support accent insensitive text comparisons, sorry if ($casesensitive) { @@ -1126,7 +1130,7 @@ public function sql_like($fieldname, $param, $casesensitive = true, $accentsensi } else { $LIKE = $notlike ? 'NOT ILIKE' : 'ILIKE'; } - return "$fieldname $LIKE $param ESCAPE '$escapechar'"; + return "$fieldname $LIKE $param ESCAPE E'$escapechar'"; } public function sql_bitxor($int1, $int2) { diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index e91dbdf5b1a87..0ef6eca624dd8 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -3512,6 +3512,14 @@ function test_sql_like() { $records = $DB->get_records_sql($sql, array("%D%")); $this->assertEquals(count($records), 6); + // verify usual escaping characters work fine + $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, false, '\\'); + $records = $DB->get_records_sql($sql, array("ouc\\_")); + $this->assertEquals(count($records), 1); + $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, false, '|'); + $records = $DB->get_records_sql($sql, array("ouc|%")); + $this->assertEquals(count($records), 1); + // TODO: we do not require accent insensitivness yet, just make sure it does not throw errors $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, false); $records = $DB->get_records_sql($sql, array('aui'));