动态预准备语句不好吗? (使用 php + mysqli)

发布于 2024-07-07 09:53:31 字数 1069 浏览 8 评论 0原文

我喜欢动态 SQL 的灵活性,也喜欢准备语句的安全性和改进的性能。 所以我真正想要的是动态准备语句,这做起来很麻烦,因为bind_param和bind_result接受“固定”数量的参数。 所以我使用 eval() 语句来解决这个问题。 但我感觉这是一个坏主意。 这是我的意思的示例代码

// array of WHERE conditions
$param = array('customer_id'=>1, 'qty'=>'2');
$stmt = $mysqli->stmt_init();

$types = ''; $bindParam = array(); $where = ''; $count = 0;

// build the dynamic sql and param bind conditions
foreach($param as $key=>$val)
{
    $types .= 'i';
    $bindParam[] = '$p'.$count.'=$param["'.$key.'"]'; 
    $where .= "$key = ? AND ";
    $count++;
}

// prepare the query -- SELECT * FROM t1 WHERE customer_id = ? AND qty = ?
$sql = "SELECT * FROM t1 WHERE ".substr($where, 0, strlen($where)-4);
$stmt->prepare($sql);

// assemble the bind_param command
$command = '$stmt->bind_param($types, '.implode(', ', $bindParam).');';

// evaluate the command -- $stmt->bind_param($types,$p0=$param["customer_id"],$p1=$param["qty"]);
eval($command);

最后一个 eval() 语句是一个坏主意吗? 我尝试通过将值封装在变量名 $param 后面来避免代码注入。

有人有意见或其他建议吗? 有我需要注意的问题吗?

I like the flexibility of Dynamic SQL and I like the security + improved performance of Prepared Statements. So what I really want is Dynamic Prepared Statements, which is troublesome to make because bind_param and bind_result accept "fixed" number of arguments. So I made use of an eval() statement to get around this problem. But I get the feeling this is a bad idea. Here's example code of what I mean

// array of WHERE conditions
$param = array('customer_id'=>1, 'qty'=>'2');
$stmt = $mysqli->stmt_init();

$types = ''; $bindParam = array(); $where = ''; $count = 0;

// build the dynamic sql and param bind conditions
foreach($param as $key=>$val)
{
    $types .= 'i';
    $bindParam[] = '$p'.$count.'=$param["'.$key.'"]'; 
    $where .= "$key = ? AND ";
    $count++;
}

// prepare the query -- SELECT * FROM t1 WHERE customer_id = ? AND qty = ?
$sql = "SELECT * FROM t1 WHERE ".substr($where, 0, strlen($where)-4);
$stmt->prepare($sql);

// assemble the bind_param command
$command = '$stmt->bind_param($types, '.implode(', ', $bindParam).');';

// evaluate the command -- $stmt->bind_param($types,$p0=$param["customer_id"],$p1=$param["qty"]);
eval($command);

Is that last eval() statement a bad idea? I tried to avoid code injection by encapsulating values behind the variable name $param.

Does anyone have an opinion or other suggestions? Are there issues I need to be aware of?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

囍笑 2024-07-14 09:53:31

我认为在这里使用eval()是危险的。

试试这个:

  • 迭代 params 数组来构建带有问号的 SQL 字符串 "SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • prepare()
  • 调用 call_user_func_array() 调用 bind_param(),传入动态参数数组。

代码:

call_user_func_array(array($stmt, 'bind_param'), array($types)+$param);

I think it is dangerous to use eval() here.

Try this:

  • iterate the params array to build the SQL string with question marks "SELECT * FROM t1 WHERE p1 = ? AND p2 = ?"
  • call prepare() on that
  • use call_user_func_array() to make the call to bind_param(), passing in the dynamic params array.

The code:

call_user_func_array(array($stmt, 'bind_param'), array($types)+$param);
带刺的爱情 2024-07-14 09:53:31

我创建了一个过滤函数,它接收一个数组,一个关联数组,如 $_GET:

在模型类中,我定义了几个属性,包括模式:

private $table_name = "products";

protected $schema = [
    'id' => 'INT',
    'name' => 'STR',
    'description' => 'STR',
    'size' => 'STR',
    'cost' => 'INT',
    'active' => 'BOOL'
];

然后是一个过滤方法,它接收条件的关联数组:

function filter($conditions)
{
    $vars   = array_keys($conditions);
    $values = array_values($conditions);

    $where = '';
    foreach($vars as $ix => $var){
        $where .= "$var = :$var AND ";
    }
    $where =trim(substr($where, 0, strrpos( $where, 'AND ')));

    $q  = "SELECT * FROM {$this->table_name} WHERE $where";
    $st = $this->conn->prepare($q);

    foreach($values as $ix => $val){
        $st->bindValue(":{$vars[$ix]}", $val, constant("PDO::PARAM_{$this->schema[$vars[$ix]]}"));
    }

    $st->execute();
    return $st->fetchAll(PDO::FETCH_ASSOC);
}

并且非常适合过滤结果

I made a filter function which recives an array an asociative array like $_GET:

In model class I've defined a couple of properties including the schema:

private $table_name = "products";

protected $schema = [
    'id' => 'INT',
    'name' => 'STR',
    'description' => 'STR',
    'size' => 'STR',
    'cost' => 'INT',
    'active' => 'BOOL'
];

Then a filter method which recive an asociative arrays of conditions:

function filter($conditions)
{
    $vars   = array_keys($conditions);
    $values = array_values($conditions);

    $where = '';
    foreach($vars as $ix => $var){
        $where .= "$var = :$var AND ";
    }
    $where =trim(substr($where, 0, strrpos( $where, 'AND ')));

    $q  = "SELECT * FROM {$this->table_name} WHERE $where";
    $st = $this->conn->prepare($q);

    foreach($values as $ix => $val){
        $st->bindValue(":{$vars[$ix]}", $val, constant("PDO::PARAM_{$this->schema[$vars[$ix]]}"));
    }

    $st->execute();
    return $st->fetchAll(PDO::FETCH_ASSOC);
}

And works great to filter results

小苏打饼 2024-07-14 09:53:31

您实际上并不需要准备好的语句和绑定参数,因为您始终可以使用 mysql_real_escape_string()。 你是对的; 动态生成的 SQL 更加灵活和有价值。

这是一个使用常规 mysql_* 接口的简单示例:

// Array of WHERE conditions
$conds = array("customer_id" => 1, "qty" => 2);

$wherec = array("1");
foreach ($conds as $col=>$val) $wherec[] = sprintf("`%s` = '%s'", $col, mysql_real_escape_string($val));

$result_set = mysql_query("SELECT * FROM t1 WHERE " . implode(" AND ", $wherec);

当然,这是一个简单化的示例,要使其有用,您必须对其进行大量构建和改进,但它显示了想法,并且确实非常非常有用。 例如,下面是一个完全通用的函数,用于将新行插入任意表中,其中列填充关联数组中的值,并且完全 SQL 注入安全:

function insert($table, $record) {
    $cols = array();
    $vals = array();
    foreach (array_keys($record) as $col) $cols[] = sprintf("`%s`", $col);
    foreach (array_values($record) as $val) $vals[] = sprintf("'%s'", mysql_real_escape_string($val));

    mysql_query(sprintf("INSERT INTO `%s`(%s) VALUES(%s)", $table, implode(", ", $cols), implode(", ", $vals)));
}

// Use as follows:
insert("customer", array("customer_id" => 15, "qty" => 86));

You don't really need prepared statements and bound arguments, because you can always use mysql_real_escape_string(). And you're right; dynamically generated SQL is far more flexible and valuable.

Here's a simple example using the regular mysql_* interface:

// Array of WHERE conditions
$conds = array("customer_id" => 1, "qty" => 2);

$wherec = array("1");
foreach ($conds as $col=>$val) $wherec[] = sprintf("`%s` = '%s'", $col, mysql_real_escape_string($val));

$result_set = mysql_query("SELECT * FROM t1 WHERE " . implode(" AND ", $wherec);

Of course, this is a simplistic example, and to make it useful you have to build and refine it a lot, but it shows the ideas and it's really very very useful. For example, here is a completely generic function to insert a new row into an arbitrary table, with the columns filled with the values from an associative array and completely SQL-injection safe:

function insert($table, $record) {
    $cols = array();
    $vals = array();
    foreach (array_keys($record) as $col) $cols[] = sprintf("`%s`", $col);
    foreach (array_values($record) as $val) $vals[] = sprintf("'%s'", mysql_real_escape_string($val));

    mysql_query(sprintf("INSERT INTO `%s`(%s) VALUES(%s)", $table, implode(", ", $cols), implode(", ", $vals)));
}

// Use as follows:
insert("customer", array("customer_id" => 15, "qty" => 86));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文