Per rispondere alle tue preoccupazioni:
-
MySQL>=5.1.17 (o>=5.1.21 per
PREPARE
eEXECUTE
istruzioni) può utilizzare le istruzioni preparate nella cache delle query . Quindi la tua versione di MySQL+PHP può utilizzare istruzioni preparate con la cache delle query. Tuttavia, prendi nota delle avvertenze per la memorizzazione nella cache dei risultati delle query nella documentazione di MySQL. Esistono molti tipi di query che non possono essere memorizzate nella cache o che sono inutili anche se sono memorizzate nella cache. Nella mia esperienza, la cache delle query non è spesso comunque una grande vittoria. Le query e gli schemi richiedono una costruzione speciale per sfruttare al massimo la cache. Spesso la memorizzazione nella cache a livello di applicazione finisce per essere comunque necessaria a lungo termine. -
La preparazione nativa non fa alcuna differenza per la sicurezza. Le istruzioni pseudo-preparate sfuggiranno comunque ai valori dei parametri della query, verrà semplicemente eseguita nella libreria PDO con le stringhe anziché sul server MySQL utilizzando il protocollo binario. In altre parole, lo stesso codice PDO sarà ugualmente vulnerabile (o non vulnerabile) agli attacchi injection indipendentemente dal tuo
EMULATE_PREPARES
collocamento. L'unica differenza è dove avviene la sostituzione del parametro, conEMULATE_PREPARES
, si trova nella libreria PDO; senzaEMULATE_PREPARES
, si verifica sul server MySQL. -
Senza
EMULATE_PREPARES
potresti ricevere errori di sintassi in fase di preparazione piuttosto che in fase di esecuzione; conEMULATE_PREPARES
otterrai solo errori di sintassi al momento dell'esecuzione perché PDO non ha una query da fornire a MySQL fino al momento dell'esecuzione. Tieni presente che questo influisce sul codice che scriverai ! Soprattutto se stai usandoPDO::ERRMODE_EXCEPTION
!
Una considerazione aggiuntiva:
- C'è un costo fisso per un
prepare()
(usando istruzioni preparate native), quindi unprepare();execute()
con istruzioni preparate native potrebbe essere un po' più lento rispetto all'emissione di una query testuale semplice utilizzando istruzioni preparate emulate. Su molti sistemi di database il piano di query per unprepare()
è anche memorizzato nella cache e può essere condiviso con più connessioni, ma non credo che MySQL lo faccia. Quindi, se non riutilizzi l'oggetto istruzione preparato per più query, l'esecuzione complessiva potrebbe essere più lenta.
Come consiglio finale , penso che con le versioni precedenti di MySQL+PHP dovresti emulare le istruzioni preparate, ma con le versioni più recenti dovresti disattivare l'emulazione.
Dopo aver scritto alcune app che utilizzano PDO, ho creato una funzione di connessione PDO che ha quelle che penso siano le migliori impostazioni. Probabilmente dovresti usare qualcosa di simile o modificare le tue impostazioni preferite:
/**
* 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;
}