Acceso a la base de datos PHP ¿Lo estás haciendo correctamente?

Hemos cubierto el API de PDO de PHP un par de veces aquí en Nettuts +, pero, en general, esos artículos se enfocaron más en la teoría y menos en la aplicación. Este artículo arreglará eso!

Para decirlo claramente, si todavía estás usando PHP antiguo mysql API para conectarse a sus bases de datos, siga leyendo!

Buscando un atajo?

Si está trabajando con PHP o MySQL y necesita una solución rápida para un error en su código, el desarrollador de PHP Araneux en Envato Studio puede corregir cualquier error individual de manera rápida y asequible..


Qué?

Es posible que, en este punto, el único pensamiento en tu mente sea: "¿Qué diablos es la DOP?" Bueno, es una de las tres API disponibles de PHP para conectarse a una base de datos MySQL. "Tres", dices? Sí; muchas personas no lo saben, pero hay tres API diferentes para conectarse:

  • mysql
  • mysqli - MySQL mejorado
  • pdo - Objetos de datos PHP

Lo tradicional mysql API ciertamente hace el trabajo, y se ha vuelto tan popular en gran parte debido al hecho de que hace que el proceso de recuperación de algunos registros de una base de datos sea lo más fácil posible. Por ejemplo:

/ * * Anti-Pattern * / # Connect mysql_connect ('localhost', 'username', 'password') o die ('No se pudo conectar:'. Mysql_error ()); # Elija una base de datos mysql_select_db ('someDatabase') o die ('No se pudo seleccionar la base de datos'); # Realizar la consulta de la base de datos $ query = "SELECT * from someTable"; $ resultado = mysql_query ($ consulta) o die ('Consulta fallida:'. mysql_error ()); # Filtrar a través de las filas y hacer eco de la información deseada mientras ($ row = mysql_fetch_object ($ result)) echo $ row-> name; 

Sí, el código anterior es bastante simple, pero viene con su parte significativa de desventajas.

  • Obsoleto: Aunque no ha sido oficialmente obsoleto, debido a su uso generalizado, en términos de mejores prácticas y educación, también podría ser.
  • Escapando El proceso de escape de la entrada del usuario se deja al desarrollador, muchos de los cuales no entienden o no saben cómo sanear los datos..
  • Flexibilidad: La API no es flexible; El código anterior está hecho a medida para trabajar con una base de datos MySQL. Que tal si cambias?

PDO, o PHP Data Objects, proporciona una API más poderosa que no le importa el controlador que usa; es agnóstico de la base de datos. Además, ofrece la posibilidad de utilizar declaraciones preparadas, eliminando virtualmente cualquier preocupación por la inyección de SQL. Echa un vistazo a la gama de scripts y aplicaciones PDO en Envato Market para tener una idea de lo que es posible.


Cómo?

Cuando aprendí por primera vez sobre la API de la DOP, debo admitir que fue un poco intimidante. Esto no se debió a que la API fuera demasiado complicada (no lo es), es solo que la antigua myqsl API era tan fácil de usar!

Pero no te preocupes; siga estos sencillos pasos y estará listo y funcionando en poco tiempo.

Conectar

Así que ya conoce la forma tradicional de conectarse a una base de datos MySQL:

# Conectar mysql_connect ('localhost', 'nombre de usuario', 'contraseña') o die ('No se pudo conectar:'. Mysql_error ());

Con PDO, creamos una nueva instancia de la clase y especificamos el controlador, el nombre de la base de datos, el nombre de usuario y la contraseña, como:

$ conn = new PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ contraseña);

No dejes que esa larga cuerda te confunda; es realmente muy simple: especificamos el nombre del controlador (mysql, en este caso), seguido de los detalles necesarios (cadena de conexión) para conectarse a él.

Lo bueno de este enfoque es que, si en cambio deseamos usar una base de datos sqlite, simplemente actualizamos el DSN, o el "Nombre de la fuente de datos", en consecuencia; no dependemos de MySQL de la forma en que somos cuando usamos funciones, como mysql_connect.

Los errores

Pero, ¿qué pasa si hay un error y no podemos conectarnos a la base de datos? Bueno, vamos a envolver todo dentro de una trata de atraparlo bloquear:

intente $ conn = new PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ contraseña); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

¡Eso es mejor! Tenga en cuenta que, de forma predeterminada, el modo de error predeterminado para DOP es DOP :: ERRMODE_SILENT. Con esta configuración sin cambios, tendrá que buscar errores manualmente, después de realizar una consulta.

echo $ conn-> errorCode (); echo $ conn-> errorInfo ();

En cambio, una mejor opción, durante el desarrollo, es actualizar esta configuración para DOP :: ERRMODE_EXCEPTION, lo que disparará excepciones a medida que se produzcan. De esta manera, cualquier excepción no detectada detendrá el script.

Para referencia, las opciones disponibles son:

  • DOP :: ERRMODE_SILENT
  • DOP :: ERRMODE_WARNING
  • DOP :: ERRMODE_EXCEPTION

Ha podido recuperar

En este punto, hemos creado una conexión a la base de datos; vamos a buscar algo de ella Hay dos formas principales de realizar esta tarea: consulta y ejecutar. Repasaremos ambos.

Consulta

/ * * El método de consulta * Anti-Pattern * / $ name = 'Joe'; # datos suministrados por el usuario intente $ conn = new PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ contraseña); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ data = $ conn-> query ('SELECT * FROM myTable WHERE name ='. $ conn-> quote ($ name)); foreach ($ data como $ row) print_r ($ row);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

Aunque esto funciona, observe que todavía estamos escapando manualmente los datos del usuario con el DOP :: cita método. Piense en este método como, más o menos, el equivalente a DOP a utilizar mysql_real_escape_string; escapará y citará la cadena que le pases. En situaciones, cuando está vinculando los datos proporcionados por el usuario a una consulta SQL, se recomienda encarecidamente que en su lugar utilice declaraciones preparadas. Dicho esto, si sus consultas SQL no dependen de los datos del formulario, la consulta El método es una opción útil, y hace que el proceso de hacer un ciclo a través de los resultados sea tan fácil como para cada declaración.

Declaraciones preparadas

/ * * El método de declaraciones preparadas * Mejores prácticas * / $ id = 5; intente $ conn = new PDO ('mysql: host = localhost; dbname = myDatabase', $ username, $ contraseña); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ conn-> prepare ('SELECT * FROM myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); while ($ row = $ stmt-> fetch ()) print_r ($ row);  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

En este ejemplo, estamos usando el preparar Método para, literalmente, preparar la consulta, antes de adjuntar los datos del usuario. Con esta técnica, la inyección de SQL es virtualmente imposible, porque los datos nunca se insertan en la consulta SQL, en sí misma. Observe que, en cambio, usamos parámetros nombrados (:carné de identidad) para especificar marcadores de posición.

Alternativamente, podrías usar ? parámetros, sin embargo, hace que sea una experiencia menos legible. Stick con parámetros nombrados.

A continuación, ejecutamos la consulta, mientras pasamos una matriz, que contiene los datos que deben estar vinculados a esos marcadores de posición..

$ stmt-> execute (array ('id' => $ id));

Un enfoque alternativo, pero perfectamente aceptable, sería utilizar el bindParam método, como tal:

$ stmt-> bindParam (': id', $ id, PDO :: PARAM_INT); $ stmt-> execute ();

Especificando la salida

Después de llamar al ejecutar método, hay una variedad de formas diferentes de recibir los datos: una matriz (la predeterminada), un objeto, etc. En el ejemplo anterior, se usa la respuesta predeterminada: DOP :: FETCH_ASSOC; esto puede ser fácilmente anulado, sin embargo, si es necesario:

while ($ row = $ stmt-> fetch (PDO :: FETCH_OBJ)) print_r ($ row); 

Ahora, hemos especificado que queremos interactuar con el conjunto de resultados de una manera más orientada a objetos. Las opciones disponibles incluyen, pero no se limitan a:

  • DOP :: FETCH_ASSOC: Devuelve una matriz.
  • DOP :: FETCH_BOTH: Devuelve una matriz, indexada por nombre de columna y 0 indexada.
  • DOP :: FETCH_BOUND: Devuelve VERDADERO y asigna los valores de las columnas en su conjunto de resultados a las variables de PHP a las que estaban vinculadas.
  • DOP :: FETCH_CLASS: Devuelve una nueva instancia de la clase especificada.
  • DOP :: FETCH_OBJ: Devuelve un objeto anónimo, con nombres de propiedades que corresponden a las columnas.

Un problema con el código anterior es que no proporcionamos ningún comentario, si no se devuelven resultados. Vamos a arreglar eso:

$ stmt-> execute (array ('id' => $ id)); # Obtener una matriz que contenga todas las filas de resultados $ result = $ stmt-> fetchAll (); # Si se devolvieron una o más filas ... if (cuenta ($ resultado)) foreach ($ resultado como $ fila) print_r ($ fila);  else else echo "No se devolvieron filas"; 

En este punto, nuestro código completo debería verse así:

 $ id = 5; intente $ conn = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ stmt = $ conn-> prepare ('SELECT * FROM myTable WHERE id =: id'); $ stmt-> execute (array ('id' => $ id)); $ result = $ stmt-> fetchAll (); if (count ($ result)) foreach ($ result as $ row) print_r ($ row);  else else echo "No se devolvieron filas";  catch (PDOException $ e) echo 'ERROR:'. $ e-> getMessage (); 

Ejecuciones Múltiples

La extensión PDO se vuelve particularmente poderosa cuando se ejecuta la misma consulta SQL varias veces, pero con diferentes parámetros.

intente $ conn = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); # Prepare la consulta UNA VEZ $ stmt = $ conn-> prepare ('INSERTE EN LOS VALORES DE LA TABLA (: nombre)'); $ stmt-> bindParam (': name', $ name); # Primera inserción $ nombre = 'Keith'; $ stmt-> execute (); # Segunda inserción $ nombre = 'Steven'; $ stmt-> execute ();  catch (PDOException $ e) echo $ e-> getMessage (); 

Una vez que la consulta ha sido preparada, se puede ejecutar varias veces, con diferentes parámetros. El código anterior insertará dos filas en la base de datos: una con el nombre "Kevin" y la otra "Steven".


CRUD

Ahora que tiene el proceso básico implementado, revisemos rápidamente las diversas tareas de CRUD. Como encontrarás, el código requerido para cada uno es virtualmente idéntico.

Crear (Insertar)

intente $ pdo = nuevo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ contraseña); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('INSERTE EN LOS VALORES DE UNA TABLA (: nombre)'); $ stmt-> execute (array (': name' => 'Justin Bieber')); # ¿Filas afectadas? echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ e-> getMessage ();

Actualizar

$ id = 5; $ name = "Joe the Plumber"; intente $ pdo = nuevo PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ contraseña); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('ACTUALIZAR alguna tabla SET nombre =: nombre WHERE id =: id'); $ stmt-> execute (array (': id' => $ id, ': name' => $ name)); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ e-> getMessage (); 

Borrar

$ id = 5; // De una forma o algo similar, intente $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ stmt = $ pdo-> prepare ('DELETE FROM someTable WHERE id =: id'); $ stmt-> bindParam (': id', $ id); // esta vez, usaremos el método bindParam $ stmt-> execute (); echo $ stmt-> rowCount (); // 1 catch (PDOException $ e) echo 'Error:'. $ e-> getMessage (); 

Mapeo de objetos

Uno de los aspectos más claros de PDO (mysqli, también) es que nos brinda la capacidad de asignar los resultados de la consulta a una instancia de clase u objeto. Aquí hay un ejemplo:

usuario de la clase public $ first_name; public $ last_name; función pública full_name () return $ this-> first_name. ". $ this-> last_name; intente $ pdo = new PDO ('mysql: host = localhost; dbname = someDatabase', $ username, $ password); $ pdo-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ result = $ pdo-> query ('SELECT * FROM someTable'); 'User'); while ($ user = $ result-> fetch ()) # Llame a nuestro método personalizado de full_name echo $ user-> full_name (); catch (PDOException $ e) echo 'Error:'. $ e-> getMessage ();

Pensamientos de cierre

En pocas palabras: si todavía estás usando ese viejo mysql API para conectarse a sus bases de datos, deténgase. Aunque aún no ha sido desaprobado, en términos de educación y documentación, bien podría estarlo. Su código será significativamente más seguro y simplificado si adopta la extensión PDO. Revise los artículos de la DOP en Envato Market para ver qué puede hacer.