あなたの懸念に答えるために:
MySQL> = 5.1.17(またはPREPARE
andEXECUTE
ステートメントの場合は> = 5.1.21)は、クエリキャッシュでプリペアドステートメントを使用できます。したがって、MySQL + PHPのバージョンでは、クエリキャッシュでプリペアドステートメントを使用できます。ただし、MySQLドキュメントでクエリ結果をキャッシュする際の注意事項に注意してください。キャッシュできないクエリや、キャッシュしても役に立たないクエリにはさまざまな種類があります。私の経験では、クエリキャッシュは、とにかくそれほど大きな勝利にはならないことがよくあります。クエリとスキーマは、キャッシュを最大限に活用するために特別な構築が必要です。多くの場合、アプリケーションレベルのキャッシュは、長期的にはとにかく必要になります。
ネイティブの準備はセキュリティに何の違いもありません。疑似プリペアドステートメントは引き続きクエリパラメータ値をエスケープします。バイナリプロトコルを使用するMySQLサーバーではなく、文字列を使用してPDOライブラリで実行されます。つまり、同じPDOコードは、設定に関係なく、インジェクション攻撃に対して同等に脆弱(または脆弱ではない)になりますEMULATE_PREPARES
。唯一の違いは、パラメータの置換が発生する場所です。を使用EMULATE_PREPARES
すると、PDOライブラリで発生します。がないEMULATE_PREPARES
と、MySQLサーバーで発生します。
これがないEMULATE_PREPARES
と、実行時ではなく準備時に構文エラーが発生する可能性があります。EMULATE_PREPARES
PDOには実行時までMySQLに提供するクエリがないため、実行時にのみ構文エラーが発生します。これはあなたが書くコードに影響を与えることに注意してください!特に使用している場合PDO::ERRMODE_EXCEPTION
!
追加の考慮事項:
prepare()
(ネイティブプリペアドステートメントを使用する)には固定コストがあるため、ネイティブプリペアドステートメントを使用prepare();execute()
する場合は、エミュレートされたプリペアドステートメントを使用してプレーンテキストクエリを発行するよりも少し遅くなる可能性があります。多くのデータベースシステムでは、aのクエリプラン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;
}