Pour répondre à vos préoccupations:
MySQL> = 5.1.17 (ou> = 5.1.21 pour les instructions PREPARE
et EXECUTE
) peut utiliser des instructions préparées dans le cache de requêtes . Ainsi, votre version de MySQL + PHP peut utiliser des instructions préparées avec le cache de requêtes. Cependant, notez attentivement les mises en garde concernant la mise en cache des résultats des requêtes dans la documentation MySQL. Il existe de nombreux types de requêtes qui ne peuvent pas être mises en cache ou qui sont inutiles même si elles sont mises en cache. D'après mon expérience, le cache de requêtes n'est pas souvent une très grande victoire de toute façon. Les requêtes et les schémas nécessitent une construction spéciale pour utiliser au maximum le cache. Souvent, la mise en cache au niveau de l'application finit par être nécessaire de toute façon à long terme.
Les préparations natives ne font aucune différence pour la sécurité. Les instructions pseudo-préparées échapperont toujours aux valeurs des paramètres de requête, cela sera juste fait dans la bibliothèque PDO avec des chaînes au lieu de sur le serveur MySQL en utilisant le protocole binaire. En d'autres termes, le même code PDO sera également vulnérable (ou non vulnérable) aux attaques par injection quel que soit votre EMULATE_PREPARES
réglage. La seule différence est l'endroit où le remplacement des paramètres se produit - avec EMULATE_PREPARES
, il se produit dans la bibliothèque PDO; sans EMULATE_PREPARES
, il se produit sur le serveur MySQL.
Sans EMULATE_PREPARES
vous pouvez obtenir des erreurs de syntaxe au moment de la préparation plutôt qu'au moment de l'exécution; avec EMULATE_PREPARES
vous n'obtiendrez des erreurs de syntaxe qu'au moment de l'exécution car PDO n'a pas de requête à donner à MySQL jusqu'au moment de l'exécution. Notez que cela affecte le code que vous allez écrire ! Surtout si vous utilisez PDO::ERRMODE_EXCEPTION
!
Une considération supplémentaire:
- Il y a un coût fixe pour a
prepare()
(en utilisant des instructions préparées natives), donc un prepare();execute()
avec des instructions préparées natives peut être un peu plus lent que d'émettre une requête textuelle en utilisant des instructions préparées émulées. Sur de nombreux systèmes de base de données, le plan de requête pour a prepare()
est également mis en cache et peut être partagé avec plusieurs connexions, mais je ne pense pas que MySQL le fasse. Donc, si vous ne réutilisez pas votre objet instruction préparé pour plusieurs requêtes, votre exécution globale peut être plus lente.
Comme recommandation finale , je pense qu'avec les anciennes versions de MySQL + PHP, vous devriez émuler des déclarations préparées, mais avec vos versions très récentes, vous devriez désactiver l'émulation.
Après avoir écrit quelques applications qui utilisent PDO, j'ai créé une fonction de connexion PDO qui a ce que je pense être les meilleurs paramètres. Vous devriez probablement utiliser quelque chose comme ça ou modifier vos paramètres préférés:
/**
* 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;
}