Щоб відповісти на ваші проблеми:
MySQL> = 5.1.17 (або> = 5.1.21 для операторів PREPARE
та EXECUTE
операторів) може використовувати підготовлені оператори у кеш-запитах . Отже, ваша версія MySQL + PHP може використовувати підготовлені оператори з кешем запитів. Однак уважно зверніть увагу на застереження щодо результатів кешування запитів у документації на MySQL. Є багато видів запитів, які не можуть бути кешовані або марні, навіть якщо вони кешовані. На мій досвід, кеш запитів так чи інакше не дуже великий виграш. Запити та схеми потребують спеціальної побудови, щоб максимально використовувати кеш. Часто кешування на рівні додатків все-таки стає необхідним у довгостроковій перспективі.
Рідна підготовка не має ніякого значення для безпеки. Псевдопідготовлені висловлювання все-таки вийдуть із значень параметрів запиту, це буде просто виконано в бібліотеці 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;
}