我一直在从头开发内容管理系统。由于经验原因,它主要是从零开始开发的,但它也将在未来使用。
我开发了一个DatabaseManager
类,它扩展了PHP中的mysqli
类。我正在使用它做MySQL查询和连接。我开发的函数传递了SQL查询字符串(参数化),后跟要替换的正确值的数组。
长话短说,我使用ReflectionClass
将参数绑定到SQL查询并执行。我很好奇这是否是一种安全的方法,还是有另一种最适合的方法?
这是DatabaseManager::do_query()
方法:
function do_query($sql, $values){
if(!isset($this->connect_error)){
$num_vals = count($values);
$i = 0;
$type = "";
while($i < $num_vals){
if(is_int($values[$i]) == true)
$type .= "i";
elseif(is_string($values[$i]) == true)
$type .= "s";
$i++;
}
$i = 0;
while($i < $num_vals){
$values2[$i] = &$values[$i];
$i++;
}
$values2 = array_merge(array($type), $values2);
$expr = $this->prepare($sql);
if($expr != false){
$ref = new ReflectionClass('mysqli_stmt');
$method = $ref->getMethod("bind_param");
$method->invokeArgs($expr, $values2);
$expr->execute();
return "Success";
}else{
$error_string = "Error: Query preparation resulted in an error. ";
$error_string .= $this->error;
__TGErrorHandler(TG_ERROR_DB_PREP);
return $error_string;
}
}
}
我没有通过测试遇到任何直接错误,并且似乎使用预准备语句来阻止SQL注入。但是,这种方法的结构是否存在潜在问题?
P.S。我以不同的方式处理SELECT
语句。这将主要处理DELETE
和INSERT
语句。
答案 0 :(得分:1)
首先,你走在正确的轨道上。只有少数,可能是百分之一的PHP用户甚至想到使用这样一个有用的功能。
接下来,反射对于此任务来说是多余的,call_user_func_array()
是一种方法。 Even though it's a little tricky,这是一种直截了当的方式,而反思则不是。
最后,对安全。我会删除自动类型检测并将所有参数绑定为字符串。它不会造成任何伤害,而使用您当前的方法,如果您碰巧将数字与数据库中的字符串进行比较,则数据库可能会返回奇怪的结果。
此功能中的错误处理也值得怀疑。
答案 1 :(得分:0)
在这里使用反射并没有什么固有的不安全感,但这完全没必要。你可以使用call_user_func_array
完成完全相同的事情而无需反思:
if ($expr !== FALSE) {
call_user_func_array([$expr, "bind_param"], $values2);
$expr->execute();
...
或者,考虑使用PDO而不是mysqli。 PDOStatement::execute()
可以将一组绑定参数作为参数。 (另外,使用PDO意味着您的代码可以移植到MySQL以外的数据库!)