[解決済み] PDO MySQL。PDO::ATTR_EMULATE_PREPARES を使うか使わないか?
質問
これは、私がこれまで読んだことのある
PDO::ATTR_EMULATE_PREPARES
:
- MySQL のネイティブな prepare はクエリキャッシュをバイパスするので、PDO の prepare エミュレーションの方がパフォーマンス的に優れています。 .
- MySQL のネイティブな準備は、セキュリティ(SQL インジェクションの防止)には優れています。 .
- エラー報告には MySQL のネイティブな prepare が適しています。 .
これらのステートメントのどれがどれだけ真実なのか、もうわかりません。MySQL インターフェースを選択する際の私の最大の関心事は、SQL インジェクションを防止することです。2 番目の懸念はパフォーマンスです。
私のアプリケーションは現在、手続き型 MySQLi (プリペアドステートメントなし) を使用しており、クエリキャッシュをかなり利用しています。1 つのリクエストでプリペアド ステートメントを再使用することはほとんどありません。私は、名前つきパラメーターとプリペアドステートメントのセキュリティのために PDO への移行を始めました。
使っているのは
MySQL 5.1.61
と
PHP 5.3.2
を残すべきでしょうか。
PDO::ATTR_EMULATE_PREPARES
を有効にしておくべきかどうか?クエリ キャッシュのパフォーマンスとプリペアド ステートメントのセキュリティの両方を確保する方法はありますか?
どのように解決するのですか?
お悩みにお答えします。
-
MySQL >= 5.1.17 (または >= 5.1.21 は
PREPARE
とEXECUTE
の文) はクエリキャッシュでプリペアドステートメントを使用することができます。 . つまり、あなたのバージョンのMySQL+PHPは、クエリキャッシュでプリペアドステートメントを使用することができます。しかし、MySQL のドキュメントにあるクエリ結果のキャッシュに関する注意事項をよく覚えておいてください。キャッシュできないクエリや、キャッシュしても意味がないクエリも多くあります。私の経験では、クエリキャッシュはいずれにせよあまり大きな勝利にはならないことが多いです。キャッシュを最大限に活用するためには、クエリやスキーマを特別に構築する必要があります。多くの場合、アプリケーションレベルのキャッシュは、長い目で見れば、いずれにせよ必要なものとなります。 -
ネイティブのプリペアドは、セキュリティ上何の違いもありません。擬似プリペアド文はクエリパラメータ値をエスケープしますが、それはバイナリプロトコルを使用する MySQL サーバー上ではなく、PDO ライブラリでストリングを使用して行われるだけです。言い換えれば、同じ PDO コードが、あなたの
EMULATE_PREPARES
の設定に関係なく、同じ PDO コードがインジェクション攻撃に対して同じように脆弱 (あるいは脆弱でない) になります。唯一の違いは、パラメータの置き換えが行われる場所です。EMULATE_PREPARES
がある場合は PDO ライブラリで行われます。EMULATE_PREPARES
がない場合は、MySQL サーバで発生します。 -
がなければ
EMULATE_PREPARES
を指定すると、実行時ではなく準備時に構文エラーが発生する可能性があります。EMULATE_PREPARES
では実行時にのみ構文エラーが発生します。なぜなら PDO は実行時まで MySQL に渡すクエリを持っていないからです。また これはあなたが書くコードに影響します。 ! を使用している場合は特にPDO::ERRMODE_EXCEPTION
!
追加の検討事項です。
-
には固定費がかかります。
prepare()
(ネイティブのプリペアドステートメントを使用) であるためprepare();execute()
はエミュレートされたプリペアドステートメントを使ったプレーンテキストクエリの発行より少し遅くなるかもしれません。多くのデータベースシステムではprepare()
のクエリプランもキャッシュされ、複数の接続で共有されることがありますが、MySQL ではこのようなことはないと思います。そのため、プリペアド ステートメント オブジェクトを複数のクエリで再利用しない場合、全体的な実行速度が低下する可能性があります。
最後の推奨事項として
MySQL+PHP の古いバージョンでは、プリペアドステートメントをエミュレートすべきですが、最近のバージョンではエミュレートをオフにすべきです。
PDOを使用するいくつかのアプリケーションを書いた後、私は最適と思われる設定を持つPDO接続関数を作りました。おそらくこのようなものを使用するか、または好みの設定に調整する必要があります。
/**
* Return PDO handle for a MySQL connection using supplied settings
*
* Tries to do the right thing with different php and mysql versions.
*
* @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
* @return PDO
* @author Francis Avila
*/
function connect_PDO($settings)
{
$emulate_prepares_below_version = '5.1.17';
$dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
$dsnarr = array_intersect_key($settings, $dsndefaults);
$dsnarr += $dsndefaults;
// connection options I like
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
// connection charset handling for old php versions
if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
}
$dsnpairs = array();
foreach ($dsnarr as $k => $v) {
if ($v===null) continue;
$dsnpairs[] = "{$k}={$v}";
}
$dsn = 'mysql:'.implode(';', $dsnpairs);
$dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);
// Set prepared statement emulation depending on server version
$serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
$emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
return $dbh;
}
関連
-
[解決済み】PHPで空の値からデフォルトオブジェクトを作成する?
-
[解決済み】「初期通信パケットの読み込み」でMySQLサーバーに接続できなくなり、システムエラーになる。0
-
[解決済み】php, mysql - データベースへの接続数が多すぎるエラー
-
[解決済み] php5パッケージのインストール候補がない (Ubuntu 16.04)
-
[解決済み] [Solved] Fatal error: 非オブジェクトのメンバ関数fetch_assoc()の呼び出し [重複]。
-
[解決済み] MySQLでdatetimeとtimestampのどちらのデータ型を使用すべきですか?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] どのような場合に '$this' よりも 'self' を使うべきですか?
-
[解決済み] ブーリアン値を格納するために使用するMySQLデータ型
-
[解決済み] PDO Preparedが1つのクエリで複数行を挿入する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】PHP 7.2 - Warning: count(): パラメータは配列かCountableを実装したオブジェクトでなければならない [解決済み]
-
[解決済み】新しいPHPMailerはPHPMailerAutoload.phpが必要?
-
[解決済み] php5パッケージのインストール候補がない (Ubuntu 16.04)
-
[解決済み] 警告:mysqli_fetch_array()は、パラメータ1がmysqli_resultであることを期待する、オブジェクトはで指定された。
-
[解決済み] 入力ファイルが指定されていない
-
[解決済み】Netbeans 7.4 for PHPで「スーパーグローバルな$_POST配列に直接アクセスしないでください」という警告が発生する。
-
MacでPHPを実行した際に、メモリサイズが134217728バイトも消費される問題の解決方法について
-
[解決済み】MySQLのカラム数が1行目の値数と一致しない【非公開
-
[解決済み】phpのシンタックスエラー、予期しないT_IFエラーを修正する方法は?[クローズド]。
-
[解決済み] mysql_real_escape_string() を回避する SQL インジェクション