逃离MySQL通配符

时间:2010-09-10 10:04:37

标签: php mysql escaping

在我正在使用的旧服务器上,我无法使用预准备语句,我目前正在尝试完全转义用户输入,然后再将其发送到MySQL。 为此我使用PHP函数mysql_real_escape_string

由于此函数不会转义MySQL通配符%和_我也使用addcslashes来转义这些函数。

当我发送类似的东西时:

test_test " ' 

到数据库然后读回数据库显示:

test\_test " ' 

看着这个我无法理解为什么_有一个前面的反斜杠但是'和'没有。 因为它们全部都是\ _ \ _并且“所有都显示相同,即所有都有可见的转义字符或者都没有可见。

是否会自动屏蔽转义

任何人都能解释一下吗?

2 个答案:

答案 0 :(得分:87)

_%一般不是MySQL中的通配符,不应为了将它们放入普通的字符串文字而进行转义。 mysql_real_escape_string对于此目的是正确和充分的。不应使用addcslashes

_%仅在LIKE - 匹配的上下文中有特殊之处。如果要在LIKE语句中准备文字字符串使用,以便100%匹配百分之百而不仅仅是以百分之一开头的任何字符串,那么您有两个级别的转义需要担心

首先是LIKE逃避。 LIKE处理完全在SQL内部进行,如果要将文字字符串转换为文字LIKE表达式,即使使用参数化查询,也必须执行此步骤

在此计划中,_%是特殊的,必须进行转义。转义字符也必须转义。根据ANSI SQL,除了之外的字符不得转义:\'是错误的。 (虽然MySQL通常会让你逃脱它。)

完成此操作后,您将进入第二级转义,这是简单的旧字符串文字转义。这发生在SQL之外,创建SQL,因此必须在LIKE转义步骤之后完成。对于MySQL,这是mysql_real_escape_string和以前一样;对于其他数据库,将有一个不同的功能,你可以只使用参数化查询,以避免必须这样做。

导致混淆的问题是,在MySQL中,使用反斜杠作为两个嵌套转义步骤的转义字符!因此,如果您希望将字符串与文字百分号匹配,则必须使用双反斜杠转义并说LIKE 'something\\%'。或者,如果它在PHP "文字中,也使用反斜杠转义,"LIKE 'something\\\\%'"。哎呀!

根据ANSI SQL,这是不正确的,它说:在字符串文字中,反斜杠意味着字面反斜杠,并且转义单引号的方式是'';在LIKE表达式中,默认情况下根本没有转义字符。

因此,如果您希望以可移植的方式进行LIKE转义,则应使用LIKE ... ESCAPE ...构造覆盖默认(错误)行为并指定自己的转义字符。为了理智,我们会选择除了该死的反斜杠之外的东西!

function like($s, $e) {
    return str_replace(array($e, '_', '%'), array($e.$e, $e.'_', $e.'%'), $s);
}

$escapedname= mysql_real_escape_string(like($name, '='));
$query= "... WHERE name LIKE '%$escapedname%' ESCAPE '=' AND ...";

或带参数(例如PDO中):

$q= $db->prepare("... WHERE name LIKE ? ESCAPE '=' AND ...");
$q->bindValue(1, '%'.like($name, '=').'%', PDO::PARAM_STR);

(如果你想要更多的可移植性派对时间,你也可以尝试考虑MS SQL Server和Sybase,其中[字符在LIKE语句中也是错误的,特殊的必须逃脱。唉。)

答案 1 :(得分:0)

没想到这么多年没人提,但如果你不需要做复杂的通配符匹配(例如foo%baz),我认为INSTR/LOCATE/ POSITIONLEFTRIGHT 等应该足够了。在我的所有案例中,我只使用 LIKE 来匹配字符串中的任何位置(即 %foobar%),所以在所有关于转义 LIKE 模式的恐怖故事之后,我'我现在改用 INSTR

等价于 value LIKE '%foobar%'(匹配任何地方):

INSTR(value, 'foobar') > 0

等价于 value LIKE 'foobar%'(开始时匹配):

INSTR(value, 'foobar') = 1

等价于 value LIKE '%foobar'(匹配结束):

RIGHT(value, 6) = 'foobar'

它可能不是那么直接和容易记住,最后匹配的解决方案也许可以以某种方式改进以更加通用。但是这些替代方案至少应该让您在安全方面放心,因为它绕过了任何自卷转义的需要,并且不需要您更改实际参数值(无论如何使用准备好的语句时)。< /p>