¿Cuáles son las razones técnicas por las cuales uno no debería usar mysql_*
funciones? (por ejemplo mysql_query()
, mysql_connect()
o mysql_real_escape_string()
)?
¿Por qué debería usar otra cosa incluso si funcionan en mi sitio?
Si no funcionan en mi sitio, ¿por qué recibo errores como
Advertencia: mysql_connect (): No existe tal archivo o directorio
Respuestas:
La extensión MySQL:
Como está en desuso, usarlo hace que su código sea menos a prueba de futuro.
La falta de soporte para las declaraciones preparadas es particularmente importante ya que proporcionan un método más claro y menos propenso a errores para escapar y citar datos externos que escapar manualmente con una llamada de función separada.
Vea la comparación de extensiones SQL .
fuente
PHP ofrece tres API diferentes para conectarse a MySQL. Estas son
mysql
(eliminadas a partir de PHP 7)mysqli
, yPDO
extensiones.Las
mysql_*
funciones solían ser muy populares, pero ya no se recomienda su uso. El equipo de documentación está discutiendo la situación de seguridad de la base de datos, y educar a los usuarios para que se alejen de la extensión ext / mysql comúnmente utilizada es parte de esto (ver php.internals: deprecando ext / mysql ).Y el equipo de desarrolladores de PHP posterior tomó la decisión de generar
E_DEPRECATED
errores cuando los usuarios se conectan a MySQL, ya sea a través demysql_connect()
,mysql_pconnect()
o la funcionalidad de conexión implícita incorporadaext/mysql
.ext/mysql
fue oficialmente obsoleto a partir de PHP 5.5 y se ha eliminado a partir de PHP 7 .¿Ves la caja roja?
Cuando va a cualquier
mysql_*
página del manual de funciones, ve un cuadro rojo que explica que ya no debe usarse.Por qué
Alejarse
ext/mysql
no solo se trata de seguridad, sino también de tener acceso a todas las funciones de la base de datos MySQL.ext/mysql
fue construido para MySQL 3.23 y solo obtuvo muy pocas adiciones desde entonces, manteniendo la compatibilidad con esta versión anterior, lo que hace que el código sea un poco más difícil de mantener. Las características faltantes que no son compatibles conext/mysql
incluyen: ( del manual de PHP ).Motivo para no usar la
mysql_*
función :Punto anterior citado de la respuesta de Quentin
La falta de soporte para las declaraciones preparadas es particularmente importante ya que proporcionan un método más claro y menos propenso a errores para escapar y citar datos externos que escapar manualmente con una llamada de función separada.
Ver la comparación de extensiones SQL .
Suprimir advertencias de desaprobación
Mientras el código se convierte a
MySQLi
/PDO
, losE_DEPRECATED
errores se pueden suprimir configurandoerror_reporting
en php.ini para excluirE_DEPRECATED:
Tenga en cuenta que esto también ocultará otras advertencias de desaprobación , que, sin embargo, pueden ser para otras cosas que no sean MySQL. ( del manual de PHP )
El artículo PDO vs. MySQLi: ¿Cuál debería usar? por Dejan Marjanovic te ayudará a elegir.
Y una mejor manera es
PDO
, y ahora estoy escribiendo unPDO
tutorial simple .Un tutorial PDO simple y breve
P. La primera pregunta en mi mente fue: ¿qué es 'PDO'?
A. " PDO - PHP Data Objects - es una capa de acceso a la base de datos que proporciona un método uniforme de acceso a múltiples bases de datos".
Conectando a MySQL
Con
mysql_*
función o podemos decirlo a la antigua usanza (en desuso en PHP 5.5 y superior)Con
PDO
: Todo lo que necesitas hacer es crear un nuevoPDO
objeto. El constructor acepta parámetros para especificar la fuente de base de datosPDO
'constructor s mayormente toma cuatro parámetros que sonDSN
(nombre de la fuente de datos) y, opcionalmenteusername
,password
.Aquí creo que estás familiarizado con todos excepto
DSN
; esto es nuevo enPDO
. BDSN
es básicamente una serie de opciones que indicanPDO
qué controlador usar y los detalles de conexión. Para mayor referencia, consulte PDO MySQL DSN .Nota: también puede usar
charset=UTF-8
, pero a veces causa un error, por lo que es mejor usarloutf8
.Si hay algún error de conexión, arrojará un
PDOException
objeto que puede ser atrapado para manejarloException
más.Buena lectura : Conexiones y gestión de conexiones ¶
También puede pasar varias opciones de controlador como una matriz al cuarto parámetro. Recomiendo pasar el parámetro que pone
PDO
en modo de excepción. Debido a que algunosPDO
controladores no admiten declaraciones preparadas nativas, por lo tanto,PDO
realiza la emulación de la preparación. También le permite habilitar manualmente esta emulación. Para usar las declaraciones preparadas nativas del lado del servidor, debe configurarlas explícitamentefalse
.El otro es desactivar la emulación de preparación que está habilitada en el
MySQL
controlador de forma predeterminada, pero la emulación de preparación debe estar desactivada para usar dePDO
manera segura.Más adelante explicaré por qué se debe desactivar la emulación de preparación. Para encontrar la razón, consulte esta publicación .
Solo se puede usar si está utilizando una versión anterior
MySQL
que no recomiendo.A continuación se muestra un ejemplo de cómo puede hacerlo:
¿Podemos establecer atributos después de la construcción de PDO?
Sí , también podemos establecer algunos atributos después de la construcción PDO con el
setAttribute
método:Manejo de errores
El manejo de errores es mucho más fácil
PDO
quemysql_*
.Una práctica común cuando se usa
mysql_*
es:OR die()
no es una buena forma de manejar el error, ya que no podemos manejarlodie
. Simplemente terminará el script abruptamente y luego hará eco del error en la pantalla que generalmente NO desea mostrar a sus usuarios finales, y permitirá que los hackers sangrientos descubran su esquema. Alternativamente, los valores de retorno de lasmysql_*
funciones a menudo se pueden usar junto con mysql_error () para manejar errores.PDO
ofrece una mejor solución: excepciones. Cualquier cosa que hacemos conPDO
debe ser envuelto en unatry
-catch
bloque. Podemos forzarPDO
uno de los tres modos de error configurando el atributo del modo de error. Hay tres modos de manejo de errores a continuación.PDO::ERRMODE_SILENT
. Solo establece códigos de error y actúa casi de la misma maneramysql_*
en que debe verificar cada resultado y luego mirar$db->errorInfo();
para obtener los detalles del error.PDO::ERRMODE_WARNING
AumentoE_WARNING
. (Advertencias en tiempo de ejecución (errores no fatales). La ejecución del script no se detiene).PDO::ERRMODE_EXCEPTION
: Lanzar excepciones. Representa un error provocado por PDO. No debe lanzar unPDOException
desde su propio código. Consulte Excepciones para obtener más información sobre excepciones en PHP. Actúa muy parecido aor die(mysql_error());
cuando no es atrapado. Pero a diferencia de estoor die()
,PDOException
se puede atrapar y manejar con gracia si elige hacerlo.Buena lectura :
Me gusta:
Y se puede envolver en
try
-catch
, como a continuación:Usted no tiene que manejar con
try
-catch
en este momento. Puede atraparlo en cualquier momento apropiado, pero le recomiendo que usetry
-catch
. También puede tener más sentido detectarlo fuera de la función que llama alPDO
material:Además, puede manejarlo
or die()
o podemos decir que me gustamysql_*
, pero será muy variado. Puede ocultar los mensajes de error peligrosos en producción girandodisplay_errors off
y simplemente leyendo su registro de errores.Ahora, después de leer todas las cosas de arriba, es probable que esté pensando: ¿qué diablos es que cuando sólo quiero empezar a inclinarse simples
SELECT
,INSERT
,UPDATE
, oDELETE
declaraciones? No te preocupes, aquí vamos:Seleccionar datos
Entonces, lo que estás haciendo
mysql_*
es:Ahora adentro
PDO
, puedes hacer esto como:O
Nota : Si está utilizando el método que se muestra a continuación (
query()
), este método devuelve unPDOStatement
objeto. Entonces, si desea obtener el resultado, úselo como se indicó anteriormente.En PDO Data, se obtiene a través del
->fetch()
método de su manejador de estado de cuenta. Antes de llamar a fetch, el mejor enfoque sería decirle a PDO cómo desea que se recuperen los datos. En la sección a continuación estoy explicando esto.Modos de recuperación
Tenga en cuenta el uso de
PDO::FETCH_ASSOC
en el códigofetch()
yfetchAll()
arriba. Esto le indicaPDO
que devuelva las filas como una matriz asociativa con los nombres de campo como claves. También hay muchos otros modos de recuperación que explicaré uno por uno.En primer lugar, explico cómo seleccionar el modo de búsqueda:
En lo anterior, he estado usando
fetch()
. También puedes usar:PDOStatement::fetchAll()
- Devuelve una matriz que contiene todas las filas del conjunto de resultadosPDOStatement::fetchColumn()
- Devuelve una sola columna de la siguiente fila de un conjunto de resultadosPDOStatement::fetchObject()
- Obtiene la siguiente fila y la devuelve como un objeto.PDOStatement::setFetchMode()
- Establecer el modo de recuperación predeterminado para esta declaraciónAhora vengo a buscar el modo:
PDO::FETCH_ASSOC
: devuelve una matriz indexada por nombre de columna como se devolvió en su conjunto de resultadosPDO::FETCH_BOTH
(predeterminado): devuelve una matriz indexada tanto por el nombre de la columna como por el número de la columna indexada en 0 como se devolvió en su conjunto de resultados¡Incluso hay más opciones! Lea sobre todos ellos en la
PDOStatement
documentación de Fetch. .Obteniendo el recuento de filas :
En lugar de usar
mysql_num_rows
para obtener el número de filas devueltas, puede obtener ayPDOStatement
hacerrowCount()
, como:Obteniendo la última identificación insertada
Insertar y actualizar o eliminar declaraciones
Lo que estamos haciendo en
mysql_*
función es:Y en pdo, esto mismo se puede hacer:
En la consulta anterior,
PDO::exec
ejecute una instrucción SQL y devuelva el número de filas afectadas.Insertar y eliminar se cubrirá más adelante.
El método anterior solo es útil cuando no está utilizando variable en la consulta. Pero cuando necesite usar una variable en una consulta, nunca intente como lo anterior y allí para la declaración preparada o la declaración parametrizada .
Declaraciones preparadas
P. ¿Qué es una declaración preparada y por qué los necesito?
R. Una declaración preparada es una declaración SQL precompilada que se puede ejecutar varias veces enviando solo los datos al servidor.
El flujo de trabajo típico de usar una declaración preparada es el siguiente ( citado en Wikipedia tres puntos 3 ):
Preparar : la aplicación crea la plantilla de extracto y la envía al sistema de gestión de bases de datos (DBMS). Ciertos valores se dejan sin especificar, llamados parámetros, marcadores de posición o variables de enlace (etiquetadas a
?
continuación):INSERT INTO PRODUCT (name, price) VALUES (?, ?)
El DBMS analiza, compila y realiza la optimización de consultas en la plantilla de declaración, y almacena el resultado sin ejecutarlo.
1.00
para el segundo parámetro.Puede usar una declaración preparada incluyendo marcadores de posición en su SQL. Básicamente, hay tres sin marcadores de posición (no intente esto con la variable por encima de uno), uno con marcadores de posición sin nombre y uno con marcadores de posición con nombre.
P. Entonces, ¿qué se denominan marcadores de posición y cómo los uso?
A. Marcadores de posición con nombre. Use nombres descriptivos precedidos por dos puntos, en lugar de signos de interrogación. No nos importa la posición / orden de valor en el marcador de posición de nombre:
bindParam(parameter,variable,data_type,length,driver_options)
También puedes enlazar usando una matriz de ejecución:
Otra buena característica para los
OOP
amigos es que los marcadores de posición con nombre tienen la capacidad de insertar objetos directamente en su base de datos, suponiendo que las propiedades coincidan con los campos con nombre. Por ejemplo:P. Entonces, ¿qué son marcadores de posición sin nombre y cómo los uso?
A. Tengamos un ejemplo:
y
En lo anterior, puede ver esos en
?
lugar de un nombre como en un marcador de posición de nombre. Ahora, en el primer ejemplo, asignamos variables a los distintos marcadores de posición ($stmt->bindValue(1, $name, PDO::PARAM_STR);
). Luego, asignamos valores a esos marcadores de posición y ejecutamos la declaración. En el segundo ejemplo, el primer elemento de matriz va al primero?
y el segundo al segundo?
.NOTA : En los marcadores de posición sin nombre , debemos cuidar el orden correcto de los elementos en la matriz que estamos pasando al
PDOStatement::execute()
método.SELECT
,INSERT
,UPDATE
,DELETE
Preparado consultasSELECT
:INSERT
:DELETE
:UPDATE
:NOTA:
Sin embargo
PDO
y / oMySQLi
no son completamente seguros. Verifique la respuesta ¿Son suficientes las declaraciones preparadas por PDO para evitar la inyección de SQL? por ircmaxell . Además, estoy citando alguna parte de su respuesta:fuente
IN (...) construct
.function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx();
Funciona para lanzar excepciones.Doesn't support non-blocking, asynchronous queries
como una razón para no usar mysql_; también debe enumerar eso como una razón para no usar PDO, porque PDO tampoco lo admite. (pero MySQLi lo admite)Primero, comencemos con el comentario estándar que les damos a todos:
Veamos esto, oración por oración, y expliquemos:
Ya no se mantienen y están oficialmente en desuso
Esto significa que la comunidad PHP está abandonando gradualmente el soporte para estas funciones muy antiguas. ¡Es probable que no existan en una versión futura (reciente) de PHP! El uso continuo de estas funciones puede romper su código en un futuro (no tan lejano).
¡NUEVO! - ext / mysql ahora está oficialmente en desuso desde PHP 5.5!
¡Más nuevo! ext / mysql ha sido eliminado en PHP 7 .
En cambio, debe aprender de las declaraciones preparadas
mysql_*
La extensión no admite declaraciones preparadas , que es (entre otras cosas) una contramedida muy efectiva contra la inyección SQL . Se corrigió una vulnerabilidad muy grave en las aplicaciones dependientes de MySQL que permite a los atacantes obtener acceso a su script y realizar cualquier consulta posible en su base de datos.Para obtener más información, consulte ¿Cómo puedo evitar la inyección de SQL en PHP?
¿Ves la caja roja?
Cuando vaya a cualquier
mysql
página del manual de funciones, verá un cuadro rojo que explica que ya no se debe usar.Use PDO o MySQLi
Hay alternativas mejores, más robustas y bien construidas, PDO - PHP Database Object , que ofrece un enfoque completo de OOP para la interacción de la base de datos, y MySQLi , que es una mejora específica de MySQL.
fuente
IN (...) construct
.Facilidad de uso
Ya se mencionaron las razones analíticas y sintéticas. Para los recién llegados hay un incentivo más significativo para dejar de usar las funciones mysql_ anticuadas.
Las API de bases de datos contemporáneas son más fáciles de usar.
Son principalmente los parámetros enlazados los que pueden simplificar el código. Y con excelentes tutoriales (como se ve arriba) la transición a PDO no es demasiado ardua.
Reescribir una base de código más grande a la vez, sin embargo, lleva tiempo. Raison d'être para esta alternativa intermedia:
Funciones pdo_ * equivalentes en lugar de
mysql_ *Usando < pdo_mysql.php > puede cambiar de las antiguas funciones mysql_ con un mínimo esfuerzo . Agrega
pdo_
envoltorios de funciones que reemplazan a susmysql_
contrapartes.Simplemente en cada script de invocación que tiene que interactuar con la base de datos.
include_once(
"pdo_mysql.php"
);
Elimine el
prefijo de la función en todas partes y reemplácelo conmysql_
pdo_
.mysql_
connect()
se conviertepdo_
connect()
mysql_
query()
se conviertepdo_
query()
mysql_
num_rows()
se conviertepdo_
num_rows()
mysql_
insert_id()
se conviertepdo_
insert_id()
mysql_
fetch_array()
se conviertepdo_
fetch_array()
mysql_
fetch_assoc()
se conviertepdo_
fetch_assoc()
mysql_
real_escape_string()
se conviertepdo_
real_escape_string()
Su código funcionará igual y aún se verá igual:
Et voilà.
Su código está usando PDO.
Ahora es el momento de utilizarlo realmente .
Los parámetros enlazados pueden ser fáciles de usar.
Solo necesita una API menos difícil de manejar.
pdo_query()
agrega soporte muy fácil para los parámetros enlazados. Convertir el código antiguo es sencillo:Mueva sus variables fuera de la cadena SQL.
pdo_query()
.?
como marcadores de posición donde estaban las variables antes.'
comillas simples que anteriormente incluían valores / variables de cadena.La ventaja se vuelve más obvia para un código más largo.
A menudo, las variables de cadena no solo se interpolan en SQL, sino que se concatenan con llamadas de escape intermedias.
Con los
?
marcadores de posición aplicados, no tiene que molestarse con eso:Recuerde que pdo_ * todavía permite o .
Simplemente no escape una variable y la asocie en la misma consulta.
:named
listas de marcadores de posición más adelante.Más importante aún, puede pasar $ _REQUEST [] variables de forma segura detrás de cualquier consulta. Cuando los
<form>
campos enviados coinciden exactamente con la estructura de la base de datos, es aún más corta:Tanta simplicidad. Pero volvamos a algunos consejos de reescritura más y razones técnicas sobre por qué es posible que desee deshacerse
y escapar.mysql_
Repara o elimina cualquier
sanitize()
función de la vieja escuelaUna vez que haya convertido todas las
llamadasmysql_
pdo_query
con parámetros vinculados, elimine todas laspdo_real_escape_string
llamadas redundantes .En particular, se debe corregir cualquier
sanitize
oclean
ofilterThis
oclean_data
funciones como se anuncia por tutoriales de fecha, de una forma u otra:El error más evidente aquí es la falta de documentación. Más significativamente, el orden de filtrado estaba exactamente en el orden incorrecto.
El orden correcto habría sido: obsoleto
stripslashes
como la llamada más interna, luegotrim
, despuésstrip_tags
,htmlentities
para el contexto de salida, y solo por último,_escape_string
ya que su aplicación debería preceder directamente a la interacción SQL.Pero como primer paso, simplemente deshágase de la
_real_escape_string
llamada.Es posible que deba mantener el resto de su
sanitize()
función por ahora si su base de datos y el flujo de la aplicación esperan cadenas seguras para el contexto HTML. Agregue un comentario que aplique solo el escape de HTML en adelante.El manejo de cadenas / valores se delega a PDO y sus declaraciones parametrizadas.
Si hubo alguna mención
stripslashes()
en su función de desinfección, puede indicar una supervisión de nivel superior.Eso estaba comúnmente allí para deshacer el daño (doble escape) de los obsoletos
magic_quotes
. Lo que, sin embargo, se soluciona mejor centralmente , no cadena por cadena.Utilice uno de los enfoques de reversión del usuario . Luego elimine el
stripslashes()
en lasanitize
función.Cómo difieren las declaraciones preparadas
Cuando codifica las variables de cadena en las consultas SQL, no solo se vuelve más intrincado para que lo siga. También es un esfuerzo extraño para MySQL segregar el código y los datos nuevamente.
Las inyecciones de SQL simplemente son cuando los datos sangran en el contexto del código . Un servidor de base de datos no puede detectar posteriormente dónde PHP originalmente pegó variables entre cláusulas de consulta.
Con los parámetros enlazados, separa el código SQL y los valores de contexto SQL en su código PHP. Pero no se vuelve a mezclar detrás de escena (excepto con PDO :: EMULATE_PREPARES). Su base de datos recibe los comandos SQL no variados y los valores variables 1: 1.
Si bien esta respuesta subraya que debe preocuparse por las ventajas de legibilidad de la caída
. De vez en cuando también hay una ventaja de rendimiento (INSERT repetidos con solo valores diferentes) debido a esta separación visible y técnica de datos / código.mysql_
Tenga en cuenta que el enlace de parámetros aún no es una solución única mágica contra todas las inyecciones SQL. Maneja el uso más común para datos / valores. Pero no se pueden incluir en la lista blanca los identificadores de tabla / nombre de columna, ayudar con la construcción de cláusulas dinámicas o simplemente listas de valores de matriz simple.
Uso de PDO híbrido
Estas
pdo_*
funciones de contenedor hacen una API de stop-gap amigable con la codificación. (Es más o menos lo queMYSQLI
podría haber sido si no fuera por el cambio de firma de la función idiosincrásica). También exponen la verdadera DOP en la mayoría de los casos.La reescritura no tiene por qué detenerse en el uso de los nuevos nombres de funciones pdo_. Podría uno por uno hacer la transición de cada pdo_query () en una simple $ pdo-> prepare () -> execute () call.
Sin embargo, es mejor comenzar a simplificar nuevamente. Por ejemplo, la obtención de resultados comunes:
Se puede reemplazar con solo una iteración foreach:
O mejor aún, una recuperación directa y completa de la matriz:
Obtendrá advertencias más útiles en la mayoría de los casos que PDO o mysql_ generalmente proporcionan después de consultas fallidas.
Otras opciones
Así que con suerte esto visualizó algunas razones prácticas y un camino digno de abandonar
.mysql_
Simplemente cambiando a pdono es suficiente.
pdo_query()
También es solo una interfaz en él.A menos que también introduzca el enlace de parámetros o pueda utilizar algo más de la API más agradable, es un cambio sin sentido. Espero que sea retratado lo suficientemente simple como para no alentar el desánimo a los recién llegados. (La educación generalmente funciona mejor que la prohibición).
Si bien califica para la categoría de lo más simple que podría funcionar, también sigue siendo un código muy experimental. Lo acabo de escribir el fin de semana. Sin embargo, hay una gran cantidad de alternativas. Simplemente busque en Google la abstracción de la base de datos PHP y explore un poco. Siempre ha habido y habrá muchas bibliotecas excelentes para tales tareas.
Si desea simplificar aún más la interacción de su base de datos, vale la pena intentarlo con mapeadores como Paris / Idiorm . Al igual que ya nadie usa el DOM blando en JavaScript, hoy en día no tiene que cuidar una interfaz de base de datos sin formato.
fuente
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
función - es decir:pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');
pdo_real_escape_string()
<- ¿Es incluso una función real, no puedo encontrar ninguna documentación para ello? Por favor, publique una fuente para esto.Las
mysql_
funciones:fuente
mysqli_
mysql_*
función es un shell en las funciones de mysqlnd para las nuevas versiones de PHP. Así que incluso si la biblioteca cliente de edad no se mantiene más, mysqlnd se mantiene :)Hablando de razones técnicas , solo hay unas pocas, extremadamente específicas y raramente utilizadas. Lo más probable es que nunca los uses en tu vida.
Tal vez soy demasiado ignorante, pero nunca tuve la oportunidad de usar cosas como
Si los necesita, estas son sin duda razones técnicas para alejarse de la extensión mysql hacia algo más elegante y moderno.
Sin embargo, también hay algunos problemas no técnicos, que pueden hacer que su experiencia sea un poco más difícil
Este último problema es un problema.
Pero, en mi opinión, la solución propuesta tampoco es mejor.
Me parece un sueño demasiado idealista que todos esos usuarios de PHP aprenderán a manejar las consultas SQL correctamente de una vez. Lo más probable es que simplemente cambien mysql_ * a mysqli_ * mecánicamente, dejando el enfoque igual . Especialmente porque mysqli hace que el uso de declaraciones preparadas sea increíblemente doloroso y problemático.
Sin mencionar que las declaraciones preparadas nativas no son suficientes para proteger de las inyecciones de SQL, y ni mysqli ni PDO ofrecen una solución.
Entonces, en lugar de luchar contra esta extensión honesta, preferiría luchar contra las prácticas incorrectas y educar a las personas de la manera correcta.
Además, hay algunas razones falsas o no significativas, como
mysql_query("CALL my_proc");
durante años)El último es un punto interesante. Aunque mysql ext no admite declaraciones preparadas nativas , no son necesarias para la seguridad. Podemos falsificar fácilmente declaraciones preparadas utilizando marcadores de posición manejados manualmente (al igual que PDO):
voila , todo está parametrizado y seguro.
Pero está bien, si no le gusta el cuadro rojo en el manual, surge un problema de elección: mysqli o PDO?
Bueno, la respuesta sería la siguiente:
Si, como la gran mayoría de la gente de PHP, está utilizando llamadas API sin procesar directamente en el código de la aplicación (lo que es esencialmente una práctica incorrecta), PDO es la única opción , ya que esta extensión pretende ser no solo API sino más bien un semi-DAL, Todavía está incompleto pero ofrece muchas características importantes, con dos de ellas hace que PDO se distinga críticamente de mysqli:
Entonces, si usted es un usuario promedio de PHP y desea ahorrarse un montón de dolores de cabeza al usar declaraciones preparadas nativas, PDO, nuevamente, es la única opción.
Sin embargo, PDO no es una bala de plata también y tiene sus dificultades.
Entonces, escribí soluciones para todos los escollos comunes y casos complejos en el wiki de la etiqueta PDO
Sin embargo, todos los que hablan de extensiones siempre pierden los 2 hechos importantes sobre Mysqli y PDO:
La declaración preparada no es una bala de plata . Hay identificadores dinámicos que no se pueden vincular mediante declaraciones preparadas. Hay consultas dinámicas con un número desconocido de parámetros que hace que la creación de consultas sea una tarea difícil.
Ni mysqli_ * ni las funciones PDO deberían haber aparecido en el código de la aplicación.
Debería haber una capa de abstracción entre ellos y el código de la aplicación, que hará todo el trabajo sucio de encuadernación, bucle, manejo de errores, etc. dentro, haciendo que el código de la aplicación esté SECO y limpio. Especialmente para los casos complejos como la construcción dinámica de consultas.
Entonces, solo cambiar a PDO o mysqli no es suficiente. Uno tiene que usar un ORM, o un generador de consultas, o cualquier clase de abstracción de base de datos en lugar de llamar a las funciones API sin procesar en su código.
Y, por el contrario, si tiene una capa de abstracción entre el código de su aplicación y la API mysql, en realidad no importa qué motor se use. Puede usar mysql ext hasta que quede obsoleto y luego reescribir fácilmente su clase de abstracción a otro motor, con todo el código de la aplicación intacto.
Aquí hay algunos ejemplos basados en mi clase safemysql para mostrar cómo debería ser una clase de abstracción como esta:
Compare esta única línea con la cantidad de código que necesitará con PDO .
Luego compare con la cantidad loca de código que necesitará con las declaraciones preparadas de Mysqli sin procesar. Tenga en cuenta que el manejo de errores, la creación de perfiles y el registro de consultas ya están integrados y en ejecución.
Compárelo con las inserciones PDO habituales, cuando cada nombre de campo se repite de seis a diez veces, en todos estos numerosos marcadores de posición con nombre, enlaces y definiciones de consulta.
Otro ejemplo:
Difícilmente puede encontrar un ejemplo para que PDO maneje un caso tan práctico.
Y será demasiado prolijo y probablemente inseguro.
Entonces, una vez más, no es solo el controlador sin formato lo que debe preocupar, sino la clase de abstracción, útil no solo para ejemplos tontos del manual para principiantes, sino para resolver cualquier problema de la vida real.
fuente
mysql_*
hace que las vulnerabilidades sean muy fáciles de encontrar. Dado que PHP es utilizado por una gran cantidad de usuarios novatos,mysql_*
es activamente dañino en la práctica, incluso si en teoría se puede usar sin problemas.everything is parameterized and safe
- puede estar parametrizado, pero su función no utiliza declaraciones preparadas reales .Not under active development
solo para ese '0.01%' inventado? Si crea algo con esta función de parada, actualice su versión de mysql en un año y termine con un sistema que no funciona, estoy seguro de que de repente hay mucha gente en ese '0.01%'. Yo diría esodeprecated
ynot under active development
están estrechamente relacionados. Puede decir que "no hay una razón [digna]" para ello, pero el hecho es que cuando se le ofrece una opción entre las opciones, ¿no active development
es casi tan malo comodeprecated
yo diría?Hay muchas razones, pero quizás la más importante es que esas funciones fomentan prácticas de programación inseguras porque no admiten declaraciones preparadas. Las declaraciones preparadas ayudan a prevenir ataques de inyección SQL.
Al usar
mysql_*
funciones, debe recordar ejecutar los parámetros proporcionados por el usuariomysql_real_escape_string()
. Si olvida en un solo lugar o si escapa solo una parte de la entrada, su base de datos puede estar sujeta a ataques.El uso de declaraciones preparadas en
PDO
omysqli
hará que este tipo de errores de programación sea más difícil de hacer.fuente
Porque (entre otras razones) es mucho más difícil garantizar que los datos de entrada estén desinfectados. Si usa consultas parametrizadas, como lo hace con PDO o mysqli, puede evitar por completo el riesgo.
Como ejemplo, alguien podría usarlo
"enhzflep); drop table users"
como nombre de usuario. Las funciones antiguas permitirán ejecutar múltiples declaraciones por consulta, por lo que algo como ese desagradable bugger puede eliminar una tabla completa.Si uno usara PDO de mysqli, el nombre de usuario terminaría siendo
"enhzflep); drop table users"
.Ver bobby-tables.com .
fuente
The old functions will allow executing of multiple statements per query
No, no lo harán. Ese tipo de inyección no es posible con ext / mysql: la única forma en que este tipo de inyección es posible con PHP y MySQL es cuando se usa MySQLi y lamysqli_multi_query()
función. El tipo de inyección que es posible con ext / mysql y cadenas sin escape es como' OR '1' = '1
extraer datos de la base de datos que no estaban destinados a ser accesibles. En ciertas situaciones, es posible inyectar subconsultas, sin embargo, aún no es posible modificar la base de datos de esta manera.Esta respuesta está escrita para mostrar cuán trivial es eludir el código de validación de usuario PHP mal escrito, cómo (y usando qué) funcionan estos ataques y cómo reemplazar las antiguas funciones de MySQL con una declaración preparada segura, y básicamente, por qué los usuarios de StackOverflow (probablemente con mucha repetición) están ladrando a los nuevos usuarios que hacen preguntas para mejorar su código.
En primer lugar, siéntase libre de crear esta base de datos mysql de prueba (he llamado preparación de mina):
Una vez hecho esto, podemos pasar a nuestro código PHP.
Supongamos que el siguiente script es el proceso de verificación para un administrador en un sitio web (simplificado pero funcionando si lo copia y lo usa para las pruebas):
Parece lo suficientemente legítimo a primera vista.
El usuario tiene que ingresar un nombre de usuario y contraseña, ¿verdad?
Brillante, no ingrese en lo siguiente:
y envíalo.
La salida es la siguiente:
¡Súper! Trabajando como se esperaba, ahora intentemos con el nombre de usuario y contraseña reales:
¡Asombroso! Hola, todo el año, el código verificó correctamente un administrador. ¡Es perfecto!
Bueno en realidad no. Digamos que el usuario es una pequeña persona inteligente. Digamos que la persona soy yo.
Ingrese lo siguiente:
Y la salida es:
Enhorabuena, solo me permitiste ingresar a tu sección de administradores súper protegidos y yo ingresé un nombre de usuario falso y una contraseña falsa. En serio, si no me cree, cree la base de datos con el código que proporcioné y ejecute este código PHP, que a simple vista REALMENTE parece verificar el nombre de usuario y la contraseña bastante bien.
Entonces, en respuesta, ES POR ESO QUE SE TE GRITA.
Entonces, echemos un vistazo a lo que salió mal y por qué acabo de entrar en su cueva de súper administrador solo murciélago. Adiviné y supuse que no estaba siendo cuidadoso con sus entradas y simplemente las pasé directamente a la base de datos. Construí la entrada de una manera que CAMBIARÍA la consulta que realmente estaba ejecutando. Entonces, ¿qué se suponía que era y qué terminó siendo?
Esa es la consulta, pero cuando reemplazamos las variables con las entradas reales que utilizamos, obtenemos lo siguiente:
¿Ves cómo construí mi "contraseña" para que primero cerrara la comilla simple alrededor de la contraseña y luego introdujera una comparación completamente nueva? Luego, solo por seguridad, agregué otra "cadena" para que la comilla simple se cerrara como se esperaba en el código que teníamos originalmente.
Sin embargo, no se trata de que la gente te grite ahora, se trata de mostrarte cómo hacer que tu código sea más seguro.
Bien, entonces, ¿qué salió mal y cómo podemos solucionarlo?
Este es un ataque de inyección SQL clásico. Uno de los más simples para el caso. En la escala de los vectores de ataque, este es un niño que ataca un tanque y gana.
Entonces, ¿cómo protegemos su sagrada sección de administración y la hacemos agradable y segura? Lo primero que debe hacer es dejar de usar esas
mysql_*
funciones realmente antiguas y obsoletas . Lo sé, seguiste un tutorial que encontraste en línea y funciona, pero es viejo, está desactualizado y en el lapso de unos minutos, lo acabo de pasar sin siquiera sudar.Ahora, tiene las mejores opciones para usar mysqli_ o PDO . Personalmente soy un gran admirador de PDO, por lo que usaré PDO en el resto de esta respuesta. Hay ventajas y desventajas, pero personalmente considero que las ventajas superan con creces a las desventajas. Es portátil a través de múltiples motores de base de datos, ya sea que esté utilizando MySQL u Oracle o casi cualquier cosa, simplemente cambiando la cadena de conexión, tiene todas las características elegantes que queremos usar y es agradable y limpio. Me gusta limpiar
Ahora, echemos un vistazo a ese código nuevamente, esta vez escrito usando un objeto PDO:
Las principales diferencias son que no hay más
mysql_*
funciones. Todo se hace a través de un objeto PDO, en segundo lugar, está utilizando una declaración preparada. Ahora, ¿qué es una declaración preparatoria que preguntas? Es una manera de decirle a la base de datos antes de ejecutar una consulta, cuál es la consulta que vamos a ejecutar. En este caso, le decimos a la base de datos: "Hola, voy a ejecutar una instrucción select que quiera id, userid y pass de los usuarios de la tabla donde el userid es una variable y el pass también es una variable".Luego, en la instrucción de ejecución, pasamos a la base de datos una matriz con todas las variables que ahora espera.
Los resultados son fantasticos. Probemos nuevamente esas combinaciones de nombre de usuario y contraseña:
El usuario no fue verificado. Increíble.
Qué tal si:
Oh, me emocioné un poco, funcionó: el cheque pasó. ¡Tenemos un administrador verificado!
Ahora, intentemos los datos que ingresaría un tipo inteligente para intentar pasar nuestro pequeño sistema de verificación:
Esta vez, obtenemos lo siguiente:
Esta es la razón por la que se te grita cuando publicas preguntas: es porque la gente puede ver que tu código se puede omitir sin siquiera intentarlo. Por favor, use esta pregunta y respuesta para mejorar su código, hacerlo más seguro y usar funciones actuales.
Por último, esto no quiere decir que este sea un código PERFECTO. Hay muchas más cosas que podría hacer para mejorarlo, use contraseñas con hash, por ejemplo, asegúrese de que cuando almacene información sensible en la base de datos, no la almacene en texto plano, tenga múltiples niveles de verificación, pero realmente, si solo cambia su antiguo código propenso a la inyección a esto, estará BIEN en el camino para escribir un buen código, y el hecho de que haya llegado tan lejos y aún esté leyendo me da la esperanza de que no solo implementará este tipo de código al escribir sus sitios web y aplicaciones, pero que podría salir e investigar esas otras cosas que acabo de mencionar, y más. Escriba el mejor código que pueda, no el código más básico que apenas funciona.
fuente
mysql_*
en sí mismo no es inseguro, pero promueve código inseguro a través de malos tutoriales y la falta de una declaración adecuada prepara API.La extensión MySQL es la más antigua de las tres y fue la forma original en que los desarrolladores solían comunicarse con MySQL. Esta extensión ahora está en desuso en favor de las otras dos alternativas debido a las mejoras realizadas en las versiones más recientes de PHP y MySQL.
MySQLi es la extensión 'mejorada' para trabajar con bases de datos MySQL. Aprovecha las funciones que están disponibles en las versiones más recientes del servidor MySQL, expone una interfaz orientada a funciones y orientada a objetos al desarrollador y hace algunas otras cosas ingeniosas.
PDO ofrece una API que consolida la mayor parte de la funcionalidad que anteriormente se extendía entre las principales extensiones de acceso a la base de datos, es decir, MySQL, PostgreSQL, SQLite, MSSQL, etc. La interfaz expone objetos de alto nivel para que el programador trabaje con conexiones de base de datos, consultas y conjuntos de resultados y controladores de bajo nivel realizan comunicación y manejo de recursos con el servidor de base de datos. Se está discutiendo y trabajando mucho en DOP y se considera el método apropiado para trabajar con bases de datos en código moderno y profesional.
fuente
Las respuestas anteriores me parecen muy largas, así que para resumir:
Fuente: descripción general de MySQLi
Como se explica en las respuestas anteriores, las alternativas a mysql son mysqli y PDO (PHP Data Objects).
Tanto MySQLi como PDO se introdujeron en PHP 5.0, mientras que MySQL se introdujo antes de PHP 3.0. Un punto a tener en cuenta es que MySQL está incluido en PHP5.x, aunque está en desuso en versiones posteriores.
fuente
Es posible definir casi todas las
mysql_*
funciones usando mysqli o PDO. Simplemente inclúyalos en la parte superior de su antigua aplicación PHP, y funcionará en PHP7. Mi solución aquí .fuente
Las funciones que son tan similares a este
mysql_connect()
,mysql_query()
tipo son la versión anterior funciones PHP es decir (PHP 4) y ahora no está en uso.Estos son reemplazados por
mysqli_connect()
, demysqli_query()
manera similar en el último PHP5.Esta es la razón detrás del error.
fuente
MySQL desaprobado en PHP 5.5.0 y eliminado en PHP 7.0.0. Para una aplicación grande y antigua, es difícil buscar y reemplazar cada función.
Podemos usar las funciones de MySQL creando una función de contenedor para cada uno de los siguientes códigos de ejecución. haga clic aquí
fuente
las funciones de mysql_ * quedaron en desuso (a partir de PHP 5.5 ) dado el hecho de que se desarrollaron mejores funciones y estructuras de código. El hecho de que la función haya quedado en desuso significa que no se hará más esfuerzo para mejorarla en términos de rendimiento y seguridad, lo que significa que es menos a prueba de futuro .
Si necesitas más razones:
fuente