2

我有一个使用 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 中的整个查询字符串?无论我怎么想,我都想不出/找到一种方法来实现这一点。

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

4

6 回答 6

2

我相信在已经建立查询的时候,这是用传统方法无法解决的:

  1. 尝试简单地在每个撇号上添加一个斜线当然是行不通的,因为您正在转义分隔符撇号以及“in-value”撇号。
  2. 没有函数或正则表达式来确定哪些是值内撇号,哪些是值分隔撇号。
  3. 即使是解析器也无济于事,因为解析器的一部分工作是告诉您查询何时具有无效语法,而不是修复该语法;一旦它碰到一个不合适的撇号并且后面的字符不是逗号,它就会阻止。

让我们来看看你的第二个例子:

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

正常的查询解析器会看到该field3'mini'后跟一个错误m的 ,它需要一个逗号。这不是解析器旨在处理的事情。

所以假设我们写了一些自定义的东西来处理这个。假设我们决定撇号,因为它后面没有逗号,所以它必须是值的一部分。这很好,但是下一个撇号是什么意思,它是一个分隔符?

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

tl;博士

GIGO = 垃圾进,垃圾出

您无法编写(传统)软件来解决任意混乱!

于 2013-02-05T16:47:20.293 回答
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 而不是简单的爆炸/内爆和适合您需要的转义函数,您可以构建一个能够清理给定查询的函数

于 2013-02-05T18:32:15.380 回答
0

您可以使用只需做一个简单的str_replace(). 即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) 指的是 '.

于 2013-02-05T16:17:48.133 回答
-1
$query = "INSERT INTO table(field) Values('".addslashes("'")."')";

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

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

因为如果您想在某天扩展插入内容,那将更容易阅读。

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

而且..重读问题..只有查询字符串,没有初始值,很难正确地转义所有内容。

于 2013-02-05T16:23:42.520 回答
-1

如果我理解您的问题,它应该可以工作

$name = addslashes("mu's'c'hle");
$query = "INSERT INTO teste (teste) VALUES ('$name')";
于 2013-02-05T16:28:26.073 回答
-1

除非您想编写可以解释查询并确定错误所在位置然后以某种方式确定正确修复方法的东西,否则没有办法。

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

于 2013-02-05T16:29:01.950 回答