我有一些SQL查询,这些查询使用PHP字符串变量在PDO prepare()
之前创建查询。
$connection = new PDO(...);
// Make variable placeholder for each column.
$params = array();
foreach ($row as $col => $value) {
$params[':' . $col] = $value;
}
$columns = implode(', ', array_keys($row));
$values = implode(', ', array_keys($params));
$query = "
INSERT INTO my_table ($columns)
VALUES ($values)
";
$statement = $connection->prepare($query);
$statement->execute($params);
或与SELECT
类似的内容:
$query = "
SELECT field
FROM my_table
WHERE id IN ($ids)
";
查询将变为
$query = "
SELECT field
FROM my_table
WHERE id IN (:id0, :id1, :id2)
";
,然后execute()
函数将传递类似array(':id0' => 0, ...)
的参数。
如果要插入的部分只是一堆占位符,可用于查询准备,这是否容易注入?还有使用PDO在PHP中执行此操作的更好方法吗?
答案 0 :(得分:1)
在绑定动态数量的参数时,我将恢复为?
占位符。您可以这样做:
$placeholders = implode(',', array_fill(0, count($values), '?'));
$query = "SELECT field FROM my_table WHERE id IN ($placeholders)";
$stmt = $pdo->prepare($query);
$stmt->execute($values);
如果列名是动态的,则仍然需要进行字符串替换,例如您的INSERT
示例。那些应该列入白名单以防止注射。但是您可以对插入的值使用上述机制。您需要使用
$values = array_values($params);
因为?
占位符无法从关联数组中填充。
答案 1 :(得分:0)
我写的东西可以做类似的事情,但是在这里继续太复杂了。我为您编写了一个示例供您使用,我绝不会说这是100%安全的事情。我确实在其中添加了一些检查,但我认为逻辑就是开始所需的一切。我在没有PDO的RexTester上进行了宽松的测试,它的功能与我想要的一样。
$ExampleParams = array('col1'=>'val', 'col2'=>'val');
function Insert(array $Params) {
$i = 1; // iteration counter
$Columns = $Selectors = "";
// All columns that can be inserted
$ColumnWhitelist = array('col1', 'col2', 'col3', 'col4');
// Iterate through parameters
foreach ($Params as $Key=>$Value) {
if (!in_array($Key, $ColumnWhitelist)) {
return FALSE; // Bad column
} else {
$Columns .= sprintf('`%s`%s', $Key, sizeof($Params) != $i ? ',' : '');
$Selectors .= sprintf('`:%s`%s', $Key, sizeof($Params) != $i ? ',' : '');
} $i++;
}
// Time to start PDO
$dbh = new PDO(...);
$cmd = $dbh->prepare(sprintf('INSERT INTO `table` (%s) VALUES (%s);', $Columns, $Selectors));
// Fill in parameters
foreach ($Params as $Key=>$Value) {
$cmd->bindParam(sprintf(':%s', $Key), $Value);
} return $cmd->execute();
}
这可以用于任何类型的查询。就像我之前说过的那样,我认为这不是100%安全的,但是白名单对于确保我们没有不好的查询是必要的。可以使用一维数组来完成,但是多维数组最适合IMO。