2012-08-02 202 views
1

我正在寫一個類,編程創建一個給定某些列名稱的表。我正在使用PDO準備好的語句,這似乎會導致一些問題。PHP的PDO問題與bindValue()

下面是基本過程:

// create a query string to be sent to $pdo->prepare 
$sql = 
'CREATE TEMP TABLE :tmp_table_name (
    :person_id bigint, 
    :encntr_id bigint, 
    :prsnl_id bigint, 
    :program_detail text, 
    :program_name text 
);'; 
$stmt = $pdo->prepare($sql); 

// Bind table name 
$stmt->bindValue(':tmp_table_name', 'tmp_patients', PDO::PARAM_STR); 

// Bind column names 
$columnNames = [ 
    'person_id', 
    'encnt_id', 
    'prsnl_id', 
    'program_detail', 
    'program_name', 
]; 
foreach($columnNames as $name) { 
    $stmt->bindValue(':'.$name, $name, PDO::PARAM_STR); 
} 

$ret = $stmt->execute(); 
// $ret is false! The statement fails. 

這裏是$stmt->errorInfo()[2]顯示:

ERROR: syntax error at or near "$1" 
LINE 1: CREATE TEMP TABLE $1 ($2 bigint, 
$3 bigint, 
$4 bigint, 
$5 text, 
$6 te... 

爲什麼$ 1,$ 2,$ 3等顯示在查詢呢?你有關於如何進一步調試這個PDO陳述的提示嗎?

更新 我嘗試了不同的方法,不使用bindParam,只是路過的則params的數組$ stmt->的execute()。我仍然得到同樣的錯誤,但...

$stmt = $this->pdo->prepare($this->createSql); 

$keys = []; 
// Bind column names 
foreach($this->columnNames as $name) { 
    $keys[] = ':'.$name; 
} 
$params = array_combine($keys, $this->columnNames); 

// Bind table name 
$params[':tmp_table_name'] = 'tmp_'.$this->objName; 

$ret = $stmt->execute($params); 
if (!$ret) { 
    throw new Exception('execSchema() failed! '. $stmt->errorInfo()[2]); 
} 
+0

爲什麼bindValue代替bindParam? http://www.php.net/manual/es/pdostatement.bindparam.php – fiunchinho 2012-08-02 19:40:58

+0

@ONe因爲bindValue更靈活(我可以使用字符串作爲bindValue的值,bindParam需要該值是一個變量。)http:///stackoverflow.com/questions/1179874/pdo-bindparam-versus-bindvalue – nnyby 2012-08-02 19:43:35

+1

請記住,您也可以發送參數來執行($ params)http://www.php.net/manual/es/pdostatement.execute.php – fiunchinho 2012-08-02 20:04:41

回答

5

在我看來,如果你正在試圖綁定到表名/列,你不能做使用PDO - 你只能綁定值佔位符。

如被看見在你的代碼在這裏:

// Bind table name 
$stmt->bindValue(':tmp_table_name', 'tmp_patients', PDO::PARAM_STR); 

感覺好像它應該工作,但事實並非如此。

例如,這將工作:

$sql = "insert into mytable (:thing1) values (:thing2); 
$stmt->bindValue(':thing1', 'column_name'); // this would not 
$stmt->bindValue(':thing2', 'column_value'); // this would have (on its own) 

然而,像這樣的工作,這應該毫無顧忌您的解決方案或類似的東西:

// imagine an incoming POST load like this: 
$cols = ['fname','lname']; 

$array_cnt = count($cols); // 2 
$sql = 'INSERT INTO mytable ('.join(',', $cols).') '; 

// and then that number of placeholders used 
$sql .= 'VALUES (' . join(array_fill(0, $array_cnt, '?'), ', ') . ')'; 

echo $sql; 
+0

感謝您的確切答案。我沒有意識到你不能綁定PDO中的表名/列,但我懷疑這一點。以前,我是按照你的建議來做的,但是我擔心SQL注入攻擊,所以我認爲我應該用準備好的語句來做到這一點。 – nnyby 2012-08-02 20:30:36

0

bindParam()bindValue()工作由基準值,這意味着你通過它的$value變量的引用,而不是它的時間價值,你叫它。當循環結束並且您撥打query()時,$value將是$array中的最後一個。

使用參照項目在數組中:

$stmt->bindValue(":".$array[$param], $array[$param]); 
$stmt->bindParam($param, $array[$param]); 
+0

我重寫了這樣的循環: 'foreach($ columnNames as $ k => $ name){ $ stmt-> bindValue(':'。$ columnNames [$ k],$ columnNames [$ k ]); }' 但我仍然收到同樣的錯誤。 – nnyby 2012-08-02 19:53:48