Php 在避免不必要的查询的同时,使用PDO是否有一种更安全的方法?

Php 在避免不必要的查询的同时,使用PDO是否有一种更安全的方法?,php,mysql,pdo,innodb,sql-injection,Php,Mysql,Pdo,Innodb,Sql Injection,我使用与下面类似的代码插入mysql数据库(使用PDO) 目的是只使用一个查询插入数据。 不幸的是,它无法达到使用PDO的目的,因为它没有使用bindValue或param。我想写代码,这样更安全,但仍然可以避免不必要的查询。 有人能推荐如何做吗 注1:每次访问程序时,集合中的问题数都会发生变化(即$totalQ每次运行时都会不同) 试试看 { 对于($i=0;$i$rowValue) { $rowValues[$key]=$rowValues[$key]; } $values[]=“(“.in

我使用与下面类似的代码插入mysql数据库(使用PDO) 目的是只使用一个查询插入数据。 不幸的是,它无法达到使用PDO的目的,因为它没有使用bindValue或param。我想写代码,这样更安全,但仍然可以避免不必要的查询。 有人能推荐如何做吗

注1:每次访问程序时,集合中的问题数都会发生变化(即
$totalQ
每次运行时都会不同)

试试看
{
对于($i=0;$i$rowValue)
{
$rowValues[$key]=$rowValues[$key];
}
$values[]=“(“.introde(',',$rowValues)。””;
}
$count=$dbh->exec(“插入到结果(实例、qid、结果、开始、结束)值中”)。内爆(“,”,$VALUES));
$dbh=null;
}
注意2:开始和结束时间格式中的逗号可能会导致内爆语句出错。我刚刚添加了它们,以便您可以看到我正在努力实现的目标

任何帮助都将不胜感激。谢谢


编辑:当我选择chris的答案时,我非常感谢Alix Axel的建议。这帮了大忙,谢谢

像这样的东西怎么样:

try 
{
    for ($i=0; $i<$totalQ; $i++)
    { 
        $stqid[$i][0]=$lastInsertValue;     //instance         PDO::PARAM_INT
        $stqid[$i][1]=$jaid[$i][0];          //question number  PDO::PARAM_INT
        $stqid[$i][2]=$jaid[$i][5];          //result           PDO::PARAM_INT
        $stqid[$i][3]=$jqid[$i][3];          //question start   PDO::PARAM_STR 
        $stqid[$i][4]=$jqid[$i][4];          //question finish  PDO::PARAM_STR 
    }

    $values = null;

    foreach ($stqid as $rowValues) 
    {
        $values .= vsprintf('(%s, %s, %s, %s, %s) ', array_map(array($dbh, 'quote'), $rowValues));
    }

    $count = $dbh->exec('INSERT INTO results (instance, qid, result, start, finish) VALUES ' . rtrim($values) . ';');  
    $dbh = null;
}
试试看
{
对于($i=0;$iexec('INSERT-INTO-results(instance,qid,result,start,finish))值.rtrim($VALUES)。;';
$dbh=null;
}

像这样的东西怎么样:

try 
{
    for ($i=0; $i<$totalQ; $i++)
    { 
        $stqid[$i][0]=$lastInsertValue;     //instance         PDO::PARAM_INT
        $stqid[$i][1]=$jaid[$i][0];          //question number  PDO::PARAM_INT
        $stqid[$i][2]=$jaid[$i][5];          //result           PDO::PARAM_INT
        $stqid[$i][3]=$jqid[$i][3];          //question start   PDO::PARAM_STR 
        $stqid[$i][4]=$jqid[$i][4];          //question finish  PDO::PARAM_STR 
    }

    $values = null;

    foreach ($stqid as $rowValues) 
    {
        $values .= vsprintf('(%s, %s, %s, %s, %s) ', array_map(array($dbh, 'quote'), $rowValues));
    }

    $count = $dbh->exec('INSERT INTO results (instance, qid, result, start, finish) VALUES ' . rtrim($values) . ';');  
    $dbh = null;
}
试试看
{
对于($i=0;$iexec('INSERT-INTO-results(instance,qid,result,start,finish))值.rtrim($VALUES)。;';
$dbh=null;
}

未测试。仍使用准备好的语句

$numColumns = 5; //or $numColumns = count($stqid[0]);
$rowPlaceholder = join(', ', array_fill(0, $numColumns, '?'));
$rowPlaceholders = array_fill(0, $totalQ, "($rowPlaceholder)");
echo $sql = "INSERT INTO results(instance, qid, result, start, finish) VALUES " . join(", \n", $rowPlaceholders);
$flat = call_user_func_array('array_merge', $stqid);
$stmt = $dbh->prepare($sql);
$stmt->execute($flat);

未测试。仍然使用准备好的语句

$numColumns = 5; //or $numColumns = count($stqid[0]);
$rowPlaceholder = join(', ', array_fill(0, $numColumns, '?'));
$rowPlaceholders = array_fill(0, $totalQ, "($rowPlaceholder)");
echo $sql = "INSERT INTO results(instance, qid, result, start, finish) VALUES " . join(", \n", $rowPlaceholders);
$flat = call_user_func_array('array_merge', $stqid);
$stmt = $dbh->prepare($sql);
$stmt->execute($flat);


您可以根据需要添加尽可能多的占位符,然后将值绑定到占位符。为什么不使用准备好的语句并使用不同的值执行它呢?我还没有测试过这一点,但我认为对性能的影响不应该太大。我可能错了。我真的很难使用PDO。您可以链接到一个示例吗?可能重复:Y你可以根据需要添加尽可能多的占位符,然后将值绑定到占位符上。为什么不使用一个准备好的语句,然后用不同的值执行它呢?我还没有测试过这一点,但我认为对性能的影响不应该太大。我可能错了。我真的很难处理PDO。你能链接到一个示例吗?可能重复:Th谢谢你的回答。我猜你使用vsprintf是为了避免在开始和结束的时间格式中出现与逗号相关的错误。但是这会使它更安全吗?@moocho:不,我使用了
[v]sprintf
因为你总是有5个占位符,而且它比
内爆更可靠。实际上,关于安全性,它是非常安全的:首先
PDO::quote()
对所有参数都起作用(这足以阻止任何SQL注入攻击),然后
vsprintf
将前3个参数转换为整数。非常可靠。感谢您的详细解释!我现在理解得更好了。我不知道为什么,但如果我在
$dbh->exec
之前回显$value,它会读取
value=(0,0,0,'2012-05-10 06:11:43',2012-05-10 06:11:43'))
问题是前几个值应该是1,1,null。我还得到了错误
SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法有错误;请查看与您的MySQL服务器版本相对应的手册,以获得正确的语法,以便在“0,0,0,'2012-05-10 06:11:43'、'2012-05-10 06:11:43'附近使用)
你对正在发生的事情有什么想法吗?@moomoochoo:哼哼…如果值首先是整数
PDO::quote
不应该在它们周围加引号(这就是为什么你看到的是
0
而不是
1
,因为
intval('1')=0
)。无论如何,使用
(%s,%s,%s,%s)
vsprintf()
调用中的
将在不影响安全性的情况下修复它。感谢您的回答。我猜您使用vsprintf是为了避免与开始和结束时间格式中的逗号相关的错误。但是这会使它更安全吗?@moomoochoo:不,我使用了
[v]sprintf
因为你总是有5个占位符,而且它比
内爆更可靠。实际上,关于安全性,它是非常安全的:首先
PDO::quote()
对所有参数都起作用(这足以阻止任何SQL注入攻击),然后
vsprintf
将前3个参数转换为整数。非常可靠。感谢您的详细解释!我现在理解得更好了。我不知道为什么,但如果我在
$dbh->exec
之前回显$value,它会读取
value=(0,0,0,'2012-05-10 06:11:43',2012-05-10 06:11:43'))
问题是前几个值应该是1,1,null。我还得到了错误
SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法有错误;请查看与您的MySQL服务器版本相对应的手册,以获得正确的语法,以便在“0,0,0,'2012-05-10 06:11:43'、'2012-05-10 06:11:43'附近使用)
你对正在发生的事情有什么想法吗?@moomoochoo:哼哼…如果值首先是整数
PDO::quote
不应该在它们周围加引号(这就是为什么你看到的是
0
而不是
1
,因为
intval('1')=0
)。无论如何,使用
(%s,%s,%s,%s)
vsprintf()中的
调用将在不影响安全性的情况下修复它。
$flat=call\u user\u func\u数组('array\u merge',$stqid)
是这样吗?谢谢你的回答。这对我来说很有效,但我不太明白它是如何让它更安全的。我还发现,如果一个
结果
的值为
null
它被作为0插入到mysql中(但我想这是另一个问题!)@moomoochoo:他是一名律师