@(PDO(PHP data object/PHP數據對象))[PDO|預處理語句|參數化查詢]
PDO Tutorial for MySQL Developers
Using Prepared Statements to Stop Injection AttacksThe database library called PHP Data Objects or PDO for short can use drivers for many different database types, and supports a very important feature known as
prepared statements, sometimes also known asparametrized queries.
PDO::prepare

在執(zhí)行之前,對一條語句進行預處理,并返回一個語句對象。
預處理一條 SQL 語句,以便 PDOStatement::execute() 方法執(zhí)行。該 SQL 語句可以包含 0 或更多個命名參數(:name)或問號參數(?),這些參數的真實值在語句執(zhí)行的時候會被替換掉。使用這些參數綁定所有的用戶輸入的數據,不要在查詢中直接包含用戶輸入的數據。
返回值:
如果數據庫服務器成功地預處理了該語句,PDO::prepare() 將會返回一個 PDOStatement 對象;否則,返回 false 或 拋出 PDOException(依 error handling 而定)。
模擬的預處理語句并沒有與數據庫服務器進行通信,所以
PDO::prepare()并沒有檢查該語句。
PDOStatement::bindParam

原來 PDO 官方手冊的簡要描述的描述順序有點怪怪的,并且后面的詳細描述也不一致。所以這里把簡要描述跟詳細描述中的描述順序統(tǒng)一一下。
Binds the specified variable name to a parameter.
綁定 指定的變量名(只能是 $name 的形式)到 一個參數(:name 或 ?參數 ,可以是 :name 或 從1 開始的索引 的形式)。
綁定 一個 PHP 變量 到 預處理語句中對應的命名占位符或問號占位符。
與 PDOStatement::bindValue() 不同的是:PDOStatement::bindParam() 中的變量是作為引用而綁定的,并且只有在調用 PDOStatement::execute() 的時候才會讀取這個變量的值。
Note we used
bindValueand notbindParam. Trying to bind a parameter by reference will generate a Fatal Error and this cannot be caught byPDOExceptioneither.
但如果需要循環(huán)執(zhí)行預處理語句,最好使用bindParam,具體原因見對應的章節(jié):Executing prepared statements in a loop。
返回值:
成功則返回 true,失敗則返回 false
例如:
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->bindParam(1, $calories, PDO::PARAM_INT);
$sth->bindParam(2, $colour, PDO::PARAM_STR, 12);
$sth->execute();
PDOStatement::bindValue

Binds a value to a parameter.
綁定 一個值(可以是 $name 或 'Jack' 的形式) 到 一個參數(:name 或 ?參數 ,可以是 :name 或 從1 開始的索引 的形式)。
綁定 一個值 到 預處理語句中對應的命名占位符或問號占位符。
返回值:
成功則返回 true,失敗則返回 false
例如:
$stm->bindValue(':name',$name);
$stm->bindValue(':name','Jack');
PDOStatement::execute

Executes a prepared statement.
執(zhí)行一條 經過預處理的語句。
如果預處理語句中包含占位符,則必須執(zhí)行以下兩點之一:
- 調用PDOStatement::bindParam() 或 PDOStatement::bindValue() 把變量或值綁定到占位符上。
- 或 傳入一個數組
1. 參數:
$input_parameters:一個數組。數組的元素數量 應該與 需要執(zhí)行的 SQL 語句中占位符數量 相等。
所有的值作為
PDO::PARAM_STR處理。不能綁定多個值到一個單獨的參數;比如,不能綁定兩個值到
IN()子句中一個單獨的命名占位符。綁定值的數量不能超過指定的數量。如果在
$input_parameters的鍵名數量 比PDO::prepare()中的 SQL 語句中指定的參數的數量還要多,則該語句將會失敗并發(fā)出一個錯誤。$input_parameters中的鍵名 必須和 SQL 中聲明的 相匹配。在 PHP 5.2.0 之前,這是被忽略的。
2. 返回值:
成功則返回 true,失敗則返回 false
例如:
/* Execute a prepared statement by passing an array of insert values */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
/* Execute a prepared statement by passing an array of insert values */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->execute(array($calories, $colour));
Preparing Statements using SQL functions
You may ask how do you use SQL functions with prepared statements. I've seen people try to bind functions into placeholders like so:
//THIS WILL NOT WORK!
$time = 'NOW()';
$name = 'BOB';
$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(?, ?)");
$stmt->execute(array($time, $name));
This does not work, you need to put the function in the query as normal:
$name = 'BOB';
$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(NOW(), ?)");
$stmt->execute(array($name));
You can bind arguments into SQL functions however:
$name = 'BOB';
$password = 'badpass';
$stmt = $db->prepare("INSERT INTO table(`hexvalue`, `password`) VALUES(HEX(?), PASSWORD(?))");
$stmt->execute(array($name, $password));
Also note that this does NOT work for LIKE statements:
//THIS DOES NOT WORK
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%");
$stmt->bindParam(1, $search, PDO::PARAM_STR);
$stmt->execute();
So do this instead:
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?");
$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);
$stmt->execute();
Note we used
bindValueand notbindParam. Trying to bind a parameter by reference will generate a Fatal Error and this cannot be caught byPDOExceptioneither.
但如果需要循環(huán)執(zhí)行預處理語句,最好使用bindParam,具體原因見對應的章節(jié):Executing prepared statements in a loop。
Executing prepared statements in a loop
Prepared statements excel in being called multiple times in a row with different values.
Because the sql statement gets compiled first, it can be called multiple times in a row with different arguments, and you'll get a big speed increase vs calling mysql_query over and over again!
Typically this is done by binding parameters with bindParam. bindParam is much like bindValue except instead of binding the value of a variable, it binds the variable itself, so that if the variable changes, it will be read at the time of execute.
$values = array('bob', 'alice', 'lisa', 'john');
$name = '';
$stmt = $db->prepare("INSERT INTO table(`name`) VALUES(:name)");
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
foreach($values as $name) {
$stmt->execute();
}
Transactions
Here's an example of using transactions in PDO: (note that calling beginTransaction() turns off auto commit automatically):
try {
$db->beginTransaction();
$db->exec("SOME QUERY");
$stmt = $db->prepare("SOME OTHER QUERY?");
$stmt->execute(array($value));
$stmt = $db->prepare("YET ANOTHER QUERY??");
$stmt->execute(array($value2, $value3));
$db->commit();
} catch(PDOException $ex) {
//Something went wrong rollback!
$db->rollBack();
echo $ex->getMessage();
}