2010-09-10 59 views
35

在我使用的旧服务器上,我无法使用准备好的语句,目前我正试图在将其发送到MySQL之前完全转义用户输入。 为此,我使用PHP函数mysql_real_escape_string转义MySQL通配符

由于这个函数不能逃脱MySQL通配符%和_我使用addcslashes来逃避这些。

当我送的东西,如:

test_test " ' 

到数据库,然后读出来的数据库显示:

test\_test " ' 

看着这个我不明白为什么_有前反斜杠,但是“和”不是 因为它们全都用\确实被转义了_'和“应该都是相同的,即所有的转义字符都是可见的或者全部不可见。

是转义\ S自动筛选出来

任何人都可以解释一下吗?

回答

79

_%在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声明中是特殊的,并且必须被转义。)

+4

我会再次为“该死的反斜杠!”+1。 – BoltClock 2010-09-10 10:30:35

+0

谢谢,现在只是吸收这个...这真的帮助我扩展我的基本知识。愚蠢的是,尽管我并没有使用任何LIKE语句,并且由于我认为(请确认)%和_在LIKE语句中是疯狂的,我实际上正在逃避%和_,实际上我正在浪费我的时间。但是,这让我想到你为什么要在LIKE语句的上下文中转义%或_。当然,使用LIKE语句的唯一原因是你可以使用它的通配符。 (请原谅我在这方面的有限知识) – Columbo 2010-09-10 11:06:05

+2

当然,但希望能够搜索文字'%'或'_'字符是非常自然的。如果用户在前端搜索'50%',那么他们可能意味着他们正在寻找一个包含'50%'的字符串,而不是任何含有'50'的字符串。 – bobince 2010-09-10 11:08:29