48

PDOMySQLのエスケープには、よりも使用したほうがよいと言われていますmysql_real_escape_string

たぶん私は脳死の日を過ごしているかもしれません(またはそれは私が想像力の範囲ではないという事実であり、自然なプログラマーであり、PHPに関してはまだ初心者の段階にあります)が、 PHPのマニュアルを確認し、PDOのエントリを読んでください。私は、PDOが実際に何であるか、そしてなぜそれがを使用するよりも優れているのかについてはまだはっきりしていませんmysql_real_escape_string。これは、OOPの複雑さをまだ理解していないためかもしれませんが(OOPと関係があると思います)、変数と配列値の前にコロンがあるように見えるという事実を除けば、それが実際に何であるか、そしてあなたがそれをどのように使用するか(そしてなぜそれがより良いのか)はまだわかりませんmysql_real_escape_string。(それはまた、私が「クラス」が何であるかを明確に理解していないという事実と関係があるかもしれません。したがって、「PDOクラス」を読んだとき、私は本当に賢くありません)。

MySQL Webサイトの「開発者ゾーン」ビットに関する記事を1つか2つ読んだのですが、まだはっきりしていません。現時点では何なのかわからないので、今は少し遠いのではないかと思いますが、それでも教育を広げて、どうすれば改善できるのか興味があります。

誰かが「平易な英語」で私にPDOとは何かを説明できますか(または平易な英語で書かれた主題に関する何かの方向に私を向けてください)、そしてあなたはそれをどのように使うのですか?

4

6 に答える 6

58

あなたの質問はより一般的な概要を目的としていますが、現在の回答は詳細になるので、試してみます:

PDO クラスは、データベースと対話するために必要なすべての機能をカプセル化することを目的としています。これは、「メソッド」(関数の OO パーラー) と「プロパティ」(変数の OO パーラー) を定義することによって行われます。データベースと対話するために現在使用しているすべての「標準」関数の完全な代替としてそれらを使用します。

したがって、一連の「mysql_doSomething()」関数を呼び出して、その結果を独自の変数に格納する代わりに、PDO クラスからオブジェクトを「インスタンス化」します (「クラス」= 抽象定義、「オブジェクト」= 具体的な、使用可能なインスタンスクラスの)、そのオブジェクトのメソッドを呼び出して同じことを行います。

例として、PDO を使用しない場合、次のようにします。

// Get a db connection
$connection = mysql_connect('someHost/someDB', 'userName', 'password');
// Prepare a query
$query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'";
// Issue a query
$db_result = mysql_query($query);
// Fetch the results
$results = array();
while ($row = mysql_fetch_array($db_result)) {
  $results[] = $row;
}

これはPDOを使用した場合と同等ですが:

// Instantiate new PDO object (will create connection on the fly)
$db = new PDO('mysql:dbname=someDB;host=someHost');
// Prepare a query (will escape on the fly)
$statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison');
// $statement is now a PDOStatement object, with its own methods to use it, e.g.
// execute the query, passing in the parameters to replace
$statement->execute(array(':comparison' => $comparison));
// fetch results as array
$results = $statement->fetchAll();

したがって、一見すると、構文を除いて大きな違いはありません。しかし、PDO バージョンにはいくつかの利点があり、最大の利点はデータベースの独立性です。

代わりに PostgreSQL データベースと対話する必要がある場合は、インスタンス化呼び出しでのみ変更mysql:します。古い方法では、すべての「mysql_doSomething()」関数を対応する「pg_doSomthing()」関数に置き換えて、すべてのコードを調べなければなりません (パラメータ処理の潜在的な違いを常にチェックします)。サポートされている他の多くのデータベース エンジンでも同じことが言えます。pgsql:new PDO()

質問に戻ると、PDO は基本的に、同じことを達成するための別の方法を提供するだけでなく、いくつかのショートカット/改善/利点を提供します。たとえば、エスケープは、使用しているデータベース エンジンに必要な適切な方法で自動的に行われます。また、パラメーターの置換 (SQL インジェクションの防止、例には示されていません) ははるかに簡単で、エラーが発生しにくくなっています。

他の利点について理解するには、いくつかの OOP の基礎を読む必要があります。

于 2009-11-16T14:51:35.040 に答える
40

私は PDO にあまり詳しくありませんが、「準備されたステートメント」とエスケープされた文字列には違いがあります。エスケープとは、許可されていない文字列をクエリから削除することですが、準備されたステートメントとは、どのような種類のクエリが期待されるかをデータベースに伝えることです。

クエリには複数の部分があります

このように考えてください: データベースにクエリを与えるとき、いくつかの別々のことをデータベースに伝えています。たとえば、「選択をお願いします」などです。もう1つは、「ユーザー名が次の値である行に制限する」ことです。

クエリを文字列として作成してデータベースに渡すと、完全な文字列を取得するまでデータベースはどちらの部分も認識しません。あなたはこれを行うかもしれません:

'SELECT * FROM transactions WHERE username=$username'

その文字列を取得すると、それを解析して、「これは aSELECTであるWHERE」と判断する必要があります。

パーツを混同する

悪意のあるユーザーが自分のユーザー名を として入力したとしますbillysmith OR 1=1。注意しないと、それを文字列に入れて、次のようになる可能性があります。

'SELECT * FROM transactions WHERE username=billysmith OR 1=1'

... 1 は常に 1 であるため、すべてのユーザーのすべてのトランザクションが返されます。おっと、ハッキングされました!

何が起こったのですか?データベースは、クエリでどの部分が期待されるかを認識していなかったため、文字列を解析しただけです。に があり、それを満たすことができる 2 つの条件があることWHEREは驚きではありませんでした。OR

部品をまっすぐに保つ

何を期待するか、つまり、条件SELECTが1 つしかないを知っていればWHERE、悪意のあるユーザーはそれを騙すことはできませんでした。

準備されたステートメントを使用すると、正しい期待を与えることができます。データベースに「私はあなたに を送信しようとしています。私があなたに提供しようとしている文字列はSELECT行に限定されWHERE username =ます。それだけです。クエリには他の部分はありません。準備はできていますか? ? OK、ここにユーザー名と比較する文字列があります。"

データベースはだまされず、username列に実際の文字列「billysmith OR 1=1」が含まれる行のみを返します。誰もそのユーザー名を持っていない場合、何も返されません。

準備済みステートメントのその他の利点

セキュリティ上の利点に加えて、プリペアド ステートメントにはいくつかの速度上の利点があります。

  • それらはさまざまなパラメーターで再利用できます。これは、データベースが基本的に何を求めようとしているのかをすでに知っているため、最初から新しいクエリを作成するよりも高速です。すでに「クエリプラン」を構築しています。
  • 一部のデータベース (Postgres はその 1 つだと思います) は、準備されたステートメントを取得するとすぐに、使用するパラメーターを実際に送信する前に、クエリ プランの作成を開始します。そのため、最初のクエリでも高速化が見られる場合があります。

別の説明については、 Theo's answer hereを参照してください。

于 2009-11-16T13:34:35.820 に答える
16

mysql_real_escape_stringとは異なり、PDOではデータ型を強制できます。

<?php
/* 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();
?>

上記の例では、最初のパラメーターcaloriesは整数(PDO :: PARAM_INT)である必要があることに注意してください。

第二に、私にとって、PDOパラメーター化されたクエリは読みやすいです。私はむしろ読みたいです:

SELECT name FROM user WHERE id = ? AND admin = ? 

よりも

SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin);

第三に、パラメータを正しく引用する必要はありません。PDOがそれを処理します。たとえば、mysql_real_query_string:

SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param

vs

SELECT * FROM user WHERE name = ?

最後に、PDOを使用すると、PHPデータ呼び出しを変更せずに、アプリを別のデータベースに移植できます。

于 2009-11-16T14:20:59.640 に答える
14

次の行に沿って何かを書くと想像してください。

$query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id);

1 OR 1=1$id の可能性があり、テーブルからすべてのレコードを取得するため、これはインジェクションからあなたを救いません。$id を正しいデータ型 (その場合は int) にキャストする必要があります。

pdo には別の利点があります。それは、データベース バックエンドの互換性です。

于 2009-11-16T13:15:01.553 に答える
3

SQL インジェクションを防ぐだけでなく、PDO を使用すると、クエリを 1 回準備して複数回実行することができます。クエリが複数回 (たとえば、ループ内で) 実行される場合、この方法はより効率的である必要があります (古いバージョンの MySQL では常にそうであるとは限らないため、「すべき」と言います)。準備/バインド方法も、私が扱った他の言語とより一致しています。

于 2009-11-16T13:25:23.263 に答える
3

PDO が mysql_real_escape_string よりも MySQL クエリ/クエリ文字列をエスケープするのに適しているのはなぜですか?

「逃げる」だけでは意味がないからです。
さらに、それは別の比類のないものです。

エスケープに関する唯一の問題は、誰もがそれをある種の「保護」と見なして誤解していることです。
誰もが「クエリを保護した」という意味で「変数をエスケープしました」と言います。
一人で逃げることは保護とは何の関係もありませんが。

I escaped and quoted my dataの場合、保護は大まかに達成できますが、たとえば識別子など、どこでも適用できるわけではありません(ちなみに、PDOも同様です)。

したがって、答えは次のとおりです。

  • PDO は、バインドされた値のエスケープを行うときに、エスケープだけでなく引用も適用します。そのため、PDO の方が優れています。
  • 「エスケープ」は「保護」と同義ではありません。ざっくり「エスケープ+引用」です。
  • ただし、一部のクエリ部分では、両方の方法が適用できません。
于 2012-04-12T13:29:48.670 に答える