2012-02-16 28 views
3

我有一個關於PDO的問題進行交談數據庫, 我熟悉的例子是:帶有k/v對和未知數的PDO?

$data = array('Cathy', '9 Dark and Twisty Road', 'Cardiff'); 

$STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?); 
$STH->execute($data); 

但是,如果我們有A K/V對,這將是一樣的嗎? ala

$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

預處理語句只文字標識符工作,而不是。因此,您需要構建填充了標識符(並正確轉義)的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); 
} 
+0

您可以解釋'$ assoc'的用途以及如何使用它? – ehime 2012-02-16 22:20:19

+0

'$ assoc'是''columnname'=>'columnvalue''的關聯數組,在你的文章中描述過! – 2012-02-16 23:21:49

+0

好吧然後我混淆了'$ pdo'是什麼,我認爲(出於某種愚蠢的原因...),那就是數組入口 – ehime 2012-02-16 23:32:39

2

你不必使用?作爲綁定佔位符,您可以使用:名稱和關聯數組。然後您可以傳遞關聯數組作爲綁定列表,並且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.')';