Voici ce que j'ai lu jusqu'à présent PDO::ATTR_EMULATE_PREPARES
:
- L'émulation de préparation de PDO est meilleure pour les performances puisque la préparation native de MySQL contourne le cache de requête .
- La préparation native de MySQL est meilleure pour la sécurité (empêchant l'injection SQL) .
- La préparation native de MySQL est meilleure pour les rapports d'erreurs .
Je ne sais plus à quel point ces déclarations sont vraies. Ma plus grande préoccupation en choisissant une interface MySQL est d'empêcher l'injection SQL. La deuxième préoccupation est la performance.
Mon application utilise actuellement MySQLi procédural (sans instructions préparées) et utilise assez souvent le cache de requêtes. Il réutilisera rarement les instructions préparées dans une seule requête. J'ai commencé le passage à PDO pour les paramètres nommés et la sécurité des déclarations préparées.
J'utilise MySQL 5.1.61
etPHP 5.3.2
Dois-je laisser PDO::ATTR_EMULATE_PREPARES
activé ou non? Existe-t-il un moyen d'avoir à la fois les performances du cache de requêtes et la sécurité des instructions préparées?
Réponses:
Pour répondre à vos préoccupations:
MySQL> = 5.1.17 (ou> = 5.1.21 pour les instructions
PREPARE
etEXECUTE
) 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 - 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 allez écrire ! Surtout si vous utilisezPDO::ERRMODE_EXCEPTION
!Une considération supplémentaire:
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 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 aprepare()
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:
la source
mysql_real_escape_string
rencontrés avec les caractères multi-octets) laisserait toujours une vulnérabilité aux attaques par injection?mysql_real_escape_string
sous le capot et les vulnérabilités qui peuvent survenir (dans des cas extrêmes très particuliers).Méfiez-vous de la désactivation
PDO::ATTR_EMULATE_PREPARES
(l'activation du natif prépare) lorsque votre PHPpdo_mysql
n'est pas compilémysqlnd
.Parce que old
libmysql
n'est pas entièrement compatible avec certaines fonctions, cela peut conduire à d'étranges bogues, par exemple:PDO::PARAM_INT
(0x12345678AB sera rogné à 0x345678AB sur une machine 64 bits)LOCK TABLES
(cela lève uneSQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet
exception)mysqlnd
ou émulé prépare, il fait automatiquement ce travail pour vous et ne se désynchronise pas avec le serveur mysql)Ces bogues, j'ai compris dans mon projet simple lors de la migration vers un autre serveur utilisé
libmysql
pour lepdo_mysql
module. Peut-être qu'il y a beaucoup plus de bugs, je ne sais pas. J'ai également testé sur de nouveaux debian jessie 64 bits, tous les bogues répertoriés se produisent lorsque jeapt-get install php5-mysql
et disparaissent lorsque jeapt-get install php5-mysqlnd
.Quand
PDO::ATTR_EMULATE_PREPARES
est défini sur true (par défaut) - ces bogues ne se produisent de toute façon pas, car PDO n'utilise pas du tout les instructions préparées dans ce mode. Donc, si vous utilisezpdo_mysql
based onlibmysql
(la sous-chaîne "mysqlnd" n'apparaît pas dans le champ "Client API version" de lapdo_mysql
section de phpinfo) - vous ne devez pasPDO::ATTR_EMULATE_PREPARES
désactiver.la source
Je désactiverais les préparations d'émulation lorsque vous exécutez 5.1, ce qui signifie que PDO profitera de la fonctionnalité de déclaration préparée native.
http://php.net/manual/en/ref.pdo-mysql.php
J'ai abandonné MySQLi pour PDO pour les instructions nommées préparées et la meilleure API.
Cependant, pour être équilibré, PDO fonctionne beaucoup plus lentement que MySQLi, mais c'est quelque chose à garder à l'esprit. Je le savais quand j'ai fait le choix et j'ai décidé qu'une meilleure API et l'utilisation de la norme de l'industrie étaient plus importantes que d'utiliser une bibliothèque négligeable plus rapide qui vous relie à un moteur particulier. FWIW Je pense que l'équipe PHP regarde également favorablement PDO par rapport à MySQLi pour l'avenir aussi.
la source
Je recommanderais d'activer de vrais
PREPARE
appels de base de données car l'émulation ne saisit pas tout .., par exemple, elle se prépareraINSERT;
!Le résultat
Je prendrai volontiers un coup de performance pour le code qui fonctionne réellement.
FWIW
Version PHP: PHP 5.4.9-4ubuntu2.4 (cli)
Version de MySQL: 5.5.34-0ubuntu0
la source
prepare
faire le travail qu'il est censé faire. (De plus, j'ai toujours supposé que l'analyseur de paramètres côté client aura nécessairement ses propres bogues.)Je suis surpris que personne n'ait mentionné l'une des principales raisons de désactiver l'émulation. Avec l'émulation activée, PDO renvoie tous les nombres entiers et flottants sous forme de chaînes . Lorsque vous désactivez l'émulation, les entiers et les flottants dans MySQL deviennent des entiers et des flottants en PHP.
Pour plus d'informations, consultez la réponse acceptée à cette question: PHP + PDO + MySQL: comment renvoyer des colonnes entières et numériques de MySQL sous forme d'entiers et de nombres en PHP? .
la source
https://tech.michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/
la source
Pour la petite histoire
PDO :: ATTR_EMULATE_PREPARES = vrai
Cela pourrait générer un effet secondaire désagréable. Il pourrait renvoyer des valeurs int sous forme de chaîne.
PHP 7.4, pdo avec mysqlnd.
Exécution d'une requête avec PDO :: ATTR_EMULATE_PREPARES = true
Colonne: id
Type: entier
Valeur: 1
Exécution d'une requête avec PDO :: ATTR_EMULATE_PREPARES = false
Colonne: id
Type: chaîne
Valeur: "1"
Dans tous les cas, les valeurs décimales sont toujours renvoyées sous forme de chaîne, quelle que soit la configuration :-(
la source