預處理語句對於防止MySQL 注入是非常有用的。
預處理語句及綁定參數
預處理語句用於執行多個相同的SQL 語句,並且執行效率更高。
預處理語句的工作原理如下:
預處理:建立SQL 語句範本並傳送到資料庫。預留的值使用參數"?" 標記。例如:
INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)
資料庫解析,編譯,對SQL語句模板執行查詢最佳化,並儲存結果不輸出。
執行:最後,將應用綁定的值傳遞給參數("?" 標記),資料庫執行語句。應用可以多次執行語句,如果參數的值不一樣。
相較於直接執行SQL語句,預處理語句有兩個主要優點:
預處理語句大大減少了分析時間,只做了一次查詢(雖然語句多次執行)。
綁定參數減少了伺服器頻寬,你只需要發送查詢的參數,而不是整個語句。
預處理語句針對SQL注入是非常有用的,因為參數值發送後使用不同的協議,確保了資料的合法性。
MySQLi 預處理語句
以下實例在MySQLi 中使用了預處理語句,並綁定了對應的參數:
實例(MySQLi 使用預處理語句)
<?php $servername = " localhost " ; $username = " username " ; $password = " password " ; $dbname = " myDB " ; //建立連接$conn = new mysqli ( $servername , $username , $password , $dbname ) ; //偵測連接if ( $conn -> connect_error ) { die ( "連線失敗: " . $conn -> connect_error ) ; } //預處理及綁定$stmt = $conn -> prepare ( " INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?) " ) ; $stmt -> bind_param ( " sss " , $firstname , $lastname , $email ) ; //設定參數並執行$firstname = " John " ; $lastname = " Doe " ; $email = " [email protected] " ; $stmt -> execute ( ) ; $firstname = " Mary " ; $lastname = " Moe " ; $email = " [email protected] " ; $stmt -> execute ( ) ; $firstname = " Julie " ; $lastname = " Dooley " ; $email = " [email protected] " ; $stmt -> execute ( ) ; echo "新記錄插入成功" ; $stmt -> close ( ) ; $conn -> close ( ) ; ?>解析以下實例的每行程式碼:
"INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)"
在SQL 語句中,我們使用了問號(?),在此我們可以將問號替換為整數型,字串,雙精確度浮點型和布林值。
接下來,讓我們來看下bind_param() 函數:
$stmt->bind_param("sss", $firstname, $lastname, $email);
此函數綁定了SQL 的參數,並告訴資料庫參數的值。 "sss" 參數列處理其餘參數的資料型態。 s 字元告訴資料庫此參數為字串。
參數有以下四種類型:
i - integer(整數)
d - double(雙精準度浮點型)
s - string(字串)
b - BLOB(binary large object:二進位大物件)
每個參數都需要指定類型。
透過告訴資料庫參數的資料類型,可以降低SQL 注入的風險。
| 注意:如果你想插入其他資料(使用者輸入),對資料的驗證是非常重要的。 |
---|
PDO 中的預處理語句
以下實例我們在PDO 中使用了預處理語句並綁定參數:
實例(PDO 使用預處理語句)
<?php $servername = " localhost " ; $username = " username " ; $password = " password " ; $dbname = " myDBPDO " ; try { $conn = new PDO ( " mysql:host= $servername ;dbname= $dbname " , $username , $password ) ; //設定PDO 錯誤模式為異常 $conn -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION ) ; //預處理SQL 並綁定參數 $stmt = $conn -> prepare ( " INSERT INTO MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email) " ) ; $stmt -> bindParam ( ' :firstname ' , $firstname ) ; $ stmt -> bindParam ( ' :lastname ' , $lastname ) ; $stmt -> bindParam ( ' :email ' , $email ) ; //插入行 $firstname = " John " ; $lastname = " Doe " ; $email = " [email protected] " ; $stmt -> execute ( ) ; //插入其他行 $firstname = " Mary " ; $lastname = " Moe " ; $email = " [email protected] " ; $stmt -> execute ( ) ; //插入其他行 $firstname = " Julie " ; $lastname = " Dooley " ; $email = " [email protected] " ; $stmt -> execute ( ) ; echo "新記錄插入成功" ; } catch ( PDOException $e ) { echo " Error: " . $e -> getMessage ( ) ; } $conn = null ; ?>