PDO:預處理語句(參數化查詢)

@(PDO(PHP data object/PHP數據對象))[PDO|預處理語句|參數化查詢]

PDO Tutorial for MySQL Developers
Using Prepared Statements to Stop Injection Attacks

The 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 as parametrized queries.

PDO::prepare

Paste_Image.png

在執(zhí)行之前,對一條語句進行預處理,并返回一個語句對象。

預處理一條 SQL 語句,以便 PDOStatement::execute() 方法執(zhí)行。該 SQL 語句可以包含 0 或更多個命名參數(:name)或問號參數(?),這些參數的真實值在語句執(zhí)行的時候會被替換掉。使用這些參數綁定所有的用戶輸入的數據,不要在查詢中直接包含用戶輸入的數據。

返回值:

如果數據庫服務器成功地預處理了該語句,PDO::prepare() 將會返回一個 PDOStatement 對象;否則,返回 false 或 拋出 PDOException(依 error handling 而定)。

模擬的預處理語句并沒有與數據庫服務器進行通信,所以PDO::prepare()并沒有檢查該語句。

PDOStatement::bindParam

Paste_Image.png

原來 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 bindValue and not bindParam. Trying to bind a parameter by reference will generate a Fatal Error and this cannot be caught by PDOException either.
但如果需要循環(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

Paste_Image.png

Binds a value to a parameter.

綁定 一個值(可以是 $name'Jack' 的形式) 一個參數(:name?參數 ,可以是 :name從1 開始的索引 的形式)。

綁定 一個值 預處理語句中對應的命名占位符或問號占位符。

返回值:

成功則返回 true,失敗則返回 false

例如:

$stm->bindValue(':name',$name);  
$stm->bindValue(':name','Jack');  

PDOStatement::execute

Paste_Image.png

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 bindValue and not bindParam. Trying to bind a parameter by reference will generate a Fatal Error and this cannot be caught by PDOException either.
但如果需要循環(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();
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容