忽略mysql搜索中的撇号

时间:2010-12-04 01:12:28

标签: php mysql select

我想要一个没有任何撇号,逗号或&符号的网址,并将其与可能包含其中一个字符的数据库中的记录匹配。

例如:

mywebsite.com/bobs-big-boy
mywebsite.com/tom--jerry
mywebsite.com/one-two-three

重写

index.php?name=bobs-big-boy
index.php?name=tom--jerry
index.php?name=bobs-big-boy

然后在php中我想使用$ _GET ['name']匹配记录

bob's big boy
tom & jerry
one, two, three

现在我的查询如下:

"SELECT * from the_records WHERE name=$NAME";

我无法更改记录,因为它们是商家名称。有没有办法可以编写查询来忽略数据库中的&符号,逗号和撇号?

4 个答案:

答案 0 :(得分:7)

是的,你可以,但我很确定它会忽略你在列上的任何索引。而且令人作呕。

这样的东西
SELECT * FROM the_records 
WHERE replace(replace(replace(name, '''', ''), ',', ''), '&', '') = $NAME

顺便提一下,像这样获取一个get变量并将它注入到mysql查询中对于sql注入来说已经很成熟了。

pg,我知道你说你无法更改/更新你选择的数据库中的内容,但有什么事情阻止你在另一个你有写入权限的数据库中制作一个表吗?您可以只为业务名称创建一个urlnames地图,并且在第一次执行replace方法时它只会很慢。

答案 1 :(得分:4)

问候,

这个花了几分钟才解决了!实际上有一些细节缺少你的要求,所以我试图用不同的假设解决问题,如下所述。

以下是来自URL的假定输入集,从您的示例中提取,以及MySQL注入攻击(仅用于咯咯笑),以及业务名称的变体。键是预期的URL,值是要匹配的数据库值。

<?php
$names = array(
  'bobs-big-boy'=>"bob's big boy",
  'tom--jerry'=>'tom & jerry',
  'tomjerry'=>'tom&jerry',
  'one-two-three'=>'one, two, three',
  'onetwothree'=>'one,two,three',
  "anything' OR 'haxor'='haxor"=>'die-haxor-die',
);
?>

最终运行mySQL缺少正则表达式替换的一种聪明方法是使用SOUNDEX,这种方法似乎主要适用于这种情况,具体取决于您需要的准确度,客户名称的密度和相似性等等。例如,这会为以上值生成soundex值:

$soundex_test = $names;
$select = 'SELECT ';
foreach ($soundex_test as $name=>$dbname) {
  echo '<p>'.$name.': '.soundex($name).' :: '.$dbname.': '.soundex($dbname).'</p>';
  $select .= sprintf("SOUNDEX('%s'),", $name);
}
echo '<pre>MySQL queries with attack -- '.print_r($select,1).'</pre>';

因此,假设没有名为“一,二,三”的客户和另一个名为“onetwothree”的客户,这种方法应该可以很好地运作。

要使用此方法,您的查询将如下所示:

$soundex_unclean = $names;
foreach ($soundex_unclean as $name=>$dbname) {
  $soundex_unclean[$name] = sprintf("SELECT * from the_records WHERE name SOUNDS LIKE '%s';", $name).' /* matches name field = ['.$dbname.'] */';
}
echo '<pre>MySQL queries with attack -- '.print_r(array_values($soundex_unclean),1).'</pre>';

然而,这是一个处理注入攻击的运行(注意新线)。我知道这不是问题的焦点,但是ajreal提到了这个问题,所以我想也要处理它:

$soundex_clean = $names;
foreach ($soundex_clean as $name=>$dbname) {
  // strip out everything but alpha-numerics and dashes
  $clean_name = preg_replace('/[^[:alnum:]-]/', '', $name);
  $soundex_unclean[$name] = sprintf("SELECT * from the_records WHERE name SOUNDS LIKE '%s';", $clean_name).' /* matches name field = ['.$dbname.'] */';
}
echo '<pre>MySQL queries with attack cleaned -- '.print_r($soundex_unclean,1).'</pre>';

如果这种方法不合适,并且您认为内联替换方法已足够,那么请记住在混音中添加逗号替换。作为这种方法的一个例子,我在这里假设单引号,双引号,&符号和逗号(即',“,&amp;和,,)是数据库中包含的唯一四个特殊字符,但是从URL,以及包含的任何其他非字母数字字符,转换为破折号(即 - )。

首先,一个不涉及注入攻击的运行:

$unclean = $names;
foreach ($unclean as $name=>$dbname) {
  $regex_name = preg_replace('/[-]+/', '[^[:alnum:]]+', $name);
  $unclean[$name] = sprintf("SELECT * from the_records WHERE REPLACE(REPLACE(REPLACE(REPLACE(name, ',', ''), '&', ''), '\"', ''), \"'\", '') REGEXP '%s'", $regex_name);
}
echo '<pre>MySQL queries with attack -- '.print_r($unclean,1).'</pre>';

其次,这是一场处理攻击的行动:

$clean = $names;
foreach ($clean as $name=>$dbname) {
  $regex_name = preg_replace('/[^[:alnum:]-]/', '', $name);
  $regex_name = preg_replace('/[-]+/', '[^[:alnum:]]+', $regex_name);
  $clean[$name] = sprintf("SELECT * from the_records WHERE REPLACE(REPLACE(REPLACE(REPLACE(name, ',', ''), '&', ''), '\"', ''), \"'\", '') REGEXP '%s'", $regex_name);
}
echo '<pre>MySQL queries with attack cleaned -- '.print_r($clean,1).'</pre>';

Aaaand这对我来说已经足够头脑风暴了一晚! = O)

答案 2 :(得分:0)

使用str_replace函数,我们将获取$ name参数并替换

ampersands (&) with "" 
spaces (" ") with "-"
commas (",") with ""
apostrophes("'") with ""
  

str_replace (混合$ search,混合$ replace,混合$ subject [,int&amp; $ count])

     

$ Search = {“&amp;”,“”,“,”,“”“}   $ Replace = {“”,“ - ”,“”,“”}

$ComparableString = str_replace($Search, $Replace, $_GET['name'])

之后我们可以执行sql查询:

$name = mysql_real_escape_string($name, $db_resource);
SELECT * from the_records WHERE name='$name'

答案 3 :(得分:0)

它有点笨拙,但你可以爆炸GET并在多个条件下构建一个WHERE。

像(未经测试)的东西:

$name_array = explode("-", $_GET['name']);

$sql_str = "SELECT * FROM the_records WHERE ";

$first_time = true;
foreach($name_array as $name){
    if ($name != ""){
        if ($first_time){
            $sql_str .= "name LIKE \"%".$name."%\"";
            $first_time = false;
        }
        else {
            $sql_str .= " AND name LIKE \"%".$name."%\"";
        }
    }
}