new wrapper for LIKE expressions to streamline the fixes. We actually need to adjust them for different DBMS as well as SQLite2 not supporting escaping characters in LIKE statements (which is a reason why we think about dropping sqlite support completely).

git-svn-id: file:///svn/phpbb/trunk@7788 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
Meik Sievertsen 2007-06-23 12:16:20 +00:00
parent 1e2db705ca
commit 318418b0f2
18 changed files with 97 additions and 82 deletions

View file

@ -295,6 +295,7 @@ p a {
<li>[Fix] Correctly check permissions on the UCP subscription/bookmark pages (Bug #12595)</li> <li>[Fix] Correctly check permissions on the UCP subscription/bookmark pages (Bug #12595)</li>
<li>[Fix] Only convert non-orphaned PMs</li> <li>[Fix] Only convert non-orphaned PMs</li>
<li>[Fix] Fixed a few Postgres related errors (Bug #12587)</li> <li>[Fix] Fixed a few Postgres related errors (Bug #12587)</li>
<li>[Feature] New DBAL wrapper for LIKE expressions / sql_like_expression()</li>
</ul> </ul>

View file

@ -239,7 +239,7 @@ class acp_permission_roles
{ {
$sql = 'SELECT auth_option_id, auth_option $sql = 'SELECT auth_option_id, auth_option
FROM ' . ACL_OPTIONS_TABLE . " FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '{$permission_type}%' WHERE auth_option " . $db->sql_like_expression($permission_type . '%') . "
AND auth_option <> '{$permission_type}' AND auth_option <> '{$permission_type}'
ORDER BY auth_option_id"; ORDER BY auth_option_id";
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
@ -305,7 +305,7 @@ class acp_permission_roles
// We need to fill the auth options array with ACL_NO options ;) // We need to fill the auth options array with ACL_NO options ;)
$sql = 'SELECT auth_option_id, auth_option $sql = 'SELECT auth_option_id, auth_option
FROM ' . ACL_OPTIONS_TABLE . " FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '{$permission_type}%' WHERE auth_option " . $db->sql_like_expression($permission_type . '%') . "
AND auth_option <> '{$permission_type}' AND auth_option <> '{$permission_type}'
ORDER BY auth_option_id"; ORDER BY auth_option_id";
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
@ -490,7 +490,7 @@ class acp_permission_roles
// Get complete auth array // Get complete auth array
$sql = 'SELECT auth_option, auth_option_id $sql = 'SELECT auth_option, auth_option_id
FROM ' . ACL_OPTIONS_TABLE . " FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '" . $db->sql_escape($permission_type) . "%'"; WHERE auth_option " . $db->sql_like_expression($permission_type . '%');
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$auth_settings = array(); $auth_settings = array();

View file

@ -1069,8 +1069,8 @@ class acp_permissions
global $db, $user; global $db, $user;
$sql_forum_id = ($permission_scope == 'global') ? 'AND a.forum_id = 0' : ((sizeof($forum_id)) ? 'AND ' . $db->sql_in_set('a.forum_id', $forum_id) : 'AND a.forum_id <> 0'); $sql_forum_id = ($permission_scope == 'global') ? 'AND a.forum_id = 0' : ((sizeof($forum_id)) ? 'AND ' . $db->sql_in_set('a.forum_id', $forum_id) : 'AND a.forum_id <> 0');
$sql_permission_option = "AND o.auth_option LIKE '" . $db->sql_escape($permission_type) . "%'"; $sql_permission_option = ' AND o.auth_option ' . $db->sql_like_expression($permission_type . '%');
$sql = $db->sql_build_query('SELECT_DISTINCT', array( $sql = $db->sql_build_query('SELECT_DISTINCT', array(
'SELECT' => 'u.username, u.username_clean, u.user_regdate, u.user_id', 'SELECT' => 'u.username, u.username_clean, u.user_regdate, u.user_id',

View file

@ -393,8 +393,8 @@ class acp_prune
$sort_by_types = array('username', 'user_email', 'user_posts', 'user_regdate', 'user_lastvisit'); $sort_by_types = array('username', 'user_email', 'user_posts', 'user_regdate', 'user_lastvisit');
$where_sql = ''; $where_sql = '';
$where_sql .= ($username) ? " AND username_clean LIKE '" . $db->sql_escape(str_replace('*', '%', utf8_clean_string($username))) . "'" : ''; $where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', '%', utf8_clean_string($username))) : '';
$where_sql .= ($email) ? " AND user_email LIKE '" . $db->sql_escape(str_replace('*', '%', $email)) . "' " : ''; $where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', '%', $email)) . ' ' : '';
$where_sql .= (sizeof($joined)) ? " AND user_regdate " . $key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]) : ''; $where_sql .= (sizeof($joined)) ? " AND user_regdate " . $key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]) : '';
$where_sql .= ($count !== '') ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : ''; $where_sql .= ($count !== '') ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : '';
$where_sql .= (sizeof($active)) ? " AND user_lastvisit " . $key_match[$active_select] . " " . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) : ''; $where_sql .= (sizeof($active)) ? " AND user_lastvisit " . $key_match[$active_select] . " " . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) : '';

View file

@ -1830,15 +1830,9 @@ class acp_users
{ {
// Select auth options // Select auth options
$sql = 'SELECT auth_option, is_local, is_global $sql = 'SELECT auth_option, is_local, is_global
FROM ' . ACL_OPTIONS_TABLE . " FROM ' . ACL_OPTIONS_TABLE . '
WHERE auth_option LIKE '%" . $db->sql_escape('\_') . "'"; WHERE auth_option ' . $db->sql_like_expression('%_') . '
AND is_global = 1
if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc')
{
$sql .= " ESCAPE '\\' ";
}
$sql .= 'AND is_global = 1
ORDER BY auth_option'; ORDER BY auth_option';
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
@ -1857,15 +1851,9 @@ class acp_users
{ {
$sql = 'SELECT auth_option, is_local, is_global $sql = 'SELECT auth_option, is_local, is_global
FROM ' . ACL_OPTIONS_TABLE . " FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '%" . $db->sql_escape('\_') . "'"; WHERE auth_option " . $db->sql_like_expression('%_') . "
AND is_local = 1
if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ORDER BY is_global DESC, auth_option";
{
$sql .= " ESCAPE '\\' ";
}
$sql .= 'AND is_local = 1
ORDER BY is_global DESC, auth_option';
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result)) while ($row = $db->sql_fetchrow($result))

View file

@ -966,20 +966,9 @@ class auth_admin extends auth
if ($permission_type !== false) if ($permission_type !== false)
{ {
// Get permission type // Get permission type
if ($db->sql_layer == 'sqlite') $sql = 'SELECT auth_option, auth_option_id
{ FROM ' . ACL_OPTIONS_TABLE . "
$sql = 'SELECT auth_option, auth_option_id WHERE auth_option " . $db->sql_like_expression($permission_type . '%');
FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '" . $db->sql_escape($permission_type) . "%'";
}
else
{
$sql = 'SELECT auth_option, auth_option_id
FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option LIKE '" . $db->sql_escape(str_replace('_', "\_", $permission_type)) . "%'";
$sql .= ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : '';
}
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$auth_id_ary = array(); $auth_id_ary = array();

View file

@ -842,15 +842,7 @@ class auth
{ {
if (strpos($auth_options, '%') !== false) if (strpos($auth_options, '%') !== false)
{ {
if (strpos($auth_options, '_') !== false && $db->sql_layer !== 'sqlite') $sql_opts = "AND $key " . $db->sql_like_expression($auth_options);
{
$sql_opts = "AND $key LIKE '" . $db->sql_escape(str_replace('_', "\_", $auth_options)) . "'";
$sql_opts .= ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\' " : '';
}
else
{
$sql_opts = "AND $key LIKE '" . $db->sql_escape($auth_options) . "'";
}
} }
else else
{ {
@ -881,16 +873,7 @@ class auth
{ {
if (strpos($option, '%') !== false) if (strpos($option, '%') !== false)
{ {
if (strpos($option, '_') !== false && $db->sql_layer !== 'sqlite') $sql[] = $key . ' ' . $db->sql_like_expression($option);
{
$_sql = $key . " LIKE '" . $db->sql_escape(str_replace('_', "\_", $option)) . "'";
$_sql .= ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : '';
$sql[] = $_sql;
}
else
{
$sql[] = $key . " LIKE '" . $db->sql_escape($option) . "'";
}
} }
else else
{ {

View file

@ -191,6 +191,21 @@ class dbal
return false; return false;
} }
/**
* Correctly adjust LIKE expression for special characters
* Some DBMS are handling them in a different way we need to take into account
*/
function sql_like_expression($expression)
{
// Standard for most DBMS
if (strpos($expression, '_') === false)
{
return 'LIKE \'' . $this->sql_escape($expression) . '\'';
}
return 'LIKE \'' . $this->sql_escape(str_replace('_', "\_", $expression)) . '\'';
}
/** /**
* SQL Transaction * SQL Transaction
* @access private * @access private

View file

@ -308,6 +308,22 @@ class dbal_mssql extends dbal
return str_replace("'", "''", $msg); return str_replace("'", "''", $msg);
} }
/**
* Correctly adjust LIKE expression for special characters
* MSSQL needs an escape character being defined
*/
function sql_like_expression($expression)
{
// Standard for most DBMS
if (strpos($expression, '_') === false)
{
return 'LIKE \'' . $this->sql_escape($expression) . '\'';
}
// sql_like_expression is only allowed directly within single quotes (to ease the use of it), therefore the special writing of ESCAPE below
return 'LIKE \'' . $this->sql_escape(str_replace('_', "\_", $expression)) . "' ESCAPE '\\'";
}
/** /**
* return sql error array * return sql error array
* @access private * @access private

View file

@ -319,6 +319,22 @@ class dbal_mssql_odbc extends dbal
return str_replace("'", "''", $msg); return str_replace("'", "''", $msg);
} }
/**
* Correctly adjust LIKE expression for special characters
* MSSQL needs an escape character being defined
*/
function sql_like_expression($expression)
{
// Standard for most DBMS
if (strpos($expression, '_') === false)
{
return 'LIKE \'' . $this->sql_escape($expression) . '\'';
}
// sql_like_expression is only allowed directly within single quotes (to ease the use of it), therefore the special writing of ESCAPE below
return 'LIKE \'' . $this->sql_escape(str_replace('_', "\_", $expression)) . "' ESCAPE '\\'";
}
/** /**
* Build db-specific query data * Build db-specific query data
* @access private * @access private

View file

@ -241,6 +241,20 @@ class dbal_sqlite extends dbal
return @sqlite_escape_string($msg); return @sqlite_escape_string($msg);
} }
/**
* Correctly adjust LIKE expression for special characters
* For SQLite an underscore is a not-known character... this may change with SQLite3
*/
function sql_like_expression($expression)
{
if (strpos($expression, '_') === false)
{
return "LIKE '" . $this->sql_escape($expression) . "'";
}
return "GLOB '" . $this->sql_escape(str_replace('%', '*', $expression)) . "'";
}
/** /**
* return sql error array * return sql error array
* @access private * @access private

View file

@ -3877,14 +3877,7 @@ function page_header($page_title = '', $display_online_list = true)
{ {
$f = request_var('f', 0); $f = request_var('f', 0);
// Do not change this (it is defined as _f_={forum_id}x within session.php) $reading_sql = ' AND s.session_page ' . $db->sql_like_expression("%_f_={$f}x%");
$reading_sql = " AND s.session_page LIKE '%" . $db->sql_escape("\_f\_={$f}x") . "%'";
// Specify escape character for MSSQL
if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc')
{
$reading_sql .= " ESCAPE '\\' ";
}
} }
// Get number of online guests // Get number of online guests

View file

@ -2206,8 +2206,7 @@ function cache_moderators()
AND a.group_id = ug.group_id AND a.group_id = ug.group_id
AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . "
AND ug.user_pending = 0 AND ug.user_pending = 0
AND o.auth_option LIKE '" . $db->sql_escape('m\_') . "%'" . AND o.auth_option " . $db->sql_like_expression('m_%'),
(($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''),
)); ));
$result = $db->sql_query($sql); $result = $db->sql_query($sql);

View file

@ -273,7 +273,7 @@ class search_backend
$sql_where = ''; $sql_where = '';
foreach ($words as $word) foreach ($words as $word)
{ {
$sql_where .= ' OR search_keywords LIKE \'%' . $db->sql_escape($word) . '%\''; $sql_where .= " OR search_keywords " . $db->sql_like_expression('%' . $word . '%');
} }
$sql = 'SELECT search_key $sql = 'SELECT search_key

View file

@ -226,7 +226,7 @@ class template
FROM ' . STYLES_TEMPLATE_DATA_TABLE . ' FROM ' . STYLES_TEMPLATE_DATA_TABLE . '
WHERE template_id = ' . $user->theme['template_id'] . " WHERE template_id = ' . $user->theme['template_id'] . "
AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "' AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "'
OR template_included LIKE '%" . $db->sql_escape($this->filename[$handle]) . ":%')"; OR template_included " . $db->sql_like_expression('%' . $this->filename[$handle] . ':%') . ')';
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result); $row = $db->sql_fetchrow($result);

View file

@ -31,7 +31,7 @@ unset($dbpasswd);
*/ */
$convertor_data = array( $convertor_data = array(
'forum_name' => 'phpBB 2.0.x', 'forum_name' => 'phpBB 2.0.x',
'version' => '1.0.RC2-dev', 'version' => '1.0.RC2',
'phpbb_version' => '3.0.0', 'phpbb_version' => '3.0.0',
'author' => '<a href="http://www.phpbb.com/">phpBB Group</a>', 'author' => '<a href="http://www.phpbb.com/">phpBB Group</a>',
'dbms' => $dbms, 'dbms' => $dbms,

View file

@ -934,13 +934,13 @@ switch ($mode)
$s_find_active_time .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>'; $s_find_active_time .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
} }
$sql_where .= ($username) ? " AND u.username_clean LIKE '" . str_replace('*', '%', $db->sql_escape(utf8_clean_string($username))) . "'" : ''; $sql_where .= ($username) ? ' AND u.username_clean ' . $db->sql_like_expression(str_replace('*', '%', utf8_clean_string($username))) : '';
$sql_where .= ($email) ? " AND u.user_email LIKE '" . str_replace('*', '%', $db->sql_escape($email)) . "' " : ''; $sql_where .= ($email) ? ' AND u.user_email ' . $db->sql_like_expression(str_replace('*', '%', $email)) . ' ' : '';
$sql_where .= ($icq) ? " AND u.user_icq LIKE '" . str_replace('*', '%', $db->sql_escape($icq)) . "' " : ''; $sql_where .= ($icq) ? ' AND u.user_icq ' . $db->sql_like_expression(str_replace('*', '%', $icq)) . ' ' : '';
$sql_where .= ($aim) ? " AND u.user_aim LIKE '" . str_replace('*', '%', $db->sql_escape($aim)) . "' " : ''; $sql_where .= ($aim) ? ' AND u.user_aim ' . $db->sql_like_expression(str_replace('*', '%', $aim)) . ' ' : '';
$sql_where .= ($yahoo) ? " AND u.user_yim LIKE '" . str_replace('*', '%', $db->sql_escape($yahoo)) . "' " : ''; $sql_where .= ($yahoo) ? ' AND u.user_yim ' . $db->sql_like_expression(str_replace('*', '%', $yahoo)) . ' ' : '';
$sql_where .= ($msn) ? " AND u.user_msnm LIKE '" . str_replace('*', '%', $db->sql_escape($msn)) . "' " : ''; $sql_where .= ($msn) ? ' AND u.user_msnm ' . $db->sql_like_expression(str_replace('*', '%', $msn)) . ' ' : '';
$sql_where .= ($jabber) ? " AND u.user_jabber LIKE '" . str_replace('*', '%', $db->sql_escape($jabber)) . "' " : ''; $sql_where .= ($jabber) ? ' AND u.user_jabber ' . $db->sql_like_expression(str_replace('*', '%', $jabber)) . ' ' : '';
$sql_where .= (is_numeric($count)) ? ' AND u.user_posts ' . $find_key_match[$count_select] . ' ' . (int) $count . ' ' : ''; $sql_where .= (is_numeric($count)) ? ' AND u.user_posts ' . $find_key_match[$count_select] . ' ' . (int) $count . ' ' : '';
$sql_where .= (sizeof($joined) > 1) ? " AND u.user_regdate " . $find_key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, intval($joined[1]), intval($joined[2]), intval($joined[0])) : ''; $sql_where .= (sizeof($joined) > 1) ? " AND u.user_regdate " . $find_key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, intval($joined[1]), intval($joined[2]), intval($joined[0])) : '';
$sql_where .= (sizeof($active) > 1) ? " AND u.user_lastvisit " . $find_key_match[$active_select] . ' ' . gmmktime(0, 0, 0, $active[1], intval($active[2]), intval($active[0])) : ''; $sql_where .= (sizeof($active) > 1) ? " AND u.user_lastvisit " . $find_key_match[$active_select] . ' ' . gmmktime(0, 0, 0, $active[1], intval($active[2]), intval($active[0])) : '';
@ -1015,12 +1015,12 @@ switch ($mode)
{ {
for ($i = 97; $i < 123; $i++) for ($i = 97; $i < 123; $i++)
{ {
$sql_where .= " AND u.username_clean NOT LIKE '" . chr($i) . "%'"; $sql_where .= ' AND u.username_clean NOT ' . $db->sql_like_expression(chr($i) . '%');
} }
} }
else if ($first_char) else if ($first_char)
{ {
$sql_where .= " AND u.username_clean LIKE '" . $db->sql_escape(substr($first_char, 0, 1)) . "%'"; $sql_where .= ' AND u.username_clean ' . $db->sql_like_expression(substr($first_char, 0, 1) . '%');
} }
// Are we looking at a usergroup? If so, fetch additional info // Are we looking at a usergroup? If so, fetch additional info

View file

@ -100,10 +100,11 @@ if ($keywords || $author || $author_id || $search_id || $submit)
trigger_error(sprintf($user->lang['TOO_FEW_AUTHOR_CHARS'], $config['min_search_author_chars'])); trigger_error(sprintf($user->lang['TOO_FEW_AUTHOR_CHARS'], $config['min_search_author_chars']));
} }
$sql_where = (strpos($author, '*') !== false) ? ' LIKE ' : ' = '; $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', '%', utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
$sql = 'SELECT user_id $sql = 'SELECT user_id
FROM ' . USERS_TABLE . " FROM ' . USERS_TABLE . "
WHERE username_clean $sql_where '" . $db->sql_escape(preg_replace('#\*+#', '%', utf8_clean_string($author))) . "' WHERE $sql_where
AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')';
$result = $db->sql_query_limit($sql, 100); $result = $db->sql_query_limit($sql, 100);