За да отговорите на вашите притеснения:
-
MySQL>=5.1.17 (или>=5.1.21 за
PREPARE
иEXECUTE
оператори) може да използва подготвени оператори в кеша на заявките . Така че вашата версия на MySQL+PHP може да използва подготвени изрази с кеша на заявките. Въпреки това, обърнете внимание на предупрежденията за кеширане на резултатите от заявката в документацията на MySQL. Има много видове заявки, които не могат да бъдат кеширани или които са безполезни, въпреки че са кеширани. Според моя опит кешът на заявките така или иначе често не е много голяма печалба. Заявките и схемите се нуждаят от специална конструкция, за да се използва максимално кеша. Често кеширането на ниво приложение все пак се оказва необходимо в дългосрочен план. -
Приготвянето на Native не прави никаква разлика за сигурността. Псевдо-подготвените оператори ще продължат да избягват стойностите на параметрите на заявката, просто ще бъде направено в PDO библиотеката с низове вместо на MySQL сървъра, използвайки двоичния протокол. С други думи, един и същ PDO код ще бъде еднакво уязвим (или не-уязвим) към атаки с инжектиране, независимо от вашия
EMULATE_PREPARES
настройка. Единствената разлика е къде се извършва подмяната на параметъра - с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;
}