Skip to content

Commit 2007d64

Browse files
authored
[Debug] Improve keyword highlighting and escaping of query strings
* Sort highlighted keywords alphabetically. * Add new composite keywords. * Deconstruct composite keywords. * Add basic test for query highlighting in toolbar. * Ignore keywords in string values of queries. * Use generic table and column names for tests. * Add credits for regex pattern. * Escape HTML entities when formatting query string. * Use esc() for escaping query string.
1 parent 0045a6f commit 2007d64

2 files changed

Lines changed: 63 additions & 23 deletions

File tree

system/Database/Query.php

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -367,46 +367,53 @@ public function debugToolbarDisplay(): string
367367
{
368368
// Key words we want bolded
369369
static $highlight = [
370-
'SELECT',
371-
'DISTINCT',
372-
'FROM',
373-
'WHERE',
374370
'AND',
375-
'LEFT JOIN',
376-
'RIGHT JOIN',
377-
'JOIN',
378-
'ORDER BY',
371+
'AS',
379372
'ASC',
373+
'AVG',
374+
'BY',
375+
'COUNT',
380376
'DESC',
381-
'GROUP BY',
382-
'LIMIT',
383-
'INSERT',
384-
'INTO',
385-
'VALUES',
386-
'UPDATE',
387-
'OR',
377+
'DISTINCT',
378+
'FROM',
379+
'GROUP',
388380
'HAVING',
389-
'OFFSET',
390-
'NOT IN',
391381
'IN',
382+
'INNER',
383+
'INSERT',
384+
'INTO',
385+
'IS',
386+
'JOIN',
387+
'LEFT',
392388
'LIKE',
393-
'NOT LIKE',
394-
'COUNT',
389+
'LIMIT',
395390
'MAX',
396391
'MIN',
392+
'NOT',
393+
'NULL',
394+
'OFFSET',
397395
'ON',
398-
'AS',
399-
'AVG',
396+
'OR',
397+
'ORDER',
398+
'RIGHT',
399+
'SELECT',
400400
'SUM',
401+
'UPDATE',
402+
'VALUES',
403+
'WHERE',
401404
];
402405

403406
if (empty($this->finalQueryString)) {
404407
$this->compileBinds(); // @codeCoverageIgnore
405408
}
406409

407-
$sql = $this->finalQueryString;
410+
$sql = esc($this->finalQueryString);
408411

409-
$search = '/\b(?:' . implode('|', $highlight) . ')\b/';
412+
/**
413+
* @see https://stackoverflow.com/a/20767160
414+
* @see https://regex101.com/r/hUlrGN/4
415+
*/
416+
$search = '/\b(?:' . implode('|', $highlight) . ')\b(?![^(')]*'(?:(?:[^(')]*'){2})*[^(')]*$)/';
410417

411418
return preg_replace_callback($search, static function ($matches) {
412419
return '<strong>' . str_replace(' ', '&nbsp;', $matches[0]) . '</strong>';

tests/system/Database/BaseQueryTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,4 +363,37 @@ public function testSetQueryBinds()
363363

364364
$this->assertSame($expected, $query->getQuery());
365365
}
366+
367+
public function queryKeywords()
368+
{
369+
return [
370+
'highlightKeyWords' => [
371+
'<strong>SELECT</strong> `a`.*, `b`.`id` <strong>AS</strong> `b_id` <strong>FROM</strong> `a` <strong>LEFT</strong> <strong>JOIN</strong> `b` <strong>ON</strong> `b`.`a_id` = `a`.`id` <strong>WHERE</strong> `b`.`id` <strong>IN</strong> (&#039;1&#039;) <strong>AND</strong> `a`.`deleted_at` <strong>IS</strong> <strong>NOT</strong> <strong>NULL</strong> <strong>LIMIT</strong> 1',
372+
'SELECT `a`.*, `b`.`id` AS `b_id` FROM `a` LEFT JOIN `b` ON `b`.`a_id` = `a`.`id` WHERE `b`.`id` IN (\'1\') AND `a`.`deleted_at` IS NOT NULL LIMIT 1',
373+
],
374+
'ignoreKeyWordsInValues' => [
375+
'<strong>SELECT</strong> * <strong>FROM</strong> `a` <strong>WHERE</strong> `a`.`col` = &#039;SELECT escaped keyword in value&#039; <strong>LIMIT</strong> 1',
376+
'SELECT * FROM `a` WHERE `a`.`col` = \'SELECT escaped keyword in value\' LIMIT 1',
377+
],
378+
'escapeHtmlValues' => [
379+
'<strong>SELECT</strong> &#039;&lt;s&gt;&#039; <strong>FROM</strong> dual',
380+
'SELECT \'<s>\' FROM dual',
381+
],
382+
];
383+
}
384+
385+
/**
386+
* @dataProvider queryKeywords
387+
*
388+
* @param mixed $expected
389+
* @param mixed $sql
390+
*/
391+
public function testHighlightQueryKeywords($expected, $sql)
392+
{
393+
$query = new Query($this->db);
394+
$query->setQuery($sql);
395+
$query->getQuery();
396+
397+
$this->assertSame($expected, $query->debugToolbarDisplay());
398+
}
366399
}

0 commit comments

Comments
 (0)