我有一个关于PDO与数据库交谈的问题, 我熟悉的例子是:
$data = array('Cathy', '9 Dark and Twisty Road', 'Cardiff');
$STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?);
$STH->execute($data);
但是,如果我们有一个k / v对,它会是一样的吗?翼
$data = array('one'=>'Cathy', 'two'=>'9 Dark and Twisty Road', 'three'=>'Cardiff');
$STH = $DBH->("INSERT INTO folks (?, ?, ?) values (?, ?, ?);
$STH->execute($data);
如果我们没有确定数量的值会怎么样?
$data = array(range(0, rand(1,99));
$STH = $DBH->("INSERT INTO folks (/* how would you put stuff here? */) values (/* how would you put stuff here? */);
$STH->execute($data);
这让我更加困惑....
有人可以告诉我上面两个如何使用k / v对和未知计数吗?
非常感谢
答案 0 :(得分:2)
你不必使用?作为绑定占位符,您可以使用:names和关联数组。然后,您可以将关联数组作为绑定列表传递,PDO现在将使用:binding_names匹配数组的键。例如,对于关联数组,如果键与数据库中的字段匹配,则可以执行以下操作:
$data = array('one'=>'Cathy', 'two'=>'9 Dark and Twisty Road', 'three'=>'Cardiff');
$fields = array_keys($data);
$field_str = '`'.implode('`,`',$fields).'`';
$bind_vals = ':'.implode(',:',$fields);
$sql = 'INSERT INTO tablename ('.$field_str.') VALUES ('.$bind_vals.')';
$sth = $dbh->prepare($sql);
$sth->execute($data);
这将处理未知数量的名称/值对。没有什么可以不知道用于插入的字段名称。这个例子也适用?作为绑定占位符。所以不是名字,你可以重复一下?:
$bind_vals = str_repeat('?,', count($data));
$sql = 'INSERT INTO tablename ('.$field_str.') VALUES ('.$bind_vals.')';
答案 1 :(得分:0)
预准备语句仅适用于文字,而不适用于标识符。因此,您需要使用填充的标识符(并正确转义)来构造SQL语句。
但正确地逃避文字是很棘手的。 PDO没有提供执行文字转义的方法,MySQL的转义文字的方法(使用`
)与其他所有数据库和ANSI SQL标准完全不同。 See this question for more detail and for workarounds
如果我们简化了转义标识符的问题,您可以使用这样的解决方案:
// assuming mysql semantics
function escape_sql_identifier($ident) {
if (preg_match('/[\x00`\\]/', $ident)) {
throw UnexpectedValueException("SQL identifier cannot have backticks, nulls, or backslashes: {$ident}");
}
return '`'.$ident.'`';
}
// returns a prepared statement and the positional parameter values
function prepareinsert(PDO $pdo, $table, $assoc) {
$params = array_values($assoc);
$literals = array_map('escape_sql_identifier', array_keys($assoc));
$sqltmpl = "INSERT INTO %s (%s) VALUES (%s)";
$sql = sprintf($sqltmpl, escape_sql_identifier($table), implode(',',$literals), implode(',', array_fill(0,count($literals),'?'));
return array($pdo->prepare($sql), $params);
}
function prefixkeys($arr) {
$prefixed = array();
for ($arr as $k=>$v) {
$prefixed[':'.$k] = $v;
}
return $prefixed;
}
// returns a prepared statement with named parameters
// this is less safe because the parameter names (keys) may be vulnerable to sql injection
// In both circumstances make sure you do not trust column names given through user input!
function prepareinsert_named(PDO $pdo, $table, $assoc) {
$params = prefixkeys($assoc);
$literals = array_map('escape_sql_identifier', array_keys($assoc));
$sqltmpl = "INSERT INTO %s (%s) VALUES (%s)";
$sql = sprintf($sqltmpl, escape_sql_identifier($table), implode(',',$literals), implode(', ', array_keys($params)));
return array($pdo->prepare($sql), $params);
}