Diferencia entre revisiones de «Usuario:ManuelRomero/php/BasesDatos»
De WikiEducator
< Usuario:ManuelRomero | php
(33 revisiones intermedias por el mismo usuario no mostrado) | |||
Línea 2: | Línea 2: | ||
− | |||
<!--__NOEDITSECTION__--> | <!--__NOEDITSECTION__--> | ||
Línea 339: | Línea 338: | ||
$fila = $resultado->fetch_array(); | $fila = $resultado->fetch_array(); | ||
} | } | ||
− | $ | + | $resultado->free(); |
$conexion->close(); | $conexion->close(); | ||
} | } | ||
Línea 380: | Línea 379: | ||
Ejercicio de transacciones | Ejercicio de transacciones | ||
}} | }} | ||
+ | |||
+ | ===Injecciones SQL=== | ||
+ | *Es un problema de seguridad importante, que hay que conocer y evitar | ||
+ | *Existe mucha documentación al respecto, en general podemos afirmar que un buen conocimiento de SQL proporcina herramientas tanto para poder establecer este tipo de ataques, como para podernos prevenir de ellos. | ||
+ | *Aportamos referenicas de web que nos pueden interesar consultar | ||
+ | {{Recursos de la Web| | ||
+ | #http://php.net/manual/es/security.database.sql-injection.php | ||
+ | #http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL | ||
+ | #http://www.w3schools.com/sql/sql_injection.asp | ||
+ | *Otras entradas un poco cuestionables por finalidad ??? | ||
+ | #http://foro.elhacker.net/tutoriales_documentacion/tutorial_de_inyeccion_sql_sql_injection-t98448.0.html | ||
+ | #http://www.mclibre.org/consultar/php/lecciones/php_db_inyeccion_sql.html#L2641 | ||
+ | #http://blog.netrunners.es/tabla-de-trucos-para-inyeccion-de-sql/ | ||
+ | }} | ||
+ | *A continuación y usando el ejemplo anterior de '''''acceso''''' vamos a probar a realizar un sencillo ataques sql. | ||
+ | #Entrar en la plataforma sin tener acceso | ||
+ | |||
+ | ===Entrar en la plataforma sin tener acceso=== | ||
+ | *Entramos en una página y vemos el siguiente acceso | ||
+ | [[Archivo:miAcceso.png]] | ||
+ | *Como no sabemos el usuario ni contraseña probamos a ver si se puede hacer una inserción no controlada | ||
+ | *Como programadores esperamos que en el código haya algo del estilo, como es nuestro caso | ||
+ | <source lang=php> | ||
+ | $nombre=$_POST['usuario']; | ||
+ | $pass=$_POST['pass']; | ||
+ | |||
+ | $consulta="select * from usuarios where nombre = \"$nombre\" and pass = \"$pass\" "; | ||
+ | $resultado = $conexion->query($consulta); | ||
+ | </php> | ||
+ | *Si todo fuera normal y nombre fuera por ejemplo "maría" la consulta que se envía al servidor sería | ||
+ | <source lang=php> | ||
+ | select * from usuarios where nombre = "maria" | ||
+ | </source> | ||
+ | *Esta consulta si existe el usuario maría nos retornará una tupla, si no no devolverá ninguna. | ||
+ | *Pero si añadimos más cosas obtendremos segura una respuesta, por ejemplo si en el codigo $nombre="maria or \"1\"= \"1\" " | ||
+ | *Entonces la consulta quedaría | ||
+ | <source lang=php> | ||
+ | select * from usuarios where nombre = "maria" or "1"="1" | ||
+ | </source> | ||
+ | *Que nos devolverá todas las filas | ||
+ | *Así que si introducimos estos datos | ||
+ | [[Archivo:miAccesoInjeccion.png]] | ||
+ | *Entramos al sistema sin conocer usuario y contraseña | ||
+ | [[Archivo:accesoInjectado.png]] | ||
===Consultas preparadas=== | ===Consultas preparadas=== | ||
Línea 386: | Línea 429: | ||
*Para trabajar con consultas preparadas, debemos usar la clase '''''mysqli_stmt''''', e inicializarla con el método '''''stmt_init ''''' | *Para trabajar con consultas preparadas, debemos usar la clase '''''mysqli_stmt''''', e inicializarla con el método '''''stmt_init ''''' | ||
<source lang=php> | <source lang=php> | ||
− | $ | + | $conexion = new mysqli('localhost', 'dwes', 'abc123.', 'dwes'); |
//Preparo el objeto $consulta para crear consultas preparadas en él | //Preparo el objeto $consulta para crear consultas preparadas en él | ||
− | $consulta = $ | + | $consulta = $conexion->stmt_init(); |
</source> | </source> | ||
Los pasos para trabajar con consultas preparadas son: | Los pasos para trabajar con consultas preparadas son: | ||
Línea 395: | Línea 438: | ||
#Una vez que ya no se necesita más, se debe ejecutar el método '''''close'''''. | #Una vez que ya no se necesita más, se debe ejecutar el método '''''close'''''. | ||
<source lang=php> | <source lang=php> | ||
− | $consulta = $ | + | $consulta = $conexion->stmt_init(); |
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES ("TABLET", "Tablet PC")'); | $consulta->prepare('INSERT INTO familia (cod, nombre) VALUES ("TABLET", "Tablet PC")'); | ||
$consulta->execute(); | $consulta->execute(); | ||
$consulta->close(); | $consulta->close(); | ||
− | $ | + | $conexion->close(); |
</source> | </source> | ||
+ | |||
===Parametrizar las consultas preparadas=== | ===Parametrizar las consultas preparadas=== | ||
*El uso real de las consultas preparadas es que los valores que pasas se asignen antes de ejectuar la consulta. | *El uso real de las consultas preparadas es que los valores que pasas se asignen antes de ejectuar la consulta. | ||
Línea 425: | Línea 469: | ||
*En el ejemplo que estamos siguiendo | *En el ejemplo que estamos siguiendo | ||
<source lang=php> | <source lang=php> | ||
− | $consulta = $ | + | $consulta = $conexion->stmt_init(); |
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)'); | $consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)'); | ||
$cod_producto = "TABLET"; | $cod_producto = "TABLET"; | ||
Línea 436: | Línea 480: | ||
</source> | </source> | ||
{{Resumen| | {{Resumen| | ||
+ | <source lang=php> | ||
$conexion = new mysqli(...); | $conexion = new mysqli(...); | ||
$consulta = $conexion->stmt_init(); | $consulta = $conexion->stmt_init(); | ||
Línea 443: | Línea 488: | ||
$consulta->close(); | $consulta->close(); | ||
$conexion->close(); | $conexion->close(); | ||
− | + | </source> | |
}} | }} | ||
− | ===Consultas preparadas que retornan valores | + | |
+ | ===Consultas preparadas que retornan valores=== | ||
*En caso de que la consulta preparada retorne valores se recogen con el método '''''bind_result'''' | *En caso de que la consulta preparada retorne valores se recogen con el método '''''bind_result'''' | ||
*Este método recibirá variables en los que se almacenarán los valores | *Este método recibirá variables en los que se almacenarán los valores | ||
*Para recorre el conjunto de valores, usamos el método fectch(), como se ve en el ejemplo | *Para recorre el conjunto de valores, usamos el método fectch(), como se ve en el ejemplo | ||
<source lang=php> | <source lang=php> | ||
− | $consulta = $ | + | $consulta = $conexion->stmt_init(); |
$consulta->prepare('SELECT producto, unidades FROM stock WHERE unidades<2'); | $consulta->prepare('SELECT producto, unidades FROM stock WHERE unidades<2'); | ||
$consulta->execute(); | $consulta->execute(); | ||
Línea 458: | Línea 504: | ||
} | } | ||
$consulta->close(); | $consulta->close(); | ||
− | $ | + | $conexion->close(); |
</source> | </source> | ||
*Aquí hay un enlace para una información completa sobre consultas preparadas | *Aquí hay un enlace para una información completa sobre consultas preparadas | ||
http://php.net/manual/es/class.mysqli-stmt.php | http://php.net/manual/es/class.mysqli-stmt.php | ||
+ | {{Actividad| | ||
+ | *Modifica el ejercicio anterior usando consultas parametrizadas | ||
+ | }} | ||
{{Actividad| | {{Actividad| | ||
− | * | + | *Vamos a trabajar con la base de datos de la tienda |
− | * | + | *Lo primero usando la herramienta workbench generamos el modelo de tablas de la base de datos dwes y la analizamos |
+ | *Crea una página web en la que se muestre el stock existente de un determinado producto en cada una de las tiendas. | ||
+ | *Para seleccionar el producto concreto utiliza un cuadro de selección dentro de un formulario en esa misma página. | ||
+ | * Puedes usar como base los siguientes ficheros css y plantilla adjuntos. | ||
+ | *Añade la opción de modificar el número de unidades del producto en cada una de las tiendas. | ||
+ | *Utiliza una consulta preparada para la actualización de registros en la tabla stock. | ||
+ | *No es necesario tener en cuenta las tareas de inserción (no existían unidades anteriormente) y borrado (si el número final de unidades es cero). | ||
}} | }} | ||
<!-- | <!-- | ||
Línea 489: | Línea 544: | ||
--> | --> | ||
+ | ==Bases de datos con PDO== | ||
+ | ===Qué es PDO=== | ||
+ | *La extensión PDO (PHP Data Objects) permite acceder a diferentes gestores de bases de datos utilizando las misma funciones. | ||
+ | *Esto es una gran ventaja frente a la extensión vista anteriormente mysqli, | ||
+ | *PDO nos abstrae de forma completa el sistema gestor que se utiliza. | ||
+ | *Como comentamos en el tema anterior, necesitaremos el driver concreto dependiendo del sistema gestor de bases de datos. | ||
+ | *Esto es lo único que tendremos que cambiar en nuestro programa para que funcione en uno u otro gestor de bases de datos, sin tener que cambiar nada del sql. | ||
+ | *En PHP 5 existen drivers para acceder a las bases de datos más populares (MySQL, Oracle, MS SQL Server, PostgreSQL, SQLite, Firebird, DB2, Informix, etc). | ||
+ | *En el siguiente enlace podemos ver los controladores de PDO que soporta directamente php. | ||
+ | http://es.php.net/manual/es/pdo.drivers.php | ||
+ | |||
+ | *En esta lección se explica el acceso a MySQL y SQLite mediante PDO. La extensión PDO no evalúa la correción de las consultas SQL. | ||
+ | |||
+ | ===Establecer conexión con PDO=== | ||
+ | *Para establecer una conexión lo que hacemos es instanciar un objeto de la clase PDO | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO(...); | ||
+ | </source> | ||
+ | El constructor tien 4 parámetros de los cuales sólo el primero es obligatorio | ||
+ | ;Origen de datos (DSN). | ||
+ | :Este parámetro es un string que la información del controlador del driver que voy a utilizar y se especifica de la siguiente manera | ||
+ | controlador:parametro1=dato1;parametro2=datos...parametron=daton | ||
+ | :Los parámetros a especificar dependerá del controlador que vamos a utilizar, en general me informarán del controlador del driver que voy a utilizar como por ejemplo el nombre o dirección IP del servidor, el nombre de la base de datos). | ||
+ | :Por ejemplo en el caso del controlador mysql | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO('mysql:host=localhost;dbname=dwes', ...); | ||
+ | </source> | ||
+ | ;Nombre de usuario | ||
+ | ;Contraseña del usuario. | ||
+ | ;Opciones de conexión, almacenadas en forma de array. | ||
+ | *Muchas de las opciones de conexión dependerán del driver que vayamos a utilizar | ||
+ | *Por ejemplo con mysql podemos verlas aquí http://php.net/manual/es/ref.pdo-mysql.php | ||
+ | (Ver dentro de cada página de controladores http://php.net/manual/es/pdo.drivers.php) | ||
+ | ====Conxión con mysql==== | ||
+ | *En el caso de mysql en parámetro DNS tendríamos los siguientes datos | ||
+ | *'''''host''''' Nombre o dirección IP del servidor. | ||
+ | *'''''port''''' Número de puerto TCP en el que escucha el servidor. | ||
+ | *'''''dbname''''' Nombre de la base de datos. | ||
+ | *'''''unix_socket''''' Socket de MySQL en sistemas Unix. | ||
+ | *Como podemos ver en el ejemplo anterior, no todos los datos del parámetro DNS son obligatorios, podemos establecer la conexión con '''''host''''' y '''''dbname'''''. | ||
+ | *Respecto a las opciones de conexión permiten establecer varios cuestiones | ||
+ | *Una vez establecida la conexión se pueden consultar/acutalizar valores de opciones de la conexión usando los métodos | ||
+ | getAtribute(int $atributo); | ||
+ | setAtribute(int $atributo, mixed $valor); | ||
+ | *Podemos ver los atributos en la página http://es.php.net/manual/es/pdo.setattribute.php http://es.php.net/manual/es/pdo.getattribute.php | ||
+ | ===Realizar consultas con PDO=== | ||
+ | *En el caso de PDO, se diferencias las consultas que retornan datos (SELECT) y las que actúan sobre el contendio de los datos (INSERT, UPDATE, DELETE) | ||
+ | ;INSERT, OPDATE, DELETE | ||
+ | *En este caso la sentencia se ejecuta envíandola con el métido '''''exec($sentencia)''''' | ||
+ | *Este método retorna un entero que indica en número de registros afectados | ||
+ | <source lang=sql> | ||
+ | $conexion= new PDO("mysql:host=localhost;db=dwes","root","root"); | ||
+ | $registros = $conexion->exec("DELETE FROM stock WHERE unidades=0"); | ||
+ | print "<p>Se han borrado $registros registros.</p>"; | ||
+ | </source> | ||
+ | ;SELECT | ||
+ | *En este caso debemos usar el método de la clase PDO llamado '''''query($consulta)''''' | ||
+ | *Este método retorna un objeto de la clase '''''PDOStatement''''' http://es1.php.net/manual/es/class.pdostatement.php | ||
+ | *Una vez que tenemos el objeto de la clase ya tenemos ese cursor o conjunto de filas con su puntero | ||
+ | *Para extraer cada fila usamos el método '''''fetch()''''', el cual en caso de que no haya filas que retornar devuelve null (El mismo concepto trabajado hasta ahora). | ||
+ | *Cada vez que hacemos un fetch obtenemos un array con la fila que podemos usar tanto de forma asociativa como indexada. | ||
+ | *Este comportamiento por defecto se puede cambiar, es decir que podemos obligar a que el array que devuelve sea indexado, asociativo o que sea un objeto. | ||
+ | *Para ello debemos pasar al método fetch un valor que lo especifique según la lista siguiente. | ||
+ | *Para cerrar el cursor se emplea el método '''''closeCursor()'''''; muchos gestores de bases de datos necesitas que se libere, antes de ser usado para realizar otra consulta. | ||
+ | #PDO::FETCH_ASSOC. Devuelve solo un array asociativo. | ||
+ | #PDO::FETCH_NUM. Devuelve solo un array con claves numéricas. | ||
+ | #PDO::FETCH_BOTH. Devuelve un array con claves numéricas y asociativas. Es el comportamiento por defecto. | ||
+ | #PDO::FETCH_OBJ. Devuelve un objeto cuyas propiedades se corresponden con los campos del registro. | ||
+ | *A continuación diferentes formas de hacer exactamente lo mismo | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $resultado = $dwes->query("SELECT producto, unidades FROM stock"); | ||
+ | while ($registro = $resultado->fetch()) { | ||
+ | echo "Producto ".$registro['producto'].": ".$registro['unidades']."<br />"; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $resultado = $dwes->query("SELECT producto, unidades FROM stock"); | ||
+ | while ($registro = $resultado->fetch(FETCH_ASSOC)) { | ||
+ | echo "Producto ".$registro['producto'].": ".$registro['unidades']."<br />"; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $resultado = $dwes->query("SELECT producto, unidades FROM stock"); | ||
+ | while ($registro = $resultado->fetch(FETCH_NUM)) { | ||
+ | echo "Producto ".$registro[0].": ".$registro[1]."<br />"; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $resultado = $dwes->query("SELECT producto, unidades FROM stock"); | ||
+ | while ($registro = $resultado->fetch(FETCH_OBJECT)) { | ||
+ | echo "Producto ".$registro.producto.": ".$registro.unidades."<br />"; | ||
+ | } | ||
+ | </source> | ||
+ | {{Resumen| | ||
+ | <source lang=php> | ||
+ | $conexion="mysql:host=localhost;dbname=dwes"; | ||
+ | $user="root"; | ||
+ | $pass="root"; | ||
+ | $opciones=$array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); | ||
+ | |||
+ | $conexion=new PDO($conexion,$usuario,$pass, $opciones); | ||
+ | $consulta = "Select * from ..."; | ||
+ | $sentencia = "Insert into ....." | ||
+ | $resultado = $conexion->exec($sentencia); | ||
+ | $sentencia->closeCursor(); | ||
+ | echo "Se han insertado $resultado filas"; | ||
+ | $resultado = $conexion->query($sconsulta); | ||
+ | while $resultado->fetch(){ | ||
+ | echo "se la leído el valor $resultado[0], ..."; | ||
+ | } | ||
+ | $conexion=null; //Es la manera de liberar a la memoria de este objeto. | ||
+ | |||
+ | </source> | ||
+ | }} | ||
+ | ===Consultas preparadas=== | ||
+ | *Al igual que en mysqli, podemos preparar las consultas. Esta forma de trabajar es cómoda y mas segura que la habitual, según viemos en apartados anteriores | ||
+ | *Para realizar una consulta parametrizada, hay que seguir unos pasos al igual que en '''''mysqli''''' | ||
+ | ;preparar la consulta '''''prepare(...)''''' | ||
+ | *Para ello se pueden pasar con ? los valores de los parámetros o bien poner un nombre precedido de : | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)'); | ||
+ | </source> | ||
+ | Es igual que hacer | ||
+ | <source lang=php> | ||
+ | $conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123."); | ||
+ | $consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (:codigoProducto, :nombreProducto)'); | ||
+ | </source> | ||
+ | ;Asignar valores a la consulta pararmetrizada | ||
+ | *Si se han especificado ? se asigna dando a cada parámetro un valor con el método bindParam(posicion, valor) | ||
+ | <source lang=php> | ||
+ | $cod_producto = "TABLET"; | ||
+ | $nombre_producto = "Tablet PC"; | ||
+ | $consulta->bindParam(1, $cod_producto); | ||
+ | $consulta->bindParam(2, $nombre_producto); | ||
+ | </source> | ||
+ | *Si se han especificado con nombre se usan los nombre en lugar de los números | ||
+ | |||
+ | <source lang=php> | ||
+ | $cod_producto = "TABLET"; | ||
+ | $nombre_producto = "Tablet PC"; | ||
+ | $consulta->bindParam(":cod", $cod_producto); | ||
+ | $consulta->bindParam(":nombre", $nombre_producto); | ||
+ | </source> | ||
+ | *Se ejecuta con el método execute() | ||
+ | *Este método permite alternativamente suplir las asignaciones anteriores realizadas con el método bindParam, pasándole en un argumento meditante una array dicha asignación. | ||
+ | *El array utilizado será asociativo o con claves numéricas dependiendo de la forma en que hayas indicado los parámetros. | ||
+ | *En el primer caso | ||
+ | <source lang=php> | ||
+ | $parametros = array["TABLET", ":nombre"]; | ||
+ | $consulta->execute($parametros); | ||
+ | </source> | ||
+ | *En el segundo caso | ||
+ | <source lang=php> | ||
+ | $parametros = array(":cod" => "TABLET", ":nombre" => "Tablet PC"); | ||
+ | $consulta->execute($parametros); | ||
+ | </source> | ||
+ | {{Actividad| | ||
+ | *Realiza un pequeño program en php que usando la extensión '''''PDO''''', realice las siguientes acciones | ||
+ | #Se conecte a la base de datos '''''dwes''''' | ||
+ | #insertamos un nuevo eleemntos o tupla en la tabla producto | ||
+ | #consultamos todos los productos y los visualizamos | ||
+ | #Hacemos otra consulta parametrizada de todos los productos de la tabla stock de una determinada tienda | ||
+ | ##Esta última acción primero usando '''''bindParam''''' y luego sin usarlo (pasando directamente el parámetro al método execute | ||
+ | |||
+ | <source lang=php> | ||
+ | <!DOCTYPE html> | ||
+ | <html> | ||
+ | <head> | ||
+ | <meta charset="UTF-8"> | ||
+ | <title></title> | ||
+ | </head> | ||
+ | <body> | ||
+ | <?php | ||
+ | $dns = "mysql:host=localhost; dbname=dwes"; | ||
+ | $user='root'; | ||
+ | $pass='root'; | ||
+ | $opciones= array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); | ||
+ | //Realizamos una conexión básico pdo | ||
+ | $conexion = new PDO($dns, $user, $pass, $opciones); | ||
+ | if ($conexion) | ||
+ | echo "conexión realizada satisfactoriamente"; | ||
+ | else | ||
+ | echo "ohhhh!!!! no se ha conectado"; | ||
+ | |||
+ | //Ahora planteamos una sentencia de tipo insert | ||
+ | $sentencia = "insert into producto values('NEW_PRODUCTO12','NOMBRE_PRODUCTO','NOMBRE_CORTO','DESCRIPCION DESCRIPCION',10000,'MP3')"; | ||
+ | |||
+ | //Y planteamos tambión una sentencia select | ||
+ | $consulta ="select nombre_corto from producto"; | ||
+ | $filas= $conexion->exec($sentencia); | ||
+ | echo"Se ha insertado correctamene $filas"; | ||
+ | //$filas será un objeto del tipo PDOStatement | ||
+ | $filas= $conexion->query($consulta); | ||
+ | |||
+ | while ($fila=$filas->fetch()){ | ||
+ | echo "Se ha recuperado $fila[0]<br/>"; | ||
+ | } | ||
+ | $filas->closeCursor(); | ||
+ | $conexon=null; | ||
+ | //Ahora hacemos la consulta parametrizadas usando un objeto de la clase PDOStatement | ||
+ | //Hacemos el prepare | ||
+ | $sentencia= "Select producto from stock where tienda = :nom"; | ||
+ | |||
+ | $consulta = $conexion->prepare($sentencia); | ||
+ | $tienda =3; | ||
+ | |||
+ | //$consulta->bindParam(':nom',$tienda,PDO::PARAM_INT); | ||
+ | //$consulta->execute(); | ||
+ | //Podemos usar la opción de antes o esta otra | ||
+ | $consulta->execute(array(":nom"=>$tienda)); | ||
+ | //Ahora mostramos los resultados | ||
+ | while ($fila=$consulta->fetch()){ | ||
+ | echo "Visualizo el producto $fila[0]<br/>"; | ||
+ | |||
+ | } | ||
+ | ?> | ||
+ | </body> | ||
+ | </html> | ||
+ | |||
+ | </source> | ||
+ | |||
+ | }} | ||
+ | |||
+ | ===Control de excepticones=== | ||
+ | *A partir de la versión 5 se introdujo en PHP un modelo de excepciones similar al existente en otros lenguajes de programación: | ||
+ | #El código susceptible de producir algún error se introduce en un bloque '''''try - catch'''''. | ||
+ | <source lang=php> | ||
+ | try{ | ||
+ | |||
+ | //Instrucciones que pueden lanzar una excepción y | ||
+ | //puedo capturar en tiempo de ejecuciónj | ||
+ | |||
+ | }cathc(Exception $e){ | ||
+ | echo "Se ha producido una excepcion". $e->getMessage(); | ||
+ | } | ||
+ | </source> | ||
+ | #Cuando se produce algún error, se lanza una excepción utilizando la instrucción '''''throw'''''. | ||
+ | #Después del bloque try debe haber como mínimo un bloque catch encargado de procesar el error. | ||
+ | #Si una vez acabado el bloque try no se ha lanzado ninguna excepción, se continúa con la ejecución en la línea siguiente al bloque o bloques catch. | ||
+ | {{Actividad| | ||
+ | Haz un programa que si dividimos por cero pase una exepcion | ||
+ | |||
+ | <source lang=php> | ||
+ | try { | ||
+ | if ($divisor == 0) | ||
+ | throw new Exception("División por cero."); | ||
+ | $resultado = $dividendo / $divisor; | ||
+ | } | ||
+ | catch (Exception $e) { | ||
+ | echo "Se ha producido el siguiente error: ".$e->getMessage(); | ||
+ | } | ||
+ | </source> | ||
+ | }} | ||
+ | *PHP ofrece una clase base Exception para utilizar como manejador de excepciones. | ||
+ | *Esta clase implementa dos métodos generales que nos muestran información sobre la excepticon que se ha podido producir | ||
+ | *'''''getMessage'''''. Devuelve el mensaje, en caso de que se haya puesto alguno. | ||
+ | *'''''getCode'''''. Devuelve el código de error si existe. | ||
+ | *El caso de PDO define su propia clase de excepciones que deriva o hereada de la clase Exception | ||
+ | *Para el caso concreto de PDO, hay que configurar para que lance las excepciones, puediento esta configuración tomar los siguientes valores: | ||
+ | #PDO::ERRMODE_SILENT. No se hace nada cuando ocurre un error. Es el comportamiento por defecto. | ||
+ | #PDO::ERRMODE_WARNING. Genera un error de tipo E_WARNING cuando se produce un error. | ||
+ | #PDO::ERRMODE_EXCEPTION. Cuando se produce un error lanza una excepción utilizando el manejador propio PDOException. | ||
+ | |||
+ | *Vamos a ver como se utiliza: | ||
+ | *Primero activamos las excepciones, y luego ya se pueden utilizar | ||
+ | <source lang=php> | ||
+ | $dwes = new PDO("mysql:host=localhost; dbname=dwes", "dwes", "abc123."); | ||
+ | $dwes->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
+ | try { | ||
+ | $sql = "SELECT * FROM stox"; | ||
+ | $result = $dwes->query($sql); | ||
+ | //… | ||
+ | } | ||
+ | catch (PDOException $p) { | ||
+ | echo "Error ".$p->getMessage()."<br />"; | ||
+ | } | ||
+ | </source> | ||
+ | *En este caso que no existe la tabla nos diría | ||
+ | <source lang=php> | ||
+ | Error SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dwes.stox' doesn't exist | ||
+ | </source> | ||
+ | *En el caso de mysqli usaríamos la clase mysqli_sql_exception que gestiona el tema de las excepciones | ||
+ | http://es.php.net/manual/es/class.mysqli-sql-exception.php | ||
+ | {{Actividad| | ||
+ | *Realicemos un fichero de conexión a base de datos que contenga las siguientes funciones | ||
+ | #'''''conectar'''''($bd, $usuario,$password) Retornará un objeto de la clase PDO si todo ok | ||
+ | #'''''consulta($sentencia,$parametros)''''' Retorna un objeto de la clase PDOStatement si todo ok, | ||
+ | ##Recibe dos argumentos, un string que será la consulta parametrizada, y un array con los valores para cada parámetro | ||
+ | #'''''Insertar($tabla,$valores)''''' | ||
+ | ##Recibe un string que es el nombre de tabla y un vector que serán los diferentes valores para cada campo de la tabla | ||
+ | ##Suponemos que se pasan los valores ok, si no, capturamos la excepción | ||
+ | }} | ||
+ | |||
+ | ===Filtros=== | ||
+ | *Qué es | ||
+ | *Para qué sirve | ||
+ | *Dónde aplicarlo | ||
+ | http://php.net/manual/es/ref.filter.php | ||
+ | *Concepto de escapar las comillas simples y dobles | ||
+ | *Ecapar las barras invertidas | ||
+ | http://php.net/manual/es/function.addslashes.php | ||
+ | |||
+ | |||
+ | |||
+ | ===Transacciones=== | ||
|} | |} |
Última revisión de 22:44 28 nov 2014
Trabajo en proceso, espera cambios frecuentes. Tu ayuda y retroalimentación son bienvenidos. Ver página de charlas. |
|