より成熟したデータベースの多くは、準備されたステートメントの概念をサポートしています。
準備されたステートメントとは何ですか?これは、実行する SQL のコンパイルされたテンプレートと考えてください。変数パラメーターを使用してカスタマイズできます。準備されたステートメントには、次の 2 つの大きな利点があります。
クエリは 1 回だけ解析 (または前処理) する必要がありますが、同じパラメータまたは異なるパラメータを使用して複数回実行できます。クエリの準備が完了すると、データベースはクエリを実行するための計画を分析、コンパイル、最適化します。複雑なクエリの場合、このプロセスには時間がかかり、同じクエリを異なるパラメータで複数回繰り返す必要がある場合、アプリケーションの速度が大幅に低下する可能性があります。準備されたステートメントを使用すると、分析/コンパイル/最適化サイクルの繰り返しを回避できます。簡単に言えば、準備されたステートメントは使用するリソースが少ないため、より高速に実行されます。
準備されたステートメントに指定されるパラメーターは引用符で囲む必要はありません。これはドライバーによって自動的に処理されます。アプリケーションでプリペアド ステートメントのみを使用する場合、SQL インジェクションは確実に発生しません。 (ただし、クエリの他の部分がエスケープされていない入力から構築されている場合は、依然として SQL インジェクションのリスクが存在します)。
プリペアド ステートメントは非常に便利ですが、その唯一の機能は、ドライバーがサポートしていない場合に PDO が処理をシミュレートすることです。これにより、データベースにそのような機能があるかどうかに関係なく、アプリケーションは同じデータ アクセス パターンを使用できるようになります。
次の例では、対応する名前付きプレースホルダーを名前と値で置き換えることにより、挿入クエリを実行します。
<?php$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");$stmt->bindParam(':name', $name);$stmt- >bindParam(':value', $value);//行を挿入 $name = 'one';$value = 1;$stmt->execute();//異なる値を持つ別の行を挿入 $name = 'two';$value = 2;$stmt->execute();?>
次の例では、プレースホルダーを名前と値に置き換えて挿入クエリを実行します。
<?php$stmt = $dbh->prepare("レジストリ (名前, 値) 値 (?, ?) に挿入します");$stmt->bindParam(1, $name);$stmt->bindParam(2, $value);//行を挿入 $name = 'one';$value = 1;$stmt->execute();//異なる値を持つ別の行を挿入 $name = 'two';$value = 2;$stmt->execute();?>
次の例では、提供されたフォームのキー値に基づいてデータを取得します。ユーザー入力は自動的に引用されるため、SQL インジェクション攻撃の危険はありません。
<?php$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");if ($stmt->execute(array($_GET['name']))) { while ($row = $stmt->fetch()) { print_r($row) }}?>
データベース ドライバーがサポートしている場合、アプリケーションは出力パラメーターと入力パラメーターをバインドすることもできます。出力パラメーターは、ストアド プロシージャから値を取得するためによく使用されます。出力パラメータをバインドするときに、指定されたパラメータの長さを知っておく必要があるため、出力パラメータの使用は入力パラメータよりも少し複雑です。パラメータにバインドされた値が推奨される長さを超える場合、エラーが生成されます。
<?php$stmt = $dbh->prepare("CALL sp_returns_string(?)");$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000) // ストアド プロシージャを呼び出します $stmt-> execute();print "プロシージャが $return_value を返しましたn";?>
出力パラメーターと同様の構文を使用して、入力値と出力値の両方を持つパラメーターを指定することもできます。次の例では、文字列「hello」がストアド プロシージャに渡され、ストアド プロシージャが返されるときに、hello がストアド プロシージャによって返された値に置き換えられます。
<?php$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");$value = 'hello';$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000 ); // ストアド プロシージャを呼び出します $stmt->execute();print "プロシージャが返されました$値n";?>
<?php$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");$stmt->execute(array($_GET['name']));// プレースホルダー記号値全体で使用する必要があります $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");$stmt->execute(array("%$_GET[name]%"));?>