我有一个使用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中验证/转义整个查询字符串?无论我如何看待它,我都无法思考/找到实现这一目标的方法。
很明显,在构建查询字符串之前很容易转义所有值,只需将'
替换为''
- 但是当你只将整个查询作为字符串时(例如上面的例子)?我个人想不出“通用解决方案”......
答案 0 :(得分:2)
我认为,在构建查询时,这与传统方法不相容:
让我们参考你的第二个例子:
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注入。