Pour répondre à vos préoccupations :
-
MySQL>=5.1.17 (ou>=5.1.21 pour le
PREPARE
etEXECUTE
instructions) peut utiliser des instructions préparées dans le cache de requête . 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 de requête 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 tirer le meilleur parti du 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 se fera simplement dans la bibliothèque PDO avec des chaînes plutôt que 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
paramètre. La seule différence est où le paramètre de remplacement se produit--avecEMULATE_PREPARES
, il se produit dans la bibliothèque PDO ; sansEMULATE_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 ; avecEMULATE_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 écrirez ! Surtout si vous utilisezPDO::ERRMODE_EXCEPTION
!
Une considération supplémentaire :
- Il y a un coût fixe pour une
prepare()
(en utilisant des instructions préparées natives), donc unprepare();execute()
avec des instructions préparées natives peut être un peu plus lent que l'émission d'une requête textuelle simple à l'aide d'instructions préparées émulées. Sur de nombreux systèmes de base de données, le plan de requête pour unprepare()
est également mis en cache et peut être partagé avec plusieurs connexions, mais je ne pense pas que MySQL le fasse. Ainsi, si vous ne réutilisez pas votre objet d'instruction préparé pour plusieurs requêtes, votre exécution globale risque d'être plus lente.
En tant que recommandation finale , je pense qu'avec les anciennes versions de MySQL+PHP, vous devriez émuler des instructions 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 ceci 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;
}