プリペアド ステートメントは、MySQL インジェクションを防ぐのに非常に役立ちます。
準備されたステートメントとバインドされたパラメーター
準備されたステートメントは、複数の同一の SQL ステートメントをより効率的に実行するために使用されます。
準備されたステートメントは次のように機能します。
前処理: SQL ステートメントのテンプレートを作成し、データベースに送信します。予約された値にはパラメータ「?」が付けられます。例えば:
INSERT INTO MyGuests (名、姓、電子メール) VALUES(?, ?, ?)
データベースの解析、コンパイル、SQL ステートメント テンプレートでのクエリの最適化、および出力なしの結果の保存。
実行: 最後に、アプリケーションにバインドされた値がパラメータ (「?」マーク) に渡され、データベースがステートメントを実行します。パラメータ値が異なる場合、アプリケーションはステートメントを複数回実行できます。
SQL ステートメントを直接実行する場合と比較して、プリペアド ステートメントには 2 つの主な利点があります。
プリペアド ステートメントを使用すると、(ステートメントは複数回実行されますが) クエリが 1 つだけ作成されるため、分析時間が大幅に短縮されます。
パラメーターをバインドするとサーバーの帯域幅が削減され、ステートメント全体ではなくクエリのパラメーターのみを送信する必要があります。
プリペアド ステートメントは、パラメーター値の送信後にさまざまなプロトコルが使用され、データの有効性が保証されるため、SQL インジェクションに非常に役立ちます。
MySQLi プリペアドステートメント
次の例では、MySQLi で準備されたステートメントを使用し、対応するパラメーターをバインドします。
例 (MySQLi はプリペアドステートメントを使用します)
<?php $ servername = " localhost " ; $ username = " username " ; $ dbname = " myDB " ;$conn =新しいmysqli ( $servername , $username , $password , $dbname ) ; //接続を検出します。
もし( $conn -> connect_error ) { die ( "接続に失敗しました: " . $conn - > connect_error ) ; //前処理とバインド$stmt = $conn -> prepare ( " INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?) " ) ; $stmt -> binding_param ( " sss " , $firstname , $lastname , $email ) ; //パラメータを設定して実行$ firstname = "ジョン" ; $ lastname = " [email protected] " ; $ stmt = "メアリー" ; " [email protected] " ; $ stmt - >実行( ) ; $ firstname = "ジュリー" ; $ email = " [email protected] " ; $stmt - >実行( ) ; "新しいレコードが正常に挿入されました" ; $ stmt - > close ( ) ;次の例のコードの各行を解析します。
「MyGuests (名、姓、メールアドレス) VALUES(?, ?, ?) に挿入」
SQL ステートメントでは疑問符 (?) を使用しますが、ここでは疑問符を整数、文字列、倍精度浮動小数点、ブール値に置き換えることができます。
次に、bind_param() 関数を見てみましょう。
$stmt->bind_param("sss", $firstname, $lastname, $email);
この関数は SQL パラメータをバインドし、データベースにパラメータの値を伝えます。 「sss」パラメータ列は、残りのパラメータのデータ型を処理します。 s 文字は、パラメータが文字列であることをデータベースに伝えます。
パラメータには次の 4 種類があります。
i - 整数 (整数型)
d - double(倍精度浮動小数点型)
s - 文字列
b - BLOB (バイナリ ラージ オブジェクト: バイナリ ラージ オブジェクト)
各パラメータには指定された型が必要です。
データベースにパラメータのデータ型を伝えることで、SQL インジェクションのリスクを軽減できます。
 | 注:他のデータ (ユーザー入力) を挿入する場合は、データの検証が非常に重要です。 |
|---|
PDO のプリペアドステートメント
次の例では、準備されたステートメントを使用し、PDO でパラメーターをバインドします。
例 (PDO は準備されたステートメントを使用します)
<?php $ servername = " localhost " ; $ username = " username " ; $ dbname = " myDBPDO " ; { $conn =新しい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 -> bindingParam ( ' :firstname ' , $firstname ) ; stmt- > bindParam ( ' :lastname ' , $lastname ) ; $stmt- > bindParam ( ' :email ' , $email ) ; //行を挿入 $firstname = " John " ; $ lastname = " Doe " ; $ email = " [email protected] " ; //他の行を挿入 $ firstname = " Mary " ; $ lastname = " [email protected] " ; $ stmt - > execute ( ) ; $ firstname = "ジュリー" ; $ lastname = " [email protected] " ;"新しいレコードが正常に挿入されました" ; catch ( PDOException $e ) { エコー"エラー: " . $e - > getMessage ( ) ; $conn = null ? >