Diferencia entre revisiones de «Usuario:ManuelRomero/php/BasesDatos»

De WikiEducator
Saltar a: navegación, buscar
(FUNCIONES)
 
(58 revisiones intermedias por el mismo usuario no mostrado)
Línea 2: Línea 2:
  
  
{{:Usuario:ManuelRomero/php/nav}}
 
  
 
<!--__NOEDITSECTION__-->
 
<!--__NOEDITSECTION__-->
Línea 19: Línea 18:
 
===Introducción===
 
===Introducción===
 
*Idea de independizar la base de datos y el lenguaje de programación: concepto de driver, conector y extensión (mysql, mysqli, PDO).
 
*Idea de independizar la base de datos y el lenguaje de programación: concepto de driver, conector y extensión (mysql, mysqli, PDO).
 +
http://php.net/manual/es/mysqli.overview.php
 
*Para trabajar con bases de datos debemos
 
*Para trabajar con bases de datos debemos
**Conectarnos  
+
**Conectarnos (Para ello necesitamos un software específico del gestor de bases de datos con el que vayamos a trabajar).
**Seleccionar  
+
**Seleccionar (La base de datos con la que vamos a trabajr).
 
*Normalmente también
 
*Normalmente también
**Realizaremos  Consulta o inserciones
+
**Actuar con la base de datos (Consultas, inserciones, modificaciones y/o borrados)
 
**Procesar información
 
**Procesar información
 
**Cerrar la base de datos
 
**Cerrar la base de datos
*PHP tiene un API especifico para trabajar directamente con mysql '''''mysqli'''''
 
 
*Para realizar estas acciones disponemos de diversas funciones específicas dentro de PHP,
 
*Para realizar estas acciones disponemos de diversas funciones específicas dentro de PHP,
 +
*PHP tiene un API especifico para trabajar directamente con mysql '''''mysqli''''', el cual incorpora el driver y conector necesario para trabajar con ella de forma nativa
 +
*Que el driver sea nativo es que está implementado utlizando un  framework de extensiones dde php.
 
*También vamos a disponer de la extensión PDO, la cual se independiza del gestor concreto de bases datos que vayamos a utilizar.
 
*También vamos a disponer de la extensión PDO, la cual se independiza del gestor concreto de bases datos que vayamos a utilizar.
*Por lo tanto en este tema vamos a ver dos extensiones
+
*Por lo tanto en este tema vamos a ver dos extensiones:
#usar una extensión nativa con su GBD en concreto mysql que viene con el propio lenguaje
+
#'''''mysqli''''' usar una extensión nativa con su SGBD en concreto mysql que viene con el propio lenguaje
#usar una extensión genéricoa que permite conectarse con cualquier gestor de BD.
+
#'''''PDO''''' usar una extensión genéricoa que permite conectarse con cualquier gestor de BD, sin necesidad de cambiar nada de código.
 
===Introduccion Usao de extensiones orientadas a objetos===
 
===Introduccion Usao de extensiones orientadas a objetos===
 
*Para trabajar con las extensiones, las usaremos siempre orientadas a objetos, aunque tengan  
 
*Para trabajar con las extensiones, las usaremos siempre orientadas a objetos, aunque tengan  
Línea 51: Línea 52:
  
 
<div class="slide">
 
<div class="slide">
===Mysql y su extensión mysqli para php===
+
=====Mysql y php=====
 
*Instalar mysql lo hicimos en el primer tema
 
*Instalar mysql lo hicimos en el primer tema
 
  apt-get install mysql-server mysql-client
 
  apt-get install mysql-server mysql-client
 
*Para parar/arrancar el servicio
 
*Para parar/arrancar el servicio
 
  service mysql start/stop/restart/status
 
  service mysql start/stop/restart/status
*El fichero de configuracion
+
*El fichero de configuración
 
  /etc/mysql/my.cnf
 
  /etc/mysql/my.cnf
 
*En él podemos ver el puerto (3306 por defecto), el usuario y otros parámetros del servicio
 
*En él podemos ver el puerto (3306 por defecto), el usuario y otros parámetros del servicio
Línea 71: Línea 72:
 
#sal de sql <!-- quit-->
 
#sal de sql <!-- quit-->
 
}}
 
}}
 +
[[archivo:baseDatos.pdf]]
 +
{{Actividad|
 +
Usa mysql para cargar por líneas de comandos el siguiente fichero arriba especificado
 +
}}
 +
*En la siguiente página puedes hacer un repaso de mysql
 +
http://dev.mysql.com/doc/refman/5.7/en/index.html
 +
*Un manual en castellano
 +
http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/
 +
*Debemos conocer también la herramienta phpmyadmin
 +
sudo apt-get install phpmyadmin
 +
*Aquí tienes una pequeña guía es de uso sencillo e intuitivo
 +
http://www.ite.educacion.es/formacion/materiales/85/cd/linux/m5/instalacin_y_configuracin_de_phpmyadmin.html
 +
*Y más información en la página oficial
 +
http://www.phpmyadmin.net/home_page/index.php
 +
{{Actividad|
 +
Probamos a conectarno por phpmyadmin a nuestro servidor local
 +
}}
 +
[[Archivo:datos.sql]]
 +
{{Actividad|
 +
Usando phpmyadmin, carga los datos para poblar la base de datos}}
 +
*Otra herramienta importante que permite realizar diseños es workbrench
 +
http://dev.mysql.com/doc/workbench/en/index.html
 +
<source lang=bash>
 +
    sudo add-apt-repository ppa:olivier-berten/misc
 +
    sudo apt-get update
 +
    sudo apt-get install  mysql-workbench
 +
</source>
 +
{{Actividad|
 +
Instalamos y probamos las diferentes opciones con esta herramienta
 +
Probamos a hacer un diseño en modelo realcional y a partir del modelo creamos las tablas.
 +
*Probamos las opciones '''''forward engineer''''' y '''''reverser engineer'''''
 +
}}
 +
===Herramientas de administración===
 +
*Con '''''phpmyadmin''''', podemos hacer casi todo de administrar y manejar las bases de datos
  
===CONECTAR AL SERVIDOR MYSQL con mysqli===
+
*No obstante mysql proporciona una serie de herraminetas que perminten administrar por línea de comandos .
 +
*En muchas ocasiones este tipo de operaciones resultan muy interesantes.
 +
#mysql
 +
#myhsqladmin
 +
#mysqlshow
 +
:mysql
 +
*Esta heramienta ya la hemos comentado, permite conectarse a un servidor MySQL para ejecutar sentencias SQL
 +
*Opciomes básicas ya conocidas
 +
#connect -h,-u, -p
 +
# use database
 +
# exit o quit
 +
# help Para conocer los comandos que se pueden usar.
 +
      http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/sql-syntax.html
 +
:mysqladmin
 +
*Es un cliente específico para la administración
 +
*Entre otras acciones podemos realizar
 +
 
 +
#crear y eliminar bases de datos.
 +
#mostrar la configuración y el estado del servidor.
 +
#cambiar contraseñas.
 +
#detener un servidor.
 +
#ver la version del servidor
 +
      http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/mysqladmin.html
 +
{{Actividad|
 +
Prueba a hacer cada una de las acciones especificadas anteriormente
 +
<!-- crear bases de datos  mysqladmin -u root -proot create nombreBaseDatos
 +
mysqladmin -u root -proot extend-status
 +
mysqladmin -u root -proot password
 +
mysqladmin -u root -proot shutdown
 +
mysqladmin -u root -proot version
 +
-->
 +
}}
 +
:mysqlshow
 +
http://ftp.nchu.edu.tw/MySQL//doc/refman/5.0/es/mysqlshow.html
 +
*muestra informaicón sobre la base de datos
 +
mysqlshow -u root -proot
 +
*Nos mostraría las tablas de ese ususario
 +
 
 +
===Mysql y su extensión mysqli para php===
 +
: CONECTARNOS A LA BASE DE DATOS
 +
*A continuación iremos viendo como implementar las acciones básicas en el lenguaje
 +
:Conectarse
 +
*Para conectarse a una base de datos , creamos una instacia de la clase mysqli de la forma
 +
<source lang=php>
 +
$miConexion = new mysqli(....);
 +
</source>
 +
 
 +
*El constructor de la clase puede recibir hasta 5 parámetros, de los cuales 4 se suelen usar con bastante frecuencia
 +
#$host nombre o ip del equipo (null o localhost, identificaría el equipo actual).i
 +
#'''''$usario''''' es el usuario de la base de datos
 +
#'''''$pass'''''
 +
#'''''$nombreBD'''''
 +
#'''''$puerto'''''
 +
#'''''$shocket'''''
 +
<source lang=php>
 +
$host="localhost"
 +
$usuario="manolo";
 +
$pass="romero";
 +
$nombreBD="alumnos";
 +
 
 +
$miConexion = new mysqli ($host,$usuario,$pass,$nombreBD);
 +
if ($miConexion==null)
 +
    echo"Error conectando a la base de datos";
 +
else
 +
    echo "Conectado a la base de datos";
 +
</source>
  
resource mysql_connect($hostname, $user, $password);
 
*Los parámetros de tipo string identificarían
 
**$hostname = nombre del host
 
**$user =  usuario
 
**$password = contraseña
 
 
*Esta función retorna el recurso de la conexión
 
*Esta función retorna el recurso de la conexión
**FALSO si no se ha conectado
+
*Para gestionar los errores deberíamos usar el atributo '''''connect_error''''' de la clase '''''mysqli'''''
</div>
+
*Este atributo aporta información sobre el error o contiene null si no se ha producido ninguno.
 +
*En el código anterior
 +
<source lang=php>
 +
if ($miConexion->connect_error)
 +
  echo "Error conectando con la base de datos: ".$miConexion->connect_error;
 +
</source>
 +
*Para ver información sobre la conexión se puede usar los atributos *server_info o host_info
 +
{{Resumen|
 +
<source lang=php>
 +
$conesion= new mysqli($host,$user,$pass,$bd);
 +
mysqli->conect_error
 +
mysqli->conect_errno
 +
mysqli->server_info
 +
mysqli->host_info
 +
</source>
 +
}}
 +
*Hay muchas opciones de mysqli que se pueden configurar en el fichero php.ini
 +
*Aquí tenemos alguna de ellas
 +
;mysqli.allow_persistent
 +
:Permite crear conexiones persistentes.
 +
;mysqli.default_port
 +
:Número de puerto TCP predeterminado a utilizar cuando se conecta al Servidor de base de datos.
 +
;mysqli.reconnect
 +
:Indica si se debe volver a conectar automáticamente en caso de que se pierda la conexión.
 +
;mysqli.default_host.
 +
:Host predeterminado a usar cuando se conecta al servidor de base de datos.
 +
;mysqli.default_user.
 +
;Nombre de usuario predeterminado a usar cuando se conecta al servidor de base de datos.
 +
:mysqli.default_pw
 +
;Contraseña predeterminada a usar cuando se conecta al servidor de base de datos.
  
 +
*La lista completa la podemos ver en el siguiente link
 +
http://php.net/manual/es/mysqli.configuration.php
 +
{{Actividad|
 +
*configura dicho fichero, para poder conectar a la base de datos sin aportar parámetros al constructor
 +
*Luego déjalo como estaba :)}}
  
<div class="slide">
 
===SELECCIONAR LA BASE DE DATOS===
 
Dentro del servidor tendremos diferentes bases de datos
 
Antes de trabajar con una debemos seleccionarla
 
Si no la seleccionamos se intentará operar con la última seleccionada
 
bool mysql_select_db ($namedatabase, $conexion)
 
*Ejemplo
 
<?php
 
$conexion = mysql_connect('localhost', 'manolo', 'manolo');
 
if (!$conexion) {
 
    die('No conectado : ' . mysql_error());
 
}
 
// Seleccionar alumnos como base de datos activa
 
$db_seleccionada = mysql_select_db('alumnos', $conexion);
 
if (!$db_seleccionada) {
 
    die ('No puedo conectar con la BD alumno : ' . mysql_error());
 
}
 
?>
 
</div>
 
  
<div class="slide">
 
===FUNCIONES die()- mysql_error() y concatenador .===
 
die('texto');
 
Es una función que aborta la ejecución
 
previamente visualiza el mensaje del parámetro por pantalla
 
mysql_error()
 
visualiza el error que da el sistema por el que no ha podido conectar
 
.
 
Es un concatenador de cadenas
 
echo "Esto es una cadena " . "Esta es otra concatenada a la anterior"
 
 
</div>
 
</div>
 +
<div class="slide">
  
 +
===Cambiar la base de datos===
 +
*Si hemos seleccionado una base de datos, o no hemos seleccionado ninguna y queremos cambiar a otra
 +
<source lang=php>
 +
$miConexion->select_db("nombre_base_datos");
 +
</source>
 +
*Cuando ya no vamos a usar un recurso, conviente y repito CONVIENE, liberarlo.
 +
<source lang=php>
 +
$miConexion->close();
 +
</source>
 +
===DML===
 +
*En SQL sabemos que tenmos tres tipos de lenguajes DDL, DML, DCL
 +
*Ahora toca DML, Leguane de maninputación de datos
 +
*Podemos clasificar en dos tipos de clúsulas:
 +
#las que no devuelven registros de datos (INSERT, DELETE, UPDATE)
 +
##Generalmente retornan un entero que es el número de filas aceptadas o un booleano que indica si se realizó no la operación
 +
#Las que pueden retornan  una colección de filas (SELECT), generalmente conocidas como cursor.
 +
*En mysqli podemos enviar cualquiera de estas claúsulas con el método '''''query'''''
 +
===INSERT, UPDATE Y DELETE===
 +
*Este tipo de sentencias retornan un booleano que indica si se ha realizado o no la acción
 +
*El número de filas afectadas lo podemos ver en el atributo '''''affected_rows'''''
 +
{{Resumen|
 +
<source lang=php>
 +
$reusultado=miConexion->query($consulta)
 +
if($resultado){
 +
  echo"Se han afectado $miConexion->affected_rows filas en esta acción");
 +
}
 +
</source>
 +
}}
 +
<source lang=php>
 +
$sentenciaDelete="DELETE FROM tabla WHERE condicion";
 +
$sentenciaInsert="INSERT INTO tabla (opcional lista de campos) VALUES (valores en posiciones respectivas a los campos);
 +
$sentenciaUpdate="UPDATE tabla WHERE condicion";
  
<div class="slide">
 
===CREAR CONSULTA===
 
resource mysql_query ( string $consulta );
 
consulta es la consulta a la base de datos
 
<?php
 
$resultado = mysql_query('SELECT * from alumnos');
 
if (!$resultado) {
 
    die('Invalid query: ' . mysql_error());
 
}
 
?>
 
</div>
 
  
 +
$miConexion->query($sentenciasDelete);
 +
$resultado =$miConexion->query($sentenciaDELETE);
 +
if ($resultado){
 +
    echo "Se han borrado $miConexion->affected_rows filas ";
 +
}
  
<div class="slide">
+
$miConexion->query($sentenciasUpdate);
===PROCESAR INFORMACIÓN===
+
$resultado = $miConexion->query($sentenciaUPDATE);
Ahora ya tenemos los datos con los que queremos trabajar
+
if ($resultado){
los tenemos en una variable de tipo consulta
+
    echo "Se han actualizado $miConexion->affected_rows filas ";
ahora debemos recorrela
+
}
La variable es como un vector de filas que hay que recorrer
+
array mysql_fetch_row ( resource $resultado )
+
esta función devuelve falso o 0 cuando ya no retorna más filas
+
si no retorna la siguiente fila de la consulta
+
la forma de acceder a cada campo será por el índice del array
+
array[0] .. array[n]
+
  
<?php
+
$miConexion->query($sentenciasInsert);
$resultado = mysql_query("SELECT nombre, apellido, direccion FROMM alumnos");
+
$resultado = $miConexion->query($sentenciaINSERT);
if (!$resultado) {
+
if ($resultado){
    die("Could not run query: " . mysql_error();
+
    echo "Se han insertado $miConexion->affected_rows filas ";
}
+
}
$c=0;
+
while ($alumno=mysql_fetch_row($result)){
+
      echo "alumno $c nombre $alumno[0] apellido $alumno[1] direccion $alumno[3]");
+
      $c++;
+
?>
+
</div>
+
  
<div class="slide">
+
</source>
  
===GESTIÓN DE BASE DE DATOS===
+
*Observemos su uso en el ejemplo
Conocer todas las bases de datos
+
mysql_connect('localhost', 'mysql_user', 'mysql_password');
+
Todas las tablas de una base de datos
+
resource mysql_list_tables ( string $database [, resource $link_identifier ])
+
</div>
+
Los campos de una tabla
+
resource mysql_list_fields ( string $database_name , string $table_name [, resource $link_identifier])
+
</div>
+
<div class="slide">
+
  
<!--
+
<source lang=php>
=FUNCIONES=
+
 +
  //Establecemos la conexión
 +
  $miConexion = new mysqli('localhost', 'manolo', '12345.', 'baseDatosPrueba');
 +
 
 +
  //Capturamos un posible error
 +
  $error = $miConexion->connect_errno;
 +
 +
  //En caso de error informamos de ello
 +
  if ($error == null) {
 +
    $resultado = $miConexion->query('DELETE FROM stock WHERE unidades=0');
 +
 +
    if ($resultado) {
 +
      print "<p>Se han borrado $miConexion->affected_rows registros.</p>";
 +
    }
 +
  }
 +
  $miConexion->close();
 +
}
 +
</source>
 
</div>
 
</div>
 +
 
<div class="slide">
 
<div class="slide">
-->
 
  
 +
===Clausula SELECT con query===
 +
*Tenemos dos maneras de realizar consultas con mysqli
 +
#query
 +
#real_query
 +
*En el primero caso el método nos retorna un cursor que será de la calse mysqli_result
 +
*En el segundo caso nos retornará un booleano y para leer los datos deberemos usar o '''''store_result''''' o '''''use_result''''' según veamos a continuación.
 +
===Método query===
 +
*Una vez que tenemos los datos almacenados debemos saber acceder.
 +
*Tenemos 4 formas de poder acceder a los datos según usemos un método u otro
 +
;fetch_array()
 +
:Va obteniendo cada registro como un array
 +
:Este array podemos usar tanto de forma indexada, como asociativa (con el nombre del campo)
 +
;fetch_assoc()
 +
:En este caso el array que retorna es asociativo
 +
;fetch_row()
 +
:En este caso el array que retorna es indexado
 +
;fetch_object()
 +
:En este caso en lugar de retornar un array, retorna un objeto, donde cada campo son los diferentes atributos de ese objeto
 +
*En todos los casos cada vez que leemos un elemento de mysqli_result, lo que por comparativa sería un cursor, vamos avanzando al siguiente. Cuando hayamos leído todos retornaría null
 +
{{Actividad|
 +
Obtén todos los registros de la tabla familia  y visualizalos en una tabla usando los tres modos de lectura de datos vistos anteriormente}}
 +
*Para liberar un recurso del tipo mysqli_result, usamos el método free();
 +
*La clase mysqli_result, además de los métodos vistos tiene un par de atributos interesantes
 +
;int $field_count;
 +
:Nos dice cuantas columnos tiene el query actual
 +
;int $num_rows;
 +
:Nos dice cuantas filas hemos obtenido con la consulta
 +
*Tenemos una lista completa
 +
http://es.php.net/manual/es/class.mysqli-result.php
 +
{{Resumen|
 +
<source lang=php>
 +
$conexion= new mysqli($host,$user,$pass,$bd);
 +
if ($conexion->connect_errno==null){
 +
  $resultado = $conexion->query($consulta);
 +
  $numFilas = $resultado->num_rows;
 +
  $numCampos = $resultado->fields_count;
 +
  echo "La consulta ha retornado $numFilas filas con  $numCampos columnas";
 +
  $fila = $resultado->fetch_array();
 +
  while ( $fila){
 +
          echo"El valor del primer campo es $fila[0]";
 +
          $fila = $resultado->fetch_array();
 +
  }
 +
  $resultado->free();
 +
  $conexion->close();
 +
}
 +
</source>
 +
}}
 +
 +
 +
{{Actividad|
 +
Haciendo una consulta del tipo select * from producto whre pvp < 200, realiza un código que visualizce en una tabla los resultados }}
 +
===Transacciones===
 +
<br/>
 +
{{Definicion|
 +
Una transacción es un conjunto de acciones u operaciones que se realizan contra una base de datos de modo que o bien se realizan correctamente todas o no se realiza ninguna}}
 +
*Supongamos que hacemos una transferencia bancaria; cuando menos implica descontar dinera de una cuenta e ingresaro en otra
 +
*Ahora supongamos que nada mas descontar el dinero de una cuenta se cae la luz y se apaga el servidor
 +
*Esto creará una inconsistencia en la base de datos
 +
*Por defecto en mysqli cada acción con la base de datos es una transacción en sí misma, pero esto se puede modificar
 +
<source lang=php>
 +
$conexion = new mysqli(..);
 +
$conexion->autocomit(false);
 +
.....
 +
</source>
 +
*Si se ha desactivado el autocomit, para terminar una transacción debemos usar los métodos '''''commit''''' o '''''rollback'''''
 +
<source lang=php>
 +
$conexion = new mysqli(..);
 +
$conexion->autocomit(false);
 +
.....
 +
 +
if (CondicionOK){
 +
    //Terminamos la transacción confirmando todas las acciones sobre la base de datos desde que se inició la   
 +
      transaccion
 +
    $conexion->commit();
 +
}else{
 +
    //Terminamos la transacción desaciendo  todas las acciones sobre la base de datos desde que se inició la   
 +
      transaccion, y dejando la base de datos igual que estaba al principio
 +
  $conexion->rollback();
 +
  }
 +
</source>
 +
{{Actividad|
 +
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===
 +
*Una consulta preparada consiste en establecer una consulta como si fuera una variable y ejecutarla posteriormente tantas veces como sea necesario.
 +
*Estas consultas se almacenan en el servidor  y están listas para ser ejecutadas cuando sea necesario. El servidor solo tiene que analizarlas una vez
 +
*Para trabajar con consultas preparadas, debemos usar  la clase '''''mysqli_stmt''''', e inicializarla con  el método '''''stmt_init '''''
 +
<source lang=php>
 +
  $conexion = new mysqli('localhost', 'dwes', 'abc123.', 'dwes');
 +
  //Preparo el objeto $consulta para crear consultas preparadas en él
 +
  $consulta = $conexion->stmt_init();
 +
</source>
 +
Los pasos para trabajar con consultas preparadas son:
 +
#Preparar la consulta en el servidor MySQL utilizando el método '''''prepare'''''.
 +
#Ejecutar la consulta, tantas veces como sea necesario, con el método '''''execute'''''.
 +
#Una vez que ya no se necesita más, se debe ejecutar el método '''''close'''''.
 +
<source lang=php>
 +
$consulta = $conexion->stmt_init();
 +
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES ("TABLET", "Tablet PC")');
 +
$consulta->execute();
 +
$consulta->close();
 +
$conexion->close();
 +
</source>
 +
 +
===Parametrizar las consultas preparadas===
 +
*El uso real de las consultas preparadas es que los valores que pasas se asignen antes de ejectuar la consulta.
 +
*La idea es preapara la consulta sin indicar los valores.
 +
*Asignar los valores y ejectuar la consulta cuantas veces sea necesario.
 +
*Veamos el proceso
 +
;Parametrizar la consulta
 +
*Consiste en indicar en la consulta preparada en lugar de los valores, signos de interrogación '''''?'''''
 +
*En el caso anterior
 +
<source lang=php>
 +
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?,?);
 +
</php>
 +
*Ahora habría que asigar los valores. Para ello usamos el método '''''bind_param''''
 +
<bind_param(tipoDatos, >
 +
*Este método recibe dos tipos de parámetros
 +
#El primero es una cadena de caracteres, donde cada carácter especifica el tipo de valor que va a recibir cada uno de los valores esperados en la consulta.
 +
**La codificación sería :
 +
#s: cadena de caracteres
 +
#i: número entero
 +
#d: número float
 +
#b: valor binario (BLOB)
 +
*En nuestro caso como va a recibir en los dos parámetros cada uno una cadena de caracteres sería '''''"ss"'''''
 +
#El segundo grupo sería cada uno de los valores.SIEMPRE hay que especificar variables
 +
*En el ejemplo que estamos siguiendo
 +
<source lang=php>
 +
$consulta = $conexion->stmt_init();
 +
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)');
 +
$cod_producto = "TABLET";
 +
$nombre_producto = "Tablet PC";
 +
$consulta->bind_param('ss', $cod_producto, $nombre_producto);
 +
</source>
 +
*Insistimos en que siempre hay que especificar variables, de modo que
 +
<source lang=php>
 +
$consulta->bind_param('ss', 'TABLET', 'Tablet PC');  // Genera un error
 +
</source>
 +
{{Resumen|
 +
<source lang=php>
 +
$conexion = new mysqli(...);
 +
$consulta = $conexion->stmt_init();
 +
$consulta->prepare(...sentencia ... con ???)
 +
$consulta->bind_param('s-i-b-d(tipo_de_valores)',valores_en_variables_respectivos_a_????');
 +
$consulta->execute();
 +
$consulta->close();
 +
$conexion->close();
 +
</source>
 +
}}
 +
 +
===Consultas preparadas que retornan valores===
 +
*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
 +
*Para recorre el conjunto de valores, usamos el método fectch(), como se ve en el ejemplo
 +
<source lang=php>
 +
$consulta = $conexion->stmt_init();
 +
$consulta->prepare('SELECT producto, unidades FROM stock WHERE unidades<2');
 +
$consulta->execute();
 +
$consulta->bind_result($producto, $unidades);
 +
while($consulta->fetch()) {
 +
print "<p>Producto $producto: $unidades unidades.</p>";
 +
}
 +
$consulta->close();
 +
$conexion->close();
 +
</source>
 +
*Aquí hay un enlace para una información completa sobre consultas preparadas
 +
http://php.net/manual/es/class.mysqli-stmt.php
 +
{{Actividad|
 +
*Modifica el ejercicio anterior usando consultas parametrizadas
 +
}}
 +
 +
{{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).
 +
}}
 +
<!--
 
===Definición de funiones=
 
===Definición de funiones=
 
  function  ‘’’nombre_de_funcion’’’ (’’’’lista_de_parametros’’’’){
 
  function  ‘’’nombre_de_funcion’’’ (’’’’lista_de_parametros’’’’){
Línea 179: Línea 530:
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
===Ejemplo de funcion===
+
===Ejemplo de funcion===
 
*Realiza una función que convierta de mayúsculas a minúsculas
 
*Realiza una función que convierta de mayúsculas a minúsculas
 
  </div>
 
  </div>
 
<div class="slide">
 
<div class="slide">
 +
 +
 +
 
===Generar pdf desde el código php===
 
===Generar pdf desde el código php===
 
pdf=new mPDF();
 
pdf=new mPDF();
Línea 189: Línea 543:
 
</div>
 
</div>
 
-->
 
-->
 +
 +
==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

Road Works.svg Trabajo en proceso, espera cambios frecuentes. Tu ayuda y retroalimentación son bienvenidos.
Ver página de charlas.
Road Works.svg




DWES TituloTema3.gif

BASES DE DATOS

Introducción

  • Idea de independizar la base de datos y el lenguaje de programación: concepto de driver, conector y extensión (mysql, mysqli, PDO).
http://php.net/manual/es/mysqli.overview.php
  • Para trabajar con bases de datos debemos
    • Conectarnos (Para ello necesitamos un software específico del gestor de bases de datos con el que vayamos a trabajar).
    • Seleccionar (La base de datos con la que vamos a trabajr).
  • Normalmente también
    • Actuar con la base de datos (Consultas, inserciones, modificaciones y/o borrados)
    • Procesar información
    • Cerrar la base de datos
  • Para realizar estas acciones disponemos de diversas funciones específicas dentro de PHP,
  • PHP tiene un API especifico para trabajar directamente con mysql mysqli, el cual incorpora el driver y conector necesario para trabajar con ella de forma nativa
  • Que el driver sea nativo es que está implementado utlizando un framework de extensiones dde php.
  • También vamos a disponer de la extensión PDO, la cual se independiza del gestor concreto de bases datos que vayamos a utilizar.
  • Por lo tanto en este tema vamos a ver dos extensiones:
  1. mysqli usar una extensión nativa con su SGBD en concreto mysql que viene con el propio lenguaje
  2. PDO usar una extensión genéricoa que permite conectarse con cualquier gestor de BD, sin necesidad de cambiar nada de código.

Introduccion Usao de extensiones orientadas a objetos

  • Para trabajar con las extensiones, las usaremos siempre orientadas a objetos, aunque tengan

la correspondiente funcionalidad en el lenguaje estructurado.

  • Para recordar muy brevemene posemos usar el siguiente enlace
http://www.desarrolloweb.com/articulos/1540.php
  • Posteriormente veremos un tema de php orientado a objetos
  • Recordamos que para crear una nueva instancia de una clase usamos el operador new
    $miObjeto = new Clase();
  • Para acceder a los diferentes métodos del objeto instaciado
 $miObjeto->metodo($parametros);
  • Con estos detalles nos sobra de momento para este tema.


Mysql y php
  • Instalar mysql lo hicimos en el primer tema
apt-get install mysql-server mysql-client
  • Para parar/arrancar el servicio
service mysql start/stop/restart/status
  • El fichero de configuración
/etc/mysql/my.cnf
  • En él podemos ver el puerto (3306 por defecto), el usuario y otros parámetros del servicio
  • Podemos accecder a la documentación que php da sobre mysqli (mysql improve), o sea interfaz mysql mejorada http://php.net/manual/es/class.mysqli.php
  • Debmos saber conectarnos por línea de comandos


Icon activity.jpg

Actividad

  1. Conectar a mysql
  2. Mira Las bases de datos que tienes
  3. usa una base de datos concreta
  4. mira las tablas que tiene esa bases de datos
  5. mira la estructura de la tabla
  6. Haz una consulta de los valores que tiene su primera columna
  7. ejecuta el comando help
  8. sal de sql




Archivo:BaseDatos.pdf


Icon activity.jpg

Actividad

Usa mysql para cargar por líneas de comandos el siguiente fichero arriba especificado




  • En la siguiente página puedes hacer un repaso de mysql
http://dev.mysql.com/doc/refman/5.7/en/index.html
  • Un manual en castellano
http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/
  • Debemos conocer también la herramienta phpmyadmin
sudo apt-get install phpmyadmin
  • Aquí tienes una pequeña guía es de uso sencillo e intuitivo
http://www.ite.educacion.es/formacion/materiales/85/cd/linux/m5/instalacin_y_configuracin_de_phpmyadmin.html
  • Y más información en la página oficial
http://www.phpmyadmin.net/home_page/index.php


Icon activity.jpg

Actividad

Probamos a conectarno por phpmyadmin a nuestro servidor local




Archivo:Datos.sql


Icon activity.jpg

Actividad

Usando phpmyadmin, carga los datos para poblar la base de datos



  • Otra herramienta importante que permite realizar diseños es workbrench
http://dev.mysql.com/doc/workbench/en/index.html
    sudo add-apt-repository ppa:olivier-berten/misc 
    sudo apt-get update 
    sudo apt-get install  mysql-workbench


Icon activity.jpg

Actividad

Instalamos y probamos las diferentes opciones con esta herramienta Probamos a hacer un diseño en modelo realcional y a partir del modelo creamos las tablas.

  • Probamos las opciones forward engineer y reverser engineer




Herramientas de administración

  • Con phpmyadmin, podemos hacer casi todo de administrar y manejar las bases de datos
  • No obstante mysql proporciona una serie de herraminetas que perminten administrar por línea de comandos .
  • En muchas ocasiones este tipo de operaciones resultan muy interesantes.
  1. mysql
  2. myhsqladmin
  3. mysqlshow
mysql
  • Esta heramienta ya la hemos comentado, permite conectarse a un servidor MySQL para ejecutar sentencias SQL
  • Opciomes básicas ya conocidas
  1. connect -h,-u, -p
  2. use database
  3. exit o quit
  4. help Para conocer los comandos que se pueden usar.
     http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/sql-syntax.html
mysqladmin
  • Es un cliente específico para la administración
  • Entre otras acciones podemos realizar
  1. crear y eliminar bases de datos.
  2. mostrar la configuración y el estado del servidor.
  3. cambiar contraseñas.
  4. detener un servidor.
  5. ver la version del servidor
     http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/es/mysqladmin.html


Icon activity.jpg

Actividad

Prueba a hacer cada una de las acciones especificadas anteriormente




mysqlshow
http://ftp.nchu.edu.tw/MySQL//doc/refman/5.0/es/mysqlshow.html
  • muestra informaicón sobre la base de datos
mysqlshow -u root -proot 
  • Nos mostraría las tablas de ese ususario

Mysql y su extensión mysqli para php

CONECTARNOS A LA BASE DE DATOS
  • A continuación iremos viendo como implementar las acciones básicas en el lenguaje
Conectarse
  • Para conectarse a una base de datos , creamos una instacia de la clase mysqli de la forma
 $miConexion = new mysqli(....);
  • El constructor de la clase puede recibir hasta 5 parámetros, de los cuales 4 se suelen usar con bastante frecuencia
  1. $host nombre o ip del equipo (null o localhost, identificaría el equipo actual).i
  2. $usario es el usuario de la base de datos
  3. $pass
  4. $nombreBD
  5. $puerto
  6. $shocket
 $host="localhost"
 $usuario="manolo";
 $pass="romero";
 $nombreBD="alumnos";
 
 $miConexion = new mysqli ($host,$usuario,$pass,$nombreBD);
 if ($miConexion==null)
     echo"Error conectando a la base de datos";
 else
     echo "Conectado a la base de datos";
  • Esta función retorna el recurso de la conexión
  • Para gestionar los errores deberíamos usar el atributo connect_error de la clase mysqli
  • Este atributo aporta información sobre el error o contiene null si no se ha producido ninguno.
  • En el código anterior
 if ($miConexion->connect_error)
   echo "Error conectando con la base de datos: ".$miConexion->connect_error;
  • Para ver información sobre la conexión se puede usar los atributos *server_info o host_info


Icon summary.gif

Resumen

$conesion= new mysqli($host,$user,$pass,$bd);
mysqli->conect_error
mysqli->conect_errno
mysqli->server_info
mysqli->host_info


  • Hay muchas opciones de mysqli que se pueden configurar en el fichero php.ini
  • Aquí tenemos alguna de ellas
mysqli.allow_persistent
Permite crear conexiones persistentes.
mysqli.default_port
Número de puerto TCP predeterminado a utilizar cuando se conecta al Servidor de base de datos.
mysqli.reconnect
Indica si se debe volver a conectar automáticamente en caso de que se pierda la conexión.
mysqli.default_host.
Host predeterminado a usar cuando se conecta al servidor de base de datos.
mysqli.default_user.
Nombre de usuario predeterminado a usar cuando se conecta al servidor de base de datos.
mysqli.default_pw
Contraseña predeterminada a usar cuando se conecta al servidor de base de datos.
  • La lista completa la podemos ver en el siguiente link
http://php.net/manual/es/mysqli.configuration.php


Icon activity.jpg

Actividad

  • configura dicho fichero, para poder conectar a la base de datos sin aportar parámetros al constructor
  • Luego déjalo como estaba :)




Cambiar la base de datos

  • Si hemos seleccionado una base de datos, o no hemos seleccionado ninguna y queremos cambiar a otra
$miConexion->select_db("nombre_base_datos");
  • Cuando ya no vamos a usar un recurso, conviente y repito CONVIENE, liberarlo.
$miConexion->close();

DML

  • En SQL sabemos que tenmos tres tipos de lenguajes DDL, DML, DCL
  • Ahora toca DML, Leguane de maninputación de datos
  • Podemos clasificar en dos tipos de clúsulas:
  1. las que no devuelven registros de datos (INSERT, DELETE, UPDATE)
    1. Generalmente retornan un entero que es el número de filas aceptadas o un booleano que indica si se realizó no la operación
  2. Las que pueden retornan una colección de filas (SELECT), generalmente conocidas como cursor.
  • En mysqli podemos enviar cualquiera de estas claúsulas con el método query

INSERT, UPDATE Y DELETE

  • Este tipo de sentencias retornan un booleano que indica si se ha realizado o no la acción
  • El número de filas afectadas lo podemos ver en el atributo affected_rows


Icon summary.gif

Resumen

$reusultado=miConexion->query($consulta)
if($resultado){
   echo"Se han afectado $miConexion->affected_rows filas en esta acción");
}


$sentenciaDelete="DELETE FROM tabla WHERE condicion";
$sentenciaInsert="INSERT INTO tabla (opcional lista de campos) VALUES (valores en posiciones respectivas a los campos);
$sentenciaUpdate="UPDATE tabla WHERE condicion";
 
 
$miConexion->query($sentenciasDelete);
$resultado =$miConexion->query($sentenciaDELETE);
if ($resultado){
    echo "Se han borrado $miConexion->affected_rows filas ";
}
 
$miConexion->query($sentenciasUpdate);
$resultado = $miConexion->query($sentenciaUPDATE);
if ($resultado){
    echo "Se han actualizado $miConexion->affected_rows filas ";
}
 
$miConexion->query($sentenciasInsert);
$resultado = $miConexion->query($sentenciaINSERT);
if ($resultado){
    echo "Se han insertado $miConexion->affected_rows filas ";
}
  • Observemos su uso en el ejemplo
 
  //Establecemos la conexión
  $miConexion = new mysqli('localhost', 'manolo', '12345.', 'baseDatosPrueba');
 
  //Capturamos un posible error
  $error = $miConexion->connect_errno;
 
  //En caso de error informamos de ello
  if ($error == null) {
    $resultado = $miConexion->query('DELETE FROM stock WHERE unidades=0');
 
    if ($resultado) {
       print "<p>Se han borrado $miConexion->affected_rows registros.</p>";
    }
  }
  $miConexion->close();
}

Clausula SELECT con query

  • Tenemos dos maneras de realizar consultas con mysqli
  1. query
  2. real_query
  • En el primero caso el método nos retorna un cursor que será de la calse mysqli_result
  • En el segundo caso nos retornará un booleano y para leer los datos deberemos usar o store_result o use_result según veamos a continuación.

Método query

  • Una vez que tenemos los datos almacenados debemos saber acceder.
  • Tenemos 4 formas de poder acceder a los datos según usemos un método u otro
fetch_array()
Va obteniendo cada registro como un array
Este array podemos usar tanto de forma indexada, como asociativa (con el nombre del campo)
fetch_assoc()
En este caso el array que retorna es asociativo
fetch_row()
En este caso el array que retorna es indexado
fetch_object()
En este caso en lugar de retornar un array, retorna un objeto, donde cada campo son los diferentes atributos de ese objeto
  • En todos los casos cada vez que leemos un elemento de mysqli_result, lo que por comparativa sería un cursor, vamos avanzando al siguiente. Cuando hayamos leído todos retornaría null


Icon activity.jpg

Actividad

Obtén todos los registros de la tabla familia y visualizalos en una tabla usando los tres modos de lectura de datos vistos anteriormente



  • Para liberar un recurso del tipo mysqli_result, usamos el método free();
  • La clase mysqli_result, además de los métodos vistos tiene un par de atributos interesantes
int $field_count;
Nos dice cuantas columnos tiene el query actual
int $num_rows;
Nos dice cuantas filas hemos obtenido con la consulta
  • Tenemos una lista completa
http://es.php.net/manual/es/class.mysqli-result.php


Icon summary.gif

Resumen

$conexion= new mysqli($host,$user,$pass,$bd);
if ($conexion->connect_errno==null){
   $resultado = $conexion->query($consulta);
   $numFilas = $resultado->num_rows;
   $numCampos = $resultado->fields_count;
   echo "La consulta ha retornado $numFilas filas con  $numCampos columnas";
   $fila = $resultado->fetch_array();
   while ( $fila){
          echo"El valor del primer campo es $fila[0]";
          $fila = $resultado->fetch_array();
   }
   $resultado->free();
   $conexion->close();
}





Icon activity.jpg

Actividad

Haciendo una consulta del tipo select * from producto whre pvp < 200, realiza un código que visualizce en una tabla los resultados



Transacciones



Icon define.gif

Definición

Una transacción es un conjunto de acciones u operaciones que se realizan contra una base de datos de modo que o bien se realizan correctamente todas o no se realiza ninguna


  • Supongamos que hacemos una transferencia bancaria; cuando menos implica descontar dinera de una cuenta e ingresaro en otra
  • Ahora supongamos que nada mas descontar el dinero de una cuenta se cae la luz y se apaga el servidor
  • Esto creará una inconsistencia en la base de datos
  • Por defecto en mysqli cada acción con la base de datos es una transacción en sí misma, pero esto se puede modificar
 $conexion = new mysqli(..);
 $conexion->autocomit(false);
 .....
  • Si se ha desactivado el autocomit, para terminar una transacción debemos usar los métodos commit o rollback
 $conexion = new mysqli(..);
 $conexion->autocomit(false);
 .....
 
 if (CondicionOK){
    //Terminamos la transacción confirmando todas las acciones sobre la base de datos desde que se inició la     
       transaccion
    $conexion->commit();
 }else{
    //Terminamos la transacción desaciendo  todas las acciones sobre la base de datos desde que se inició la     
       transaccion, y dejando la base de datos igual que estaba al principio
  $conexion->rollback();
  }


Icon activity.jpg

Actividad

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



  • A continuación y usando el ejemplo anterior de acceso vamos a probar a realizar un sencillo ataques sql.
  1. Entrar en la plataforma sin tener acceso

Entrar en la plataforma sin tener acceso

  • Entramos en una página y vemos el siguiente acceso

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
 $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"
  • 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
      select * from usuarios where nombre = "maria" or "1"="1"
  • Que nos devolverá todas las filas
  • Así que si introducimos estos datos

MiAccesoInjeccion.png

  • Entramos al sistema sin conocer usuario y contraseña

AccesoInjectado.png

Consultas preparadas

  • Una consulta preparada consiste en establecer una consulta como si fuera una variable y ejecutarla posteriormente tantas veces como sea necesario.
  • Estas consultas se almacenan en el servidor y están listas para ser ejecutadas cuando sea necesario. El servidor solo tiene que analizarlas una vez
  • Para trabajar con consultas preparadas, debemos usar la clase mysqli_stmt, e inicializarla con el método stmt_init
   $conexion = new mysqli('localhost', 'dwes', 'abc123.', 'dwes');
   //Preparo el objeto $consulta para crear consultas preparadas en él
   $consulta = $conexion->stmt_init();

Los pasos para trabajar con consultas preparadas son:

  1. Preparar la consulta en el servidor MySQL utilizando el método prepare.
  2. Ejecutar la consulta, tantas veces como sea necesario, con el método execute.
  3. Una vez que ya no se necesita más, se debe ejecutar el método close.
$consulta = $conexion->stmt_init();
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES ("TABLET", "Tablet PC")');
$consulta->execute();
$consulta->close();
$conexion->close();

Parametrizar las consultas preparadas

  • El uso real de las consultas preparadas es que los valores que pasas se asignen antes de ejectuar la consulta.
  • La idea es preapara la consulta sin indicar los valores.
  • Asignar los valores y ejectuar la consulta cuantas veces sea necesario.
  • Veamos el proceso
Parametrizar la consulta
  • Consiste en indicar en la consulta preparada en lugar de los valores, signos de interrogación ?
  • En el caso anterior
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?,?);
</php>
*Ahora habría que asigar los valores. Para ello usamos el método '''''bind_param''''
<bind_param(tipoDatos, >
*Este método recibe dos tipos de parámetros
#El primero es una cadena de caracteres, donde cada carácter especifica el tipo de valor que va a recibir cada uno de los valores esperados en la consulta.
**La codificación sería :
#s: cadena de caracteres
#i: número entero
#d: número float
#b: valor binario (BLOB)
*En nuestro caso como va a recibir en los dos parámetros cada uno una cadena de caracteres sería '''''"ss"'''''
#El segundo grupo sería cada uno de los valores.SIEMPRE hay que especificar variables
*En el ejemplo que estamos siguiendo
<source lang=php>
$consulta = $conexion->stmt_init();
$consulta->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)');
$cod_producto = "TABLET";
$nombre_producto = "Tablet PC";
$consulta->bind_param('ss', $cod_producto, $nombre_producto);
  • Insistimos en que siempre hay que especificar variables, de modo que
$consulta->bind_param('ss', 'TABLET', 'Tablet PC');  // Genera un error


Icon summary.gif

Resumen

$conexion = new mysqli(...);
$consulta = $conexion->stmt_init();
$consulta->prepare(...sentencia ... con ???)
$consulta->bind_param('s-i-b-d(tipo_de_valores)',valores_en_variables_respectivos_a_????');
$consulta->execute();
$consulta->close();
$conexion->close();



Consultas preparadas que retornan valores

  • 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
  • Para recorre el conjunto de valores, usamos el método fectch(), como se ve en el ejemplo
$consulta = $conexion->stmt_init();
$consulta->prepare('SELECT producto, unidades FROM stock WHERE unidades<2');
$consulta->execute();
$consulta->bind_result($producto, $unidades);
while($consulta->fetch()) {
	print "<p>Producto $producto: $unidades unidades.</p>";
}
$consulta->close();
$conexion->close();
  • Aquí hay un enlace para una información completa sobre consultas preparadas
http://php.net/manual/es/class.mysqli-stmt.php


Icon activity.jpg

Actividad

  • Modifica el ejercicio anterior usando consultas parametrizadas






Icon activity.jpg

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).





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
 $conexion = new PDO(...);

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
 $conexion = new PDO('mysql:host=localhost;dbname=dwes', ...);
Nombre de usuario
Contraseña del usuario.
Opciones de conexión, almacenadas en forma de array.
(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);

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
   $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>";
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.
  1. PDO::FETCH_ASSOC. Devuelve solo un array asociativo.
  2. PDO::FETCH_NUM. Devuelve solo un array con claves numéricas.
  3. PDO::FETCH_BOTH. Devuelve un array con claves numéricas y asociativas. Es el comportamiento por defecto.
  4. 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
$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 />";
}
$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 />";
}
$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 />";
}
$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 />";
}


Icon summary.gif

Resumen

 $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.


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 :
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123.");
$consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (?, ?)');

Es igual que hacer

$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123.");
$consulta = $conexion->prepare('INSERT INTO familia (cod, nombre) VALUES (:codigoProducto, :nombreProducto)');
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)
$cod_producto = "TABLET";
$nombre_producto = "Tablet PC";
$consulta->bindParam(1, $cod_producto);
$consulta->bindParam(2, $nombre_producto);
  • Si se han especificado con nombre se usan los nombre en lugar de los números
$cod_producto = "TABLET";
$nombre_producto = "Tablet PC";
$consulta->bindParam(":cod", $cod_producto);
$consulta->bindParam(":nombre", $nombre_producto);
  • 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
$parametros = array["TABLET", ":nombre"];
$consulta->execute($parametros);
  • En el segundo caso
$parametros = array(":cod" => "TABLET", ":nombre" => "Tablet PC");
$consulta->execute($parametros);


Icon activity.jpg

Actividad

  • Realiza un pequeño program en php que usando la extensión PDO, realice las siguientes acciones
  1. Se conecte a la base de datos dwes
  2. insertamos un nuevo eleemntos o tupla en la tabla producto
  3. consultamos todos los productos y los visualizamos
  4. Hacemos otra consulta parametrizada de todos los productos de la tabla stock de una determinada tienda
    1. Esta última acción primero usando bindParam y luego sin usarlo (pasando directamente el parámetro al método execute
<!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>





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:
  1. El código susceptible de producir algún error se introduce en un bloque try - catch.
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();
}
  1. Cuando se produce algún error, se lanza una excepción utilizando la instrucción throw.
  2. Después del bloque try debe haber como mínimo un bloque catch encargado de procesar el error.
  3. 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.


Icon activity.jpg

Actividad

Haz un programa que si dividimos por cero pase una exepcion

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();
}




  • 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:
  1. PDO::ERRMODE_SILENT. No se hace nada cuando ocurre un error. Es el comportamiento por defecto.
  2. PDO::ERRMODE_WARNING. Genera un error de tipo E_WARNING cuando se produce un error.
  3. 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
$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 />";
}
  • En este caso que no existe la tabla nos diría
 Error SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dwes.stox' doesn't exist
  • 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


Icon activity.jpg

Actividad

  • Realicemos un fichero de conexión a base de datos que contenga las siguientes funciones
  1. conectar($bd, $usuario,$password) Retornará un objeto de la clase PDO si todo ok
  2. consulta($sentencia,$parametros) Retorna un objeto de la clase PDOStatement si todo ok,
    1. Recibe dos argumentos, un string que será la consulta parametrizada, y un array con los valores para cada parámetro
  3. Insertar($tabla,$valores)
    1. Recibe un string que es el nombre de tabla y un vector que serán los diferentes valores para cada campo de la tabla
    2. 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

Obtenido de «https://es.wikieducator.org/index.php?title=Usuario:ManuelRomero/php/BasesDatos&oldid=16212»