私はいくつかのコードを分析していますが、これに遭遇しました、
$sql = 'SELECT page.*, author.name AS author, updator.name AS updator '
. 'FROM '.TABLE_PREFIX.'page AS page '
. 'LEFT JOIN '.TABLE_PREFIX.'user AS author ON author.id = page.created_by_id '
. 'LEFT JOIN '.TABLE_PREFIX.'user AS updator ON updator.id = page.updated_by_id '
. 'WHERE slug = ? AND parent_id = ? AND (status_id='.Page::STATUS_REVIEWED.' OR status_id='.Page::STATUS_PUBLISHED.' OR status_id='.Page::STATUS_HIDDEN.')';
「?」って何だろうWHEREステートメントで行います。何らかのパラメーターホルダーですか?
準備された文は「?」を使用しますMySQLで、パラメーターをステートメントにバインドできるようにします。適切に使用すれば、SQLインジェクションに対してより安全であると高く評価されます。また、リクエストは一度コンパイルするだけで再利用できるため、より高速なSQLクエリが可能になります。
疑問符は、後で置き換えられるパラメーターを表します。パラメーター化されたクエリを使用する方が、パラメーターをクエリに直接埋め込むよりも安全です。
SQL Serverはこれをパラメーター化クエリと呼び、Oracleはバインド変数と呼びます。
使用法は、クエリを実行する言語によって異なります。
PHPからの使用例を次に示します。
仮定して $mysqli
はデータベース接続であり、people
は4列のテーブルです。
$stmt = $mysqli->prepare("INSERT INTO People VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $firstName, $lastName, $email, $age);
'sssd'
は、残りのパラメータを識別するフラグです。s
は文字列を表し、d
は数字を表します。
?
はMySQLで特別な意味を持ちませんWHERE =
ステートメント
PHP stdlibやRailsのようなWebフレームワークなど、いくつかの外部インターフェースに対して特別な意味を持つだけです。
?
は、次の構文エラーです。
CREATE TABLE t (s CHAR(1));
SELECT * FROM t WHERE s = ?;
引用符で囲まれていないため、および:
INSERT INTO t VALUES ('a');
INSERT INTO t VALUES ("?");
SELECT * FROM t WHERE s = '?';
それは返します:
s
?
したがって、明らかに特別な意味はありません。
レールの例
Railsでは、疑問符は、ライブラリのプログラミング言語(Ruby)の変数で指定された引数に置き換えられます。例:
Table.where("column = ?", "value")
また、バグやSQLインジェクションを回避するために引数を自動的に引用し、次のようなステートメントを生成します。
SELECT * FROM Table WHERE column = 'value';
次のような場合、クォートは私たちを救うでしょう:
Table.where("column = ?", "; INJECTION")
MySQL 5.0準備済みステートメント
MySQL 5.0は、Webフレームワークの疑問符と同様のセマンティクスを持つ 準備済みステートメント機能 を追加しました。
ドキュメントの例:
PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
SET @a = 3;
SET @b = 4;
EXECUTE stmt1 USING @a, @b;
出力:
hypotenuse
5
また、これらは期待どおりに特殊文字をエスケープします。
PREPARE stmt1 FROM 'SELECT ? AS s';
SET @a = "'";
EXECUTE stmt1 USING @a;
出力:
s
'
これらは準備された声明であり、準備された声明は2つの主要な利点を提供します:
クエリは1回だけ解析(または準備)する必要がありますが、同じまたは異なるパラメーターを使用して複数回実行できます。クエリが準備されると、データベースはクエリの実行計画を分析、コンパイル、最適化します。複雑なクエリの場合、このプロセスは時間がかかり、同じパラメータを異なるパラメータで何度も繰り返す必要がある場合、アプリケーションの速度が著しく低下します。準備されたステートメントを使用することにより、アプリケーションは分析/コンパイル/最適化サイクルを繰り返すことを避けます。これは、準備されたステートメントが使用するリソースが少ないため、実行が高速になることを意味します。
準備済みステートメントのパラメーターを引用する必要はありません。ドライバーはこれを自動的に処理します。アプリケーションが準備済みステートメントのみを使用する場合、開発者はSQLインジェクションが発生しないことを確認できます(ただし、クエリの他の部分がエスケープされていない入力で構築されている場合、SQLインジェクションは引き続き可能です)。