139 votes

PDO MySQL : Utilisation PDO::ATTR_EMULATE_PREPARES ou pas ?

C'est ce que j'ai lu jusqu'à présent sur PDO::ATTR_EMULATE_PREPARES:

  1. AOP préparer l'émulation est mieux pour la performance depuis MySQL natif de préparer contourne le cache de requêtes.
  2. MySQL natif de préparer le mieux pour la sécurité (prévention de l'Injection SQL).
  3. MySQL natif de préparer le mieux pour les rapports d'erreurs.

Je ne sais pas comment vrai un de ces états sont plus. Ma plus grande préoccupation dans le choix d'une interface MySQL est la prévention de l'Injection SQL. La deuxième préoccupation est la performance.

Mon application utilise actuellement de procédure MySQLi (sans déclarations préparées à l'avance), et utilise la mise en cache de requêtes un peu. Il sera rarement ré-utiliser les requêtes préparées en une seule requête. J'ai commencé à le passer à PDO pour les paramètres nommés et de la sécurité de déclarations préparées à l'avance.

Je suis à l'aide d' MySQL 5.1.61 et PHP 5.3.2

Dois-je quitter PDO::ATTR_EMULATE_PREPARES activé ou pas? Est-il un moyen d'avoir à la fois la performance de la mise en cache de requêtes et la sécurité de déclarations préparées à l'avance?

121voto

Francis Avila Points 18236

Pour répondre à vos préoccupations:

  1. MySQL >= 5.1.17 (ou >= 5.1.21 pour l' PREPARE et EXECUTE des déclarations) peut utiliser les requêtes préparées dans le cache de requêtes. Si votre version de MySQL+PHP peut utiliser des requêtes préparées avec le cache de requêtes. Cependant, note soigneusement les mises en garde pour la mise en cache résultats de la requête dans la documentation de MySQL. Il existe de nombreux types de requêtes qui ne peuvent pas être mis en cache ou qui sont inutiles, même si elles sont mises en cache. Dans mon expérience, la mise en cache de requêtes n'est pas souvent une très grande victoire, de toute façon. Des requêtes et schémas besoin spécial de construction pour faire une utilisation maximale de la mémoire cache. Souvent au niveau de l'application de la mise en cache finit par être nécessaire de toute façon dans le long terme.

  2. Natif prépare ne fait aucune différence pour la sécurité. Le pseudo-préparées vont encore s'échapper de valeurs de paramètres de requête, il suffit de faire dans la librairie PDO avec des chaînes au lieu de le faire sur le serveur MySQL en utilisant le protocole binaire. En d'autres termes, la même AOP code sera tout aussi vulnérables (ou non-vulnérable à des attaques par injection, quel que soit votre EMULATE_PREPARES réglage. La seule différence est l'emplacement du paramètre de remplacement se produit-- EMULATE_PREPARES, il se produit dans la librairie PDO; sans EMULATE_PREPARES, il se produit sur le serveur MySQL.

  3. Sans EMULATE_PREPARES vous pouvez obtenir des erreurs de syntaxe à préparer en temps plutôt qu'à exécuter en temps; avec EMULATE_PREPARES , vous obtiendrez uniquement des erreurs de syntaxe lors de l'exécution parce que PDO n'est pas question de donner à MySQL jusqu'à ce que le temps d'exécution. Notez que cela affecte le code que vous allez écrire! Surtout si vous utilisez PDO::ERRMODE_EXCEPTION!

Une autre considération:

  • Il y a un coût fixe pour un prepare() (en utilisant natif déclarations préparées à l'avance), donc un prepare();execute() natif de déclarations préparées à l'avance peut être un peu plus lent que la délivrance d'une plaine textuelle requête à l'aide de émulé déclarations préparées à l'avance. Sur de nombreux systèmes de base de données le plan de requête pour un prepare() est mis en cache et peuvent être partagées avec des connexions multiples, mais je ne pense pas que MySQL ne ce. Donc, si vous ne pas réutiliser votre déclaration d'objet de plusieurs requêtes de l'ensemble de votre exécution peut être plus lente.

Comme une recommandation finale, je pense qu'avec les anciennes versions de MySQL+PHP, vous devez imiter déclarations préparées à l'avance, mais avec votre des versions très récentes, vous devez tourner à l'émulation off.

Après avoir écrit quelques applications que l'utilisation de PDO, j'ai fait un AOP fonction de connexion qui a, je pense, ce sont les meilleurs réglages. Vous devriez 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;
}

9voto

Will Morgan Points 1856

Je voudrais désactiver émuler prépare comme vous êtes en cours d'exécution 5.1 qui signifie PDO tirer parti des indigènes de l'instruction préparée fonctionnalité.

PDO_MYSQL aura l'avantage de natif de l'instruction préparée de soutien présents dans MySQL 4.1 et plus. Si vous utilisez une ancienne version de la bibliothèque cliente mysql, PDO imiter pour vous.

http://php.net/manual/en/ref.pdo-mysql.php

J'ai abandonné MySQLi pour les AOP pour la préparation nommé états et la meilleure API.

Toutefois, pour être équilibré, PDO effectue de façon négligeable plus lent que MySQLi, mais c'est quelque chose à garder à l'esprit. Je le savais quand j'ai fait le choix, et décidé que la meilleure API et à l'aide de la norme de l'industrie est plus important que l'aide d'un très rapide de la bibliothèque qui vous lie à un moteur particulier. FWIW, je pense que le PHP de l'équipe est également à la recherche favorablement à PDO sur MySQLi pour l'avenir aussi.

8voto

quickshiftin Points 6379

Je recommanderais ce qui permet de base réelle appelle comme l’émulation n’attrapent pas tout.., par exemple, il préparera !

La sortie

Je prendrai volontiers une performance frappée pour le code qui fonctionne réellement.

FWIW

Version de PHP : PHP 5.4.9-4ubuntu2.4 (cli)

MySQL Version : 5.5.34-0ubuntu0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X