-2

PDOなどではなく単純なmysqlを使用した、より専門的でエラーのないアプローチは何でしょうか

私は通常これが好きです

    $sql_request = "SELECT * 
                      FROM myusers 
                          WHERE user_id = {$user_id} 
                            AND email = '{$email_address}' 
                              LIMIT 0,1";

しかし、私{$user_id}も引用する必要がありますか?

ユーザー入力を受け取っても、数字を引用しませんが、処理する前にctype_digit()をチェックします。

4

7 に答える 7

7

いいえ、数値リテラルを引用符で囲む必要はありません。

MySQLでは、数値リテラルを一重引用符で囲んでも問題ありません。これが頻繁に行われるのは、プログラマーが文字か数値かを気にせず、すべてのリテラルを引用符で囲むと便利だからだと思います。

値が引用符で囲まれている場合と、値が数値リテラルでない場合に引用符で囲まれていない場合の動作には違いがあります。たとえば、このコンテキストではid、タイプの列が与えられますINTEGER

... WHERE id = '1X'

ここ'1X'では、値が1のリテラル数値として解釈されますが、このコンテキストでは

... WHERE id = 1X

ここ1Xでは、数値リテラルではなく、列名として解釈されます。これにより、MySQLが「不明な列」例外をスローする可能性があります。

これらがどのように解釈されるかの違いを考慮してください...

... WHERE id = 'id'   -- 'id' will be interpreted as numeric literal value 0

... WHERE id = id     -- id will be interpreted as a column name

したがって、数値リテラルとして解釈されることが期待されるものが数値以外のものである場合、それは実際にはアプリケーションに最適な動作に要約されます。


私の個人的な好みは、数値リテラルを引用しないことです。これはおそらく、他のDBMSでの経験と、暗黙的なデータ変換によって引き起こされる問題を回避する必要があるためです。私の個人的な好みは、プリペアドステートメントを使用し、SQLテキストのリテラルとして値を含むステートメントを避けることです。(MySQLの場合、バインド変数を含むプリペアドステートメントはデータベースに送信されるときにプレーンSQLテキストに変換されるため、その点はほとんど意味がありません...しかし、これは私のコードではなくMySQLライブラリによって行われます。おそらく、MySQL自体ではなく、他のRDBMS(Oracle、Teradata、DB2、SQL Server)を使用した長い経験から最も多くの情報を得ています。

于 2012-08-31T19:42:08.337 に答える
2

数値を引用するときは注意することを強くお勧めします-これが私に起こったことです:最適化された、頻繁に実行されるクエリは、異常な量のIOとかなりのCPU負荷を生成しました:

SELECT blah FROM foo WHERE intcolumn='17';

選択性は数百万行のうち約100行です。私は実行計画を確認しました:見よ、運転テーブルの全表スキャン。インデックスを何度もチェックし、foo(intcolumn)ドロップして再作成しましたが、運が悪かったです。クエリ時間は分単位でした。

SELECT blah FROM foo WHERE intcolumn=17;

0.1秒未満かかりました。何らかの理由で、MySQLはすべてfoo.intcolumnをにキャストしてからVARCHAR、と比較する文字列を実行することを選択しました'17'。もちろん、これにはインデックスを無視することも含まれます。

古いバージョンのMySQLでエキゾチックなバグに遭遇した場合、私は確かに1つのことを取り除いたのかわかりません。パーサーは、使用するデータ型を知っていることを確認してください。このofocurseは、引用符で囲まれた数字では扱いにくい場合があります。

于 2012-08-31T19:51:21.040 に答える
1

PDOなどではなく単純なmysqlを使用した、より専門的でエラーのないアプローチは何でしょうか

私はそれがsprintf読みやすいコードを書いていると思います。通常、変数名を文字列に配置するのではなく、順序に基づいて後で追加します。それはそれをもう少し切り離し、読みやすくします。

また、数値データをとして指定%dして、整数値であり、文字列が挿入されにくいようにすることもできます。数値リテラルは通常、引用符を必要としません。したがってsprintf、SQLはここでうまく連携します。%s引用符が必要ですが、必要あり%dません。ただし、引用符も問題ありません。

$sql_request = "SELECT * 
                  FROM myusers 
                      WHERE user_id = '%d'
                        AND email = '%s' 
                          LIMIT 0,1";

$query = sprintf($sql_request, $user_id, mysql_real_escape_string($email_address, $link));

ただし、mysqliまたはPDOではないことについての質問を読みました。可能であれば、PDOに切り替えて、プリペアドステートメント/パラメーター化されたクエリを使用します。これが古いアプリケーションの場合は、mysql_*関数の前に何かを付けて、PDOに基づいて独自に実装し、ゆっくりと、しかし着実に古いものを新しいコードに置き換えます。

また、コードの移植を開始するのにも役立つはずのこの質問を見てください。比較的迅速に機能します。

そして、PDOに切り替える方法については:

于 2012-08-31T19:44:21.777 に答える
1

共通のコンセンサスは、SQLステートメントを補間(例)または連結された文字列として記述することは良い考えではない(つまり、専門的でもエラー防止でもない)ということです。代わりに、プリペアドステートメントを使用する必要があります。

暗黒時代に、私は次のような関数を使用しました:

// This is obsolete!!
function escape_input($s) {
  if (!ctype_digit($s))
    return "'" . mysql_real_escape_string($s) . "'";
  else
    return $s;
}

ご覧のとおり、文字列入力を引用符で囲みましたが、整数入力は引用符なしで通過できました。(悪影響なしに整数入力を引用できますが。)入力が整数であるかどうかに関係なく、すべてのMySQL入力でこの関数を使用しました。このパターンに従うように強制することで、SQLインジェクション攻撃に自分自身を開放したことはないと思います。しかし、繰り返しになりますが、私はもうこの方法で物事を行うことはありません。PDOまたはmysqli_*のプリペアドステートメントを使用します。

于 2012-08-31T19:52:00.540 に答える
0

User_id列は数値であるため、引用符で囲まないでください。ただし、数値が渡されていることを確認する必要があります。

于 2012-08-31T19:39:15.160 に答える
0

変数に数値が含まれていることを確認$user_idする限り、引用符で囲む必要はありません。

そうでない場合は、クエリが破損し、データベースが損傷する可能性があります。

より良い解決策は、PDOまたは別のライブラリを使用してプリペアドステートメントを使用することです。

于 2012-08-31T19:40:19.480 に答える
-1

引用をお勧めします。あなたは決して確信しすぎることはできません!(そして、MySQLに起こりうるエラーを処理させます)。また、変数の前後に引用符を追加することに慣れると、慣れたら常に引用符を付けることを忘れないようにして、エラーを減らすことができます。(入力もエスケープすることを忘れないでください)

または、プリペアドステートメントでPDOまたはMySQLiを使用してください!もう引用する必要はありません。(ええ、申し訳ありません。廃止されたものを本当に使用したいという質問に答えると、より良い選択肢が得られます)

于 2012-08-31T19:39:08.077 に答える