Esto es lo que he leído hasta ahora PDO::ATTR_EMULATE_PREPARES
:
- La emulación de preparación de PDO es mejor para el rendimiento, ya que la preparación nativa de MySQL evita la caché de consultas .
- La preparación nativa de MySQL es mejor para la seguridad (evitando la inyección de SQL) .
- La preparación nativa de MySQL es mejor para la notificación de errores .
Ya no sé qué tan cierta es ninguna de estas declaraciones. Mi mayor preocupación al elegir una interfaz MySQL es evitar la inyección de SQL. La segunda preocupación es el rendimiento.
Mi aplicación utiliza actualmente MySQLi procedimental (sin declaraciones preparadas) y utiliza bastante la caché de consultas. Rara vez reutilizará declaraciones preparadas en una sola solicitud. Comencé a moverme a PDO para los parámetros con nombre y la seguridad de las declaraciones preparadas.
Estoy usando MySQL 5.1.61
yPHP 5.3.2
¿Debo dejar PDO::ATTR_EMULATE_PREPARES
habilitado o no? ¿Hay alguna manera de tener tanto el rendimiento de la caché de consultas como la seguridad de las declaraciones preparadas?
Respuestas:
Para responder a sus inquietudes:
MySQL> = 5.1.17 (o> = 5.1.21 para las declaraciones
PREPARE
yEXECUTE
) puede usar declaraciones preparadas en la caché de consultas . Entonces, su versión de MySQL + PHP puede usar declaraciones preparadas con la caché de consultas. Sin embargo, tenga en cuenta las advertencias para almacenar en caché los resultados de las consultas en la documentación de MySQL. Hay muchos tipos de consultas que no se pueden almacenar en caché o que son inútiles aunque estén en caché. En mi experiencia, la caché de consultas no suele ser una gran ganancia de todos modos. Las consultas y los esquemas necesitan una construcción especial para aprovechar al máximo la caché. A menudo, el almacenamiento en caché a nivel de aplicación termina siendo necesario de todos modos a largo plazo.Native se prepara no hace ninguna diferencia para la seguridad. Las declaraciones pseudopreparadas aún escaparán de los valores de los parámetros de consulta, solo se hará en la biblioteca PDO con cadenas en lugar de en el servidor MySQL utilizando el protocolo binario. En otras palabras, el mismo código PDO será igualmente vulnerable (o no vulnerable) a los ataques de inyección independientemente de su
EMULATE_PREPARES
configuración. La única diferencia es dónde se produce el reemplazo del parámetro, conEMULATE_PREPARES
, ocurre en la biblioteca PDO; sinEMULATE_PREPARES
, ocurre en el servidor MySQL.Sin
EMULATE_PREPARES
él, puede obtener errores de sintaxis en el tiempo de preparación en lugar de en el tiempo de ejecución; conEMULATE_PREPARES
, solo obtendrá errores de sintaxis en el momento de la ejecución porque PDO no tiene una consulta para entregar a MySQL hasta el momento de la ejecución. ¡Tenga en cuenta que esto afecta el código que escribirá ! ¡Especialmente si estás usandoPDO::ERRMODE_EXCEPTION
!Una consideración adicional:
prepare()
(usando declaraciones preparadas nativas), por lo queprepare();execute()
con declaraciones preparadas nativas puede ser un poco más lento que emitir una consulta de texto sin formato usando declaraciones preparadas emuladas. En muchos sistemas de bases de datos, el plan de consulta para a tambiénprepare()
se almacena en caché y puede compartirse con múltiples conexiones, pero no creo que MySQL haga esto. Entonces, si no reutiliza su objeto de declaración preparado para múltiples consultas, su ejecución general puede ser más lenta.Como recomendación final , creo que con versiones anteriores de MySQL + PHP, debería emular declaraciones preparadas, pero con sus versiones más recientes debería desactivar la emulación.
Después de escribir algunas aplicaciones que usan PDO, he creado una función de conexión PDO que tiene lo que creo que son las mejores configuraciones. Probablemente debería usar algo como esto o ajustar su configuración preferida:
fuente
mysql_real_escape_string
con caracteres de varios bytes) aún dejaría a uno abierto a ataques de inyección?mysql_real_escape_string
bajo el capó y las consiguientes vulnerabilidades que pueden surgir (en casos extremos muy particulares).Tenga cuidado con la desactivación
PDO::ATTR_EMULATE_PREPARES
(activando la preparación nativa) cuando su PHPpdo_mysql
no está compilado contramysqlnd
.Como lo antiguo
libmysql
no es totalmente compatible con algunas funciones, puede provocar errores extraños, por ejemplo:PDO::PARAM_INT
(0x12345678AB se recortará a 0x345678AB en una máquina de 64 bits)LOCK TABLES
(lanza unaSQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet
excepción)mysqlnd
o emulado se prepara automáticamente hace esto por usted y no se desincroniza con el servidor mysql)Estos errores los descubrí en mi proyecto simple cuando migré a otro servidor que usé
libmysql
parapdo_mysql
module. Quizás haya muchos más errores, no lo sé. También probé en debian jessie de 64 bits, todos los errores enumerados ocurren cuando yoapt-get install php5-mysql
, y desaparecen cuandoapt-get install php5-mysqlnd
.Cuando
PDO::ATTR_EMULATE_PREPARES
se establece en verdadero (por defecto): estos errores no ocurren de todos modos, porque PDO no usa declaraciones preparadas en absoluto en este modo. Por lo tanto, si usa la subcadenapdo_mysql
basada enlibmysql
(la subcadena "mysqlnd" no aparece en el campo de lapdo_mysql
sección "Versión de la API del cliente" en phpinfo), no debePDO::ATTR_EMULATE_PREPARES
apagar.fuente
Desactivaría emular prepares mientras ejecuta 5.1, lo que significa que PDO aprovechará la funcionalidad de declaración preparada nativa.
http://php.net/manual/en/ref.pdo-mysql.php
Dejé MySQLi para PDO por las declaraciones con nombre preparadas y la mejor API.
Sin embargo, para equilibrarlo, PDO se comporta insignificantemente más lento que MySQLi, pero es algo a tener en cuenta. Lo supe cuando tomé la decisión y decidí que una mejor API y el uso del estándar de la industria era más importante que usar una biblioteca insignificantemente más rápida que lo vincula a un motor en particular. FWIW Creo que el equipo de PHP también está mirando favorablemente a PDO sobre MySQLi para el futuro.
fuente
Recomendaría habilitar
PREPARE
llamadas a bases de datos reales ya que la emulación no captura todo ..., por ejemplo, ¡se prepararáINSERT;
!La salida
Con mucho gusto recibiré un golpe de rendimiento para el código que realmente funciona.
FWIW
Versión de PHP: PHP 5.4.9-4ubuntu2.4 (cli)
Versión de MySQL: 5.5.34-0ubuntu0
fuente
prepare
haga el trabajo que se supone que debe hacer. (Además, siempre he asumido que el analizador de parámetros del lado del cliente necesariamente tendrá errores propios).https://tech.michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/
fuente
Me sorprende que nadie haya mencionado una de las principales razones para desactivar la emulación. Con la emulación activada, PDO devuelve todos los números enteros y flotantes como cadenas . Cuando desactiva la emulación, los números enteros y flotantes en MySQL se convierten en números enteros y flotantes en PHP.
Para obtener más información, consulte la respuesta aceptada para esta pregunta: PHP + PDO + MySQL: ¿cómo devuelvo columnas enteras y numéricas de MySQL como enteros y numéricos en PHP? .
fuente
Para el registro
PDO :: ATTR_EMULATE_PREPARES = verdadero
Podría generar un efecto secundario desagradable. Podría devolver valores int como cadena.
PHP 7.4, pdo con mysqlnd.
Ejecutando una consulta con PDO :: ATTR_EMULATE_PREPARES = true
Columna:
tipo de identificación : entero
Valor: 1
Ejecutando una consulta con PDO :: ATTR_EMULATE_PREPARES = false
Columna: id
Tipo: cadena
Valor: "1"
En cualquier caso, los valores decimales siempre se devuelven como una cadena, independientemente de la configuración :-(
fuente