在查询字符串中转义'是否可能?

时间:2013-02-05 16:13:48

标签: php sql oracle

我有一个使用oracle-db的大型php应用程序(纯粹是php,没有框架等)。 所有查询都按如下方式执行:

oci_parse($conn_id,"insert into table (bla) values ('bla')");
oci_execute($stmt)

我知道这很糟糕!不需要指出像“使用绑定”之类的东西。我知道,但我无法改变这一点。

我们都知道你必须逃避角色。 这个问题特别关于'字符。

我有很多这样的问题:

$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
$query2 = "UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'"

当然,通常他们没有那么多' - 但这只是为了示范。

现在问题: 有没有办法在php中验证/转义整个查询字符串?无论我如何看待它,我都无法思考/找到实现这一目标的方法。

很明显,在构建查询字符串之前很容易转义所有值,只需将'替换为'' - 但是当你只将整个查询作为字符串时(例如上面的例子)?我个人想不出“通用解决方案”......

6 个答案:

答案 0 :(得分:2)

我认为,在构建查询时,这与传统方法不相容:

  1. 尝试简单地为每个撇号添加斜杠,当然不会起作用,因为您正在转义分隔符撇号以及“有价值”撇号。
  2. 没有函数或正则表达式来确定哪些是值内值撇号,哪些是值分隔撇号。
  3. 即使是解析器也无法帮助您,因为解析器的一部分工作是告诉您何时查询语法无效,而不是修复该语法;一旦它踩到一个撇号不合适而且下面的字符不是逗号,它就会阻止。
  4. 让我们参考你的第二个例子:

    field3 = 'mimi'm', field4 = 'mu's'c'hle'
    

    普通查询解析器会将field3值视为'mini',后跟错误的m,其中需要逗号。这不是解析器旨在处理的东西。

    假设我们写了一些自定义来处理这个问题。假设我们认为撇号(因为它后面没有逗号)必须是值的一部分。那很好,但是下一个撇号是什么呢?它是一个分隔符?

    我们的代码如何知道撇号是否是分隔符,而不是实际包含撇号后跟逗号的值?实际上,该值可能包含与查询的其余部分完全相同的内容! (此外,一旦我们开始以这种方式质疑查询本身的结构,我们如何检测实际上 无效的查询)。

    <强> TL;博士

    GIGO =垃圾输入,垃圾输出

    你不能写(传统)软件来解决任意混乱!

答案 1 :(得分:2)

好的,这绝对不是故障保护,甚至是优雅的,但它确实适用于给定的查询,作为“概念证明”可以这么说......

不要在生产服务器中使用该功能..它会更快地破坏(不是更晚;))

<?php


$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')";
$query2 = "UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'";

function clean_given_query($qry)
{
    if(strpos($qry , " VALUES "))
    {   
        //the easy way, since we know exactly how many fields we have here
        $qra = explode('VALUES', $qry);
        if(count($qra) == 2)
        {
            // qra[0] = "INSERT INTO table (field1, field2,field3,field4)"
            // qra[1] = "('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
            $qtemp = explode('(', $qra[0]);
            $qtemp = $qtemp[1]; // we can loose the insert -part for now
            $fieldcount = count(explode(',',$qtemp)); // now we know how many fields we want to populate
            $qra[1] = explode("','", $qra[1]); // dirty values....
            if(count($qra[1]) === $fieldcount) //make sure we have the correkt value count
            {
                $values = array();
                foreach($qra[1] as $i => $val)
                {
                    if($i==0)
                        $val = substr($val, 3); // we know $val is a string and index 0 starts with (' which we need to remove!
                    if($i == count($qra[1])-1) // last item  needs to be cropped at the end
                        $val = substr($val, 0, count($val)-3); //also a string as we know.

                    $val = addslashes($val); //escape the string according to your needs
                    $values[] = $val;
                }
                return $qra[0]." VALUES ('".implode("','", $values)."')";
            }

        }
    }
    else if (strpos($qry, "SET"))
    {
        $qra = explode('=', $qry);
        // $qra[0] = "UPDATE table SET field1";
        // $qra[1] = "'bla,bla', field2";
        $save = $qra[0]."='";

        foreach($qra as $i => $mixed)
        {   
            if($i == 0) // qra[0]  holds nothing to edit!
                continue;

            $parts = explode(',', $mixed); // [0] 'bla    [1] bla'  [2] field2
            $nextfield = array_pop($parts);

            $val = implode(',', $parts); // $val = 'bla,bla'
            if(strpos($nextfield , "WHERE"))
            {
                list($val, $nextfield) = explode("WHERE",$nextfield);
                $nextfield = " WHERE ".$nextfield;
            }
            $val = trim($val);
            $val = substr($val, 1, count($val)-2); //$val  bla,bla
            $val = addslashes($val); // escape according to your needs

            if($val!=="" and strpos($nextfield , "WHERE") === false)
                $save .= $val."', ".$nextfield."='";
            elseif($val!=="" and strpos($nextfield , "WHERE"))
                $save .= $val."' ".$nextfield."='";
            else
            {
                $val = trim($nextfield);
                $val = substr($val, 1, count($val)-2); //$val  bla,bla
                $val = addslashes($val); // escape according to your needs
                $save .= $val."'";
            }
        }
        return $save;
    }
}

echo $query.PHP_EOL;
echo clean_given_query($query).PHP_EOL;

echo $query2.PHP_EOL;
echo clean_given_query($query2).PHP_EOL;

?>

输出:

INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')
INSERT INTO table (field1, field2,field3,field4)  VALUES ('bla,bla','blub','mimi\'m','mu\'s\'c\'hle')
UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'
UPDATE table SET field1 ='bla,bla',  field2 ='blub',  field3 ='mimi\'m',  field4 ='mu\'s\'c\'hle'  WHERE  field5 ='lol\'zj\'d'

通过一点努力,并且正确的reg_exp而不是简单的爆炸/内爆以及适合您需要的转义函数,您可以构建一个能够清除给定查询的函数

答案 2 :(得分:0)

你可以使用一个简单的str_replace()。 I.E. str_replace("'", "\'", $string);

编辑: 你也可以

$str = "INSERT INTO table(field1, field2) 
                        VALUES (
                                replace(" . $value . ", Chr(39), Chr(39) & Chr(39)), 
                                replace(" . $value . ", Chr(39), Chr(39) & Chr(39))
                               );";

正如Chr(39)所指的那样。

答案 3 :(得分:-1)

$query = "INSERT INTO table(field) Values('".addslashes("'")."')";

我认为这是失败的,甚至更好

$query = sprintf("INSERT INTO table(field) Values('%s')", addslashes("'"));

因为如果你想在某天扩展插入内容,那么最容易理解的是。

[编辑] 据我所知,如果你只想让字符串转义,你使用哪种sql并不重要,但以防万一这里的addslashes也能正常工作。 是的......在PHP中有一些专门的sql-escape函数,

并重新阅读问题..只是拥有查询字符串,没有初始值,很难正确地逃避一切。

答案 4 :(得分:-1)

如果我理解你的问题它应该有效

$name = addslashes("mu's'c'hle");
$query = "INSERT INTO teste (teste) VALUES ('$name')";

答案 5 :(得分:-1)

除非您想编写可以解释查询并确定错误位置的内容,然后以某种方式确定正确修复的内容,否则无法做到。

此外,如果你这样做,你仍然没有解决你的更大的问题,这是sql注入。