lunes, 26 de agosto de 2013

[Tutorial] PDO MySQL

¿Por que usar PDO en lugar de mysql_*?

Una de las razones es por que ya no tendrá mas mantenimiento.


Y otra es que PDO es mas eficaz, limpio y seguro.

¿Que es PDO?

Es un controlador que implementa la interfaz de datos de php (PDO) esta disponible para varias bases de datos pero nosotros nos enfocaremos en mysql, para poder en este caso utilizar PDO necesitamos tener ese controlador y podemos verificarlo desde un archivo PHP que contenga la función:  phpinfo();



PDO viene por defecto en PHP 5.1 y aprovecha las sentencias preparadas en MySQL 4.1 o superior. Si se utiliza un version anterior PDO las emulará.

Conectando a MySQL

Anteriormente conectabamos a MySQL de la siguiente manera:


$conectar=mysql_connect('localhost','usuario','contrasena');
mysql_select_db('tubasededatos',$conectar);
mysql_set_charset('UTF-8',$conectar);

En este caso lo que hacemos seria conectar a la base de datos y darle que nos acepte caracteres unicode :)


Ahora con usando PDO en MySQL conectamos de la siguiente manera:

$bd=new PDO($dsn,$usuario_bd,$contraseña_bd);

Explico:

$dsn  - Data source name (nombre de origen de datos), nos indica a que tipo de base de datos nos estaremos conectando en este caso como es mysql, tiene varios parametros como son: host, port, dbname, unix_socket,charset. Su sintaxis basica es la siguiente:

DRIVER:HOST;dbname=mibd;

$usuario - Es el nombre de usuario de la base de datos

$contraseña_bd - Es la contraseña de la base de datos


Un ejemplo haciendo la conexion como la que usabamos anteriormente pero ya aplicando PDO en MySQL es de la siguiente manera:

$bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','Usuario','Contraseña');


Entonces vamos hacer nuestra conexion :D



Si todo aparece en blanco significa que la conexion se ha realizado con exito, sino entonces deberia saltar un error. Por ejemplo:



Como ves ese error se ve algo feo entonces podemos usar una excepción y arrojar nuestro propio error antes en mysql_* usabamos or die()

De la manera anterior:

$conectar=mysql_connect('localhost','usuario','contrasena') or die('No se pudo conectar con la base de datos.');

Usando Excepciones con PDO en MySQL:

try{
 $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','Usuario','Contraseña');
}catch(PDOException $ex){
  echo 'No se pudo conectar con la base de datos.';
}

En este caso si no damos algun dato correcto nos dara el mensaje de error personalizado.



Realizar Consultas

Seleccionando datos

Se podría decir fácilmente que esta es la parte mas interesante :D

Anteriormente, pediamos una consulta de la siguiente manera:

$conectar=mysql_connect('localhost','usuario','contraseña') or die('No se pudo conectar con la base de datos.');
    mysql_select_db("test");
    $peticion=mysql_query("SELECT * FROM accounts",$conectar);
    while($filas=mysql_fetch_array($peticion,MYSQL_ASSOC)){
        echo $filas['id']."<br />";
        echo $filas['name']."<br />";
        echo $filas['balance']."<br />";
        echo "<hr />";
    }

Que lo que haria seria conectar a la base de datos, seleccionar nuestra base de datos, y luego hacer una peticion, mientras la peticion sea verdad nos arrojara los registros id,name y balance.

De esa manera nos arrojaba un resultado como el siguiente:


Usando PDO en MySQL lo podemos hacer de la siguiente manera:

try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $stmt= $bd->query("SELECT * FROM accounts");
    while($filas=$stmt->fetch(PDO::FETCH_ASSOC)){
        echo $filas['id']."<br />";
        echo $filas['name']."<br />";
        echo $filas['balance']."<br />";
        echo "<hr />";
    }



Lo que decimos con este codigo es que se conecte a la base de datos que haga la peticion haciendo referencia al objecto $bd, query() este metodo lo que hace es ejecutar una consulta, mientras que sea verdad que nos muestre las filas id,name y balance. fetch() este metodo nos devuelve un array con los registros y con el bucle while los recorremos, en este caso le damos la opcion PDO::FETCH_ASSOC que estamos dandole que se puedan poner los arrays con su nombre, otra opcion del modo de devolver los registros podria ser numericos usando PDO::FETCH_NUM.

Y el resultado es exactamente el mismo.

También podemos usar el método fetchAll() en lugar de fetch() la diferencia es que fetchAll() retorna todos los registros y fetch() de 1 registro en 1 por eso lo recorremos con el bucle, una manera de verlo en accion seria comparando estos dos, de la siguiente manera:

Ejemplo usando fetchAll():

try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $stmt= $bd->query("SELECT * FROM accounts");
    print_r($stmt->fetchAll(PDO::FETCH_ASSOC));

Resultado:



Ejemplo usando fetch():

try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $stmt= $bd->query("SELECT * FROM accounts");
    print_r($stmt->fetch(PDO::FETCH_ASSOC));

Resultado:




Obteniendo el numero de filas


Anteriormente utilizabamos la funcion mysql_num_rows() para realizar esta accion, de manera que era asi:

$conectar=mysql_connect('localhost','usuario','contraseña') or die('No se pudo conectar con la base de datos.');
    mysql_select_db("test");
    $peticion=mysql_query("SELECT * FROM accounts",$conectar);
    echo mysql_num_rows($peticion);


De esta manera como solo tengo 3 filas me devolveria el numero 3 :P :D

Podemos hacer lo mismo usando el metodo rowCount() en PDO.


try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $stmt= $bd->query("SELECT * FROM accounts");
    echo $stmt->rowCount();

Seria el mismo resultado 3 por que son 3 filas :D, rowCount() - retorna el numero de filas.


Ultimo id de inserción de registros

mysql_insert_id() - devuelve el ultimo numero de registro.
Si el registro se inserta devuelve el numero del ultimo registro pero si no se inserta devuelve un 0.

Ejemplo usando mysql_insert_id():

$conectar=mysql_connect('localhost','usuario','contraseña') or die('No se pudo conectar con la base de datos.');
    mysql_select_db("test");
    $peticion=mysql_query("INSERT INTO usuarios (nombre,apellido) VALUES ('john2','doe2')",$conectar);
    echo mysql_insert_id();

El resultado es el siguiente:



Usando PDO el metodo lastInsertId(); seria su equivalente.

try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $stmt= $bd->query("INSERT INTO usuarios (nombre,apellido) VALUES ('john2','doe2')");
    echo $bd->lastInsertId();

El resultado:








Declaraciones insert, update y delete

mysql_affected_rows() - Nos dice el numero de filas que han sido afectadas  en las consultas insert,update o delete.

Un ejemplo usando esta funcion:

$conectar=mysql_connect('localhost','usuario','contraseña') or die('No se pudo conectar con la base de datos.');
    mysql_select_db("test");
    $peticion=mysql_query("UPDATE usuarios SET nombre='john'",$conectar);
    echo mysql_affected_rows();



En este caso me devolveria 8 ya que 8 filas fueron afectadas por ese update ya que no le indique un filtro de que valores quiero solamente.


Podemos hacer lo mismo usando PDO de la siguiente manera:




try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    $rows_affected=$bd->exec("UPDATE usuarios SET nombre='arthusu'");
    echo $rows_affected;


En este caso obtendríamos el mismo resultado que es 8 filas cambiadas, algo interesante en esta parte es que no estamos usando el método query() sino estamos usando exec() para ejecutar la consulta esto lo usamos mas en clausulas insert,update y delete.


Declaraciones Preparadas


Las declaraciones preparadas es la parte mas importante aqui ya que con esto nos evitaremos las famosas "Inyecciones SQL".


prepare() - Prepara una sentencia SQL
execute() - Ejecuta una sentencia preparada
bindParam() - Vincula un parametro al nombre de variable especificado


Un ejemplo:


try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    if(isset($_POST['enviar'])){
    $stmt=$bd->prepare("INSERT INTO usuarios (nombre,apellido) VALUES (:nombre,:apellido)");
    $stmt->bindParam(':nombre',$_POST['nombre'],PDO::PARAM_STR);
    $stmt->bindParam(':apellido',$_POST['apellido'],PDO::PARAM_STR);
    $stmt->execute();
    }



Lo que hace esto es algo nada filtrado en verdad xD. Solo Dice que si existe enviar entonces que prepare la inserción de un nuevo registro con nombre y apellido y esos dos los evalue como cadenas PDO::PARAM_STR también esta PDO::PARAM_INT,PDO::PARAM_BOOL,PDO::PARAM_NULL ... despues que ejecute la consulta...

Si hacemos esto ingresamos algún carácter para romper la consulta, lo que haría esto seria escaparlos (\) :P


 
Como cerrar la base de datos

Para cerrar una conexion solo necesitamos declarar nuestro objeto como null, por ejemplo:

$bd=null;

Aplicado al anterior codigo:

try{
    $bd= new PDO('mysql:host=localhost;dbname=test;charset=utf8','usuario','contraseña');
}catch(PDOException $ex){
    echo 'No se pudo conectar con la base de datos.';
}
    if(isset($_POST['enviar'])){
    $stmt=$bd->prepare("INSERT INTO usuarios (nombre,apellido) VALUES (:nombre,:apellido)");
    $stmt->bindParam(':nombre',$_POST['nombre'],PDO::PARAM_STR);
    $stmt->bindParam(':apellido',$_POST['apellido'],PDO::PARAM_STR);
    $stmt->execute();
    }
    $bd=null;

Conclusión

Usar PDO es mas seguro, eficaz y limpio.


Espero que este tutorial les haya gustado pero eso no es todo si quieren tener algo mas completo pueden ver la documentacion oficial de PHP

2 comentarios: