Diferencia entre revisiones de «Plantilla:PHP/Mysqli»

De WikiEducator
Saltar a: navegación, buscar
(Clausula SELECT con query)
 
(32 revisiones intermedias por el mismo usuario no mostrado)
Línea 1: Línea 1:
 
<div id=parrafo>
 
<div id=parrafo>
 
 
<div class="slide">
 
<div class="slide">
===Introducción al Uso de extensiones orientadas a objetos===
+
===Mysqli===
*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  
 
la correspondiente funcionalidad en el lenguaje estructurado.
 
la correspondiente funcionalidad en el lenguaje estructurado.
 
*Para recordar muy brevemente posemos usar el siguiente enlace
 
*Para recordar muy brevemente posemos usar el siguiente enlace
Línea 10: Línea 9:
  
 
<div class="slide">
 
<div class="slide">
;Uso básico de POO
+
;Uso básico de un recurso de tipo '''''mysqli'''''
 
*Recordamos que para crear una nueva instancia de una clase usamos el operador '''''new'''''
 
*Recordamos que para crear una nueva instancia de una clase usamos el operador '''''new'''''
 
<source lang=php>
 
<source lang=php>
Línea 21: Línea 20:
 
</div>
 
</div>
  
 +
{{MRM_Puntos clave|Title=Acciones básicas que hemos de aprender|
 +
;Para trabajar con una base de datos, siempre hemos de seguir una serie de acciones
  
<div class="slide">
+
;1.- Concetarnos a la base de datos
=====Mysql y php=====
+
  Esto será crear una instancia de un objeto de conexión
'''''Mysql''''' es un gestor de bases de datos relacional. Actualmente es un producto propietario de la empresa '''''Oracle''''', y el software correspondiente libre es '''''Maria''''' que en estos momentos funciona exactamente igual que '''''Mysql''''' y con los mismos comandos. <br />
+
;2.- Verificar que la conexión se ha realizado
Tener en cuenta la diferencia de la parte del servidor  (donde realmente se guardan los datos), y la parte del cliente que es un software que nos ofrece una interfaz de comandos o gráfica y nos permite conectarnos al servidor  y gestionar la bases de datos (básicamente enviar sentencias SQL y recoger los resultado).<br />
+
  Si, por el motivo que fuera, no nos hemos podido conectar,generalmente:
[[Imagen:MysqlClienteServidor.png]]
+
  1.- Informaremos de ello
 
+
  2.- Cerraremos la conexión
<source lang=bash>
+
;3.- Realizaremos las operativas que necesitemos
apt-get install mysql-server mysql-client
+
Ejecutaremos sentencias SQL y recogeremos el resultado de la consulta
</source>
+
Generalmente informaremos de algo al usuario de la aplicación 
Como todos servicio se puede arrancar o parar
+
;4.- Cerraremos la conexión
  service mysql start/stop/restart/status
+
  Un aspecto que puede pasar desapercibido, pero muy importante
*El fichero de configuración
+
/etc/mysql/my.cnf
+
</div>
+
 
+
<div class="slide">
+
;Mysql
+
*En él podemos ver el puerto (3306 por defecto), el usuario y otros parámetros del servicio
+
{{MRM_Actividad|Title=Mysql con docker|
+
*Monta un contenedor de docker llamdo contenedorMysql
+
*Instala en el contenedor mysql.  
+
*Guarda el contenedor como una imagen y llámalo imagen Mysql.
+
*Crea un nuevo contenedor de esa imagen
+
*Prueba desde tu localhost a conectarte a la base de datos de ese contenedor
+
 
}}
 
}}
</div>
 
  
 
<!-- MRM Falta insertar ejemplos de las acciones -->
 
 
===Línea de comandos de Mysql===
 
Es importante saberse manejar en línea de comandos con el cliente mysql. En alguna ocasión puede se la forma más rápida de obtener información o realizar acciones sobre la base de dados. Para ello debemos de repasar algún comandos. Son pocos, pero hay que conocerlos.
 
*Acciones que hay que saber hacer
 
#Conectarse a una base de datos en un servidor
 
<source lang=sql>
 
</source>
 
#Mostrar las bases de datos
 
#Usar una base de datos concreta
 
#Mostrar la descripción de una base de datos (Las tablas que contiene)
 
#Obtener ayuda de los comandos disponibles
 
*Por supuesto debemos de poder ejecutar sentencias SQL
 
#Crear una base de datos (Sentencia SQL), y borrarla
 
#Crear una tabla
 
#Crear un usuario y darle permisos
 
#Modificar y borrar una tabla
 
#Insertar, modificar y borrar registros o tuplas
 
#Realizar consultas '''''select'''''
 
<source lang=bash>
 
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
 
</source>
 
 
<div class="slide">
 
{{MRM_Actividad|
 
#Conectar a mysql <!--mysql -u root -proot-->
 
#Mira Las bases de datos que tienes <!-- show databases;-->
 
#usa una base de datos concreta <!--use mysql -->
 
#mira las tablas que tiene esa bases de datos <!-- show tables-->
 
#mira la estructura de la tabla <!-- show nombreTabla-->
 
#Haz una consulta de los valores que tiene su primera columna <!--select campo from tabla;-->
 
#ejecuta el comando help
 
#sal de sql <!-- quit-->
 
}}
 
</div>
 
<div class="slide">
 
;Bases de datos
 
[[archivo:baseDatos.pdf]]
 
<source lang=sql>
 
-- Creamos la base de datos
 
CREATE DATABASE `dwes` DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci;
 
USE `dwes`;
 
-- Creamos las tablas
 
CREATE TABLE `dwes`.`tienda` (
 
`cod` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
 
`nombre` VARCHAR( 100 ) NOT NULL ,
 
`tlf` VARCHAR( 13 ) NULL
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`producto` (
 
`cod` VARCHAR( 12 ) NOT NULL ,
 
`nombre` VARCHAR( 200 ) NULL ,
 
`nombre_corto` VARCHAR( 50 ) NOT NULL ,
 
`descripcion` TEXT NULL ,
 
`PVP` DECIMAL( 10, 2 ) NOT NULL ,
 
`familia` VARCHAR( 6 ) NOT NULL ,
 
PRIMARY KEY ( `cod` ) ,
 
INDEX ( `familia` ) ,
 
UNIQUE ( `nombre_corto` )
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`familia` (
 
`cod` VARCHAR( 6 ) NOT NULL ,
 
`nombre` VARCHAR( 200 ) NOT NULL ,
 
PRIMARY KEY ( `cod` )
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`stock` (
 
`producto` VARCHAR( 12 ) NOT NULL ,
 
`tienda` INT NOT NULL ,
 
`unidades` INT NOT NULL ,
 
PRIMARY KEY ( `producto` , `tienda` )
 
) ENGINE = INNODB;
 
-- Creamos las claves foráneas
 
ALTER TABLE `producto`
 
ADD CONSTRAINT `producto_ibfk_1`
 
FOREIGN KEY (`familia`) REFERENCES `familia` (`cod`)
 
ON UPDATE CASCADE;
 
ALTER TABLE `stock`
 
ADD CONSTRAINT `stock_ibfk_2`
 
FOREIGN KEY (`tienda`) REFERENCES `tienda` (`cod`)
 
ON UPDATE CASCADE,
 
ADD CONSTRAINT `stock_ibfk_1`
 
FOREIGN KEY (`producto`) REFERENCES `producto` (`cod`)
 
ON UPDATE CASCADE;
 
CREATE USER `dwes`
 
IDENTIFIED BY 'abc123.';
 
GRANT ALL ON `dwes`.*
 
TO `dwes`;
 
</source>
 
{{Actividad|
 
Usa mysql para cargar por líneas de comandos el siguiente fichero arriba especificado
 
}}
 
</div>
 
 
<div class="slide">
 
;Recordando mysql
 
*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
 
</div>
 
 
<div class="slide">
 
;Recordando mysql
 
*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
 
</div>
 
<div class="slide">
 
====Interfaz gráfica====
 
Además de línea de comandos también se dispone de varias herramientas gráficas alternativas. Siempre resulta más agradable e intuitivo, pero requiere más recursos y tener instalados aplicaciones concretas.<br />
 
En windows o con wine en linux podemos probar '''''SQLyog'''''  https://www.webyog.com/product/sqlyog, una herramienta intuitiva y de poco peso. No obstante usaremos '''''phpmyadmin''''', por ser un clásico y de sencillo uso.<br />
 
 
{{MRM_Actividad|
 
*Instalamos phpmyadmin en nuestro contenedor contenedorMysql
 
*Probamos a acceder a él desde nuestro localhost
 
*Depende de como instalemso es posible que haya que hacer un enlace simbóloco.
 
*Para  ello hay que buscar dónde se ha instalado el '''''index.php''''' de '''''phpmyadmin''''' .
 
*Entonces haceremos un enlace simbólico de esa carpeta a nuestro DocumentRoot.
 
*En mi caso:
 
<source lang=bash>
 
# ln -s /usr/share/phpmyadmin /var/www/phpmyadmin
 
</source>
 
Probamos a conectarnos por phpmyadmin a nuestro servidor local
 
<source lang=bash>
 
#Escribimos en el url
 
http://ip_contenedor/phpmyadmin
 
# ln -s /usr/share/phpmyadmin /var/www/phpmyadmin
 
</source>
 
 
}}
 
[[Archivo:datos.sql]]
 
<source lang=sql>
 
-- Creamos la base de datos
 
CREATE DATABASE `dwes` DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci;
 
USE `dwes`;
 
-- Creamos las tablas
 
CREATE TABLE `dwes`.`tienda` (
 
`cod` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
 
`nombre` VARCHAR( 100 ) NOT NULL ,
 
`tlf` VARCHAR( 13 ) NULL
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`producto` (
 
`cod` VARCHAR( 12 ) NOT NULL ,
 
`nombre` VARCHAR( 200 ) NULL ,
 
`nombre_corto` VARCHAR( 50 ) NOT NULL ,
 
`descripcion` TEXT NULL ,
 
`PVP` DECIMAL( 10, 2 ) NOT NULL ,
 
`familia` VARCHAR( 6 ) NOT NULL ,
 
PRIMARY KEY ( `cod` ) ,
 
INDEX ( `familia` ) ,
 
UNIQUE ( `nombre_corto` )
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`familia` (
 
`cod` VARCHAR( 6 ) NOT NULL ,
 
`nombre` VARCHAR( 200 ) NOT NULL ,
 
PRIMARY KEY ( `cod` )
 
) ENGINE = INNODB;
 
CREATE TABLE `dwes`.`stock` (
 
`producto` VARCHAR( 12 ) NOT NULL ,
 
`tienda` INT NOT NULL ,
 
`unidades` INT NOT NULL ,
 
PRIMARY KEY ( `producto` , `tienda` )
 
) ENGINE = INNODB;
 
-- Creamos las claves foráneas
 
ALTER TABLE `producto`
 
ADD CONSTRAINT `producto_ibfk_1`
 
FOREIGN KEY (`familia`) REFERENCES `familia` (`cod`)
 
ON UPDATE CASCADE;
 
ALTER TABLE `stock`
 
ADD CONSTRAINT `stock_ibfk_2`
 
FOREIGN KEY (`tienda`) REFERENCES `tienda` (`cod`)
 
ON UPDATE CASCADE,
 
ADD CONSTRAINT `stock_ibfk_1`
 
FOREIGN KEY (`producto`) REFERENCES `producto` (`cod`)
 
ON UPDATE CASCADE;
 
CREATE USER `dwes`
 
IDENTIFIED BY 'abc123.';
 
GRANT ALL ON `dwes`.*
 
TO `dwes`;
 
 
</source>
 
</div>
 
 
<div class="slide">
 
 
{{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>
 
</div>
 
<div class="slide">
 
{{Actividad|
 
*Instalamos y probamos las diferentes opciones con esta herramienta
 
*Probamos a hacer un diseño en modelo relacional y a partir del modelo creamos las tablas.
 
*Probamos las opciones '''''forward engineer''''' y '''''reverser engineer'''''
 
}}
 
</div>
 
<div class="slide">
 
 
===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.
 
#mysql
 
#myhsqladmin
 
#mysqlshow
 
</div>
 
<div class="slide">
 
 
<div class="slide">
 
;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
 
</div>
 
<div class="slide">
 
{{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
 
-->
 
}}
 
</div>
 
 
<div class="slide">
 
;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
 
</div>
 
  
 
<div class="slide">
 
<div class="slide">
===Mysql y su extensión mysqli para php===
+
====Mysql y su extensión mysqli para php====
 
: CONECTARNOS A LA BASE DE DATOS
 
: CONECTARNOS A LA BASE DE DATOS
 
*A continuación iremos viendo como implementar las acciones básicas en el lenguaje
 
*A continuación iremos viendo como implementar las acciones básicas en el lenguaje
Línea 314: Línea 50:
 
<div class="slide">
 
<div class="slide">
 
;Extensión Mysqli
 
;Extensión Mysqli
*El constructor de la clase puede recibir hasta 5 parámetros, de los cuales 4 se suelen usar con bastante frecuencia
+
*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
+
#'''''$host''''' nombre o ip del equipo (null o localhost, identificaría el equipo actual).i
 
#'''''$usario''''' es el usuario de la base de datos
 
#'''''$usario''''' es el usuario de la base de datos
 
#'''''$pass'''''
 
#'''''$pass'''''
Línea 333: Línea 69:
 
  $miConexion = new mysqli ($host,$usuario,$pass,$nombreBD);
 
  $miConexion = new mysqli ($host,$usuario,$pass,$nombreBD);
 
  if ($miConexion==null)
 
  if ($miConexion==null)
     echo"Error conectando a la base de datos";
+
     echo"No se ha podido crear el objeto.
 +
          Seguramente no tiene instalada la extensión mysqli.
 +
          Prueba a instalar apt install php-mysql  ";
 
  else
 
  else
     echo "Conectado a la base de datos";
+
     echo "Objeto creado";
 
</source>
 
</source>
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
 +
{{Nota|Pruena a ver el contenido del objeto con '''''var_dump''''', así podrás observar los atributos que tenemos disponibles. Son todos muy intuitivos y los iremos viendo a lo largo de este tema.}}
 +
<source lang=php>
 +
var_dump($miConexion);
 +
</source>
 +
 
;mysqli(...)
 
;mysqli(...)
*Esta función retorna el recurso de la conexión
+
*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'''''
+
{{Tip|Aunque hablemos de mysqli como una clase, en realidad es una clase especial conocida como recurso.
 +
'''Un recurso a diferencia de una clase no se puede serializar para pasar entre scripts.'''
 +
}}
 +
*Para gestionar los errores de la conexión, debemos de usar los  atributos:
 +
# '''''connect_errno''''': Número o códiog del error  que se ha producido en la conexión. 0 implica que no hay error.
 +
# '''''connect_error''''':Descripción del error en forma de string. "" (cadena vacía) es la descripción cuando no ha habido error en la conexión.
 +
de la clase '''''mysqli'''''.
 +
*El echo de que se pueda instanciar o  el objeto de la clase, no implica que se haya realizado  la conexión.
 
*Este atributo aporta información sobre el error o contiene null si no se ha producido ninguno.
 
*Este atributo aporta información sobre el error o contiene null si no se ha producido ninguno.
 
*En el código anterior
 
*En el código anterior
 
  <source lang=php>
 
  <source lang=php>
if ($miConexion->connect_error)
+
if ($miConexion->connect_error) {
  echo "Error conectando con la base de datos: ".$miConexion->connect_error;
+
echo "ERROR;
 +
echo "Error: Fallo al conectarse a MySQL debido a: \n";
 +
echo "Errno: " . $mysqli->connect_errno . "\n";
 +
echo "Error: " . $mysqli->connect_error . "\n";
 +
}
 
</source>
 
</source>
 
</div>
 
</div>
  
 
<div class="slide">
 
<div class="slide">
*Para ver información sobre la conexión se puede usar los atributos *server_info o host_info
+
*Para ver información sobre la conexión se puede usar los atributos '''''$server_info''''' o '''''$host_info'''''
{{Resumen|
+
{{MRM_Resumen|
 
<source lang=php>
 
<source lang=php>
 
$conesion= new mysqli($host,$user,$pass,$bd);
 
$conesion= new mysqli($host,$user,$pass,$bd);
mysqli->conect_error
+
$conesion->conect_error
mysqli->conect_errno
+
$conesion->conect_errno
mysqli->server_info
+
$conesion->server_info
mysqli->host_info
+
$conesion->host_info
 
</source>
 
</source>
 
}}
 
}}
Línea 365: Línea 119:
 
;Opciones por defecto
 
;Opciones por defecto
 
<hr/>
 
<hr/>
*Hay muchas opciones de mysqli que se pueden configurar en el fichero php.ini
+
*Hay muchas opciones de '''mysqli''' que se pueden configurar en el fichero '''''php.ini''''', no es algo que normalmente se modifique, pero por curiosidad las comentamos aquí.
 
*Aquí tenemos alguna de ellas
 
*Aquí tenemos alguna de ellas
 
;mysqli.allow_persistent
 
;mysqli.allow_persistent
Línea 374: Línea 128:
  
 
<div class="slide">
 
<div class="slide">
;Opciones por defecto
+
 
 
<hr/>
 
<hr/>
 
;mysqli.reconnect
 
;mysqli.reconnect
Línea 389: Línea 143:
 
*La lista completa la podemos ver en el siguiente link
 
*La lista completa la podemos ver en el siguiente link
 
  http://php.net/manual/es/mysqli.configuration.php
 
  http://php.net/manual/es/mysqli.configuration.php
{{Actividad|
+
{{MRM_Actividad|
 
*Configura dicho fichero, para poder conectar a la base de datos sin aportar parámetros al constructor
 
*Configura dicho fichero, para poder conectar a la base de datos sin aportar parámetros al constructor
 
*Luego déjalo como estaba :)}}
 
*Luego déjalo como estaba :)}}
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
 +
====Cerrar una base de datos====
 +
;Cerrar conexión
 +
*Cuando ya no vamos a utilizar más la conexión la cerramos para liberar recursos.
 +
*Es importante hacer esta acción de forma explícita
 +
<source lang=php>
 +
$miConexion->close();
 +
</source>
  
===Cambiar la base de datos===
+
=====Cambiar la base de datos=====
 
*Si hemos seleccionado una base de datos, o no hemos seleccionado ninguna y queremos cambiar a otra
 
*Si hemos seleccionado una base de datos, o no hemos seleccionado ninguna y queremos cambiar a otra
 
<source lang=php>
 
<source lang=php>
Línea 404: Línea 165:
 
$miConexion->close();
 
$miConexion->close();
 
</source>
 
</source>
 +
{{Tip|Es muy importante liberar un recurso reservado una vez que ya no se vaya a usar mas.}}
 
</div>
 
</div>
  
 
<div class="slide">
 
<div class="slide">
===DML===
+
====Ejecutando sentencias SQL: DML (insert, delete, update, select)====
 
*En SQL sabemos que tenmos tres tipos de lenguajes DDL, DML, DCL
 
*En SQL sabemos que tenmos tres tipos de lenguajes DDL, DML, DCL
*Ahora toca DML, Leguane de maninputación de datos
+
*Nos vamos a centrar en el DML, Leguane de maniputación de datos
 
*Podemos clasificar en dos tipos de clúsulas:  
 
*Podemos clasificar en dos tipos de clúsulas:  
 
#las que no devuelven registros de datos (INSERT, DELETE, UPDATE)
 
#las que no devuelven registros de datos (INSERT, DELETE, UPDATE)
Línea 421: Línea 183:
 
<div class="slide">
 
<div class="slide">
  
===INSERT, UPDATE Y DELETE: Método '''''query(...)'''''===
+
=====INSERT, UPDATE Y DELETE: Método '''''query(...)'''''=====
 
El método '''''query''''', es un método de la clase '''''mysqli''''' que permite enviar una '''sentencia sql''' a la base de datos con la que tengamos conexión. En función del tipo de consulta, el método nos puede devolver los siguientes valores: <br />
 
El método '''''query''''', es un método de la clase '''''mysqli''''' que permite enviar una '''sentencia sql''' a la base de datos con la que tengamos conexión. En función del tipo de consulta, el método nos puede devolver los siguientes valores: <br />
 
#'''''Booleano''''' (con las sentencias ''' Insert, Update, Delete'''); indica si la acción se realizó o no correctamente.
 
#'''''Booleano''''' (con las sentencias ''' Insert, Update, Delete'''); indica si la acción se realizó o no correctamente.
Línea 440: Línea 202:
 
//Me preparo sentencias
 
//Me preparo sentencias
 
//Actuaré sobre la tabla tienda (ver BD anterior)
 
//Actuaré sobre la tabla tienda (ver BD anterior)
//Tiene los campos cod (autogenerado de forma incremental), nombre y tlf (ambos de tipo varchar)
+
//Tiene los campos cod (autogenerado de forma incremental),  
 
+
//nombre y tlf (ambos de tipo varchar)
$sentenciaInsert="INSERT INTO tienda (nombre, tlf) VALUES ('Tienda centro', '111-155226')";
+
$sentenciaInsert="INSERT INTO tienda (nombre, tlf)  
$sentenciaDelete="DELETE FROM tienda WHERE nombre = 'Tienda centro' ";
+
  VALUES ('Tienda centro', '111-155226')";
$sentenciaUpdate="UPDATE tabla tienda SET nombre = 'Tienda principal'  WHERE  nombre = 'Tienda centro'";
+
$sentenciaDelete="DELETE FROM tienda
 +
  WHERE nombre = 'Tienda centro' ";
 +
$sentenciaUpdate="UPDATE tabla tienda  
 +
SET nombre = 'Tienda principal'
 +
  WHERE  nombre = 'Tienda centro'";
  
  
Línea 450: Línea 216:
 
$resultado=miConexion->query($sentenciaInsert)
 
$resultado=miConexion->query($sentenciaInsert)
 
if($resultado){
 
if($resultado){
   echo"Se han insertado  $miConexion->affected_rows filas en esta acción <br />");
+
   echo"Se han insertado  $miConexion->affected_rows  
   echo"en la inserción se asignó el id autogenerado $miConexion->insert_id <br />");
+
        filas en esta acción <br />";
 +
   echo "en la inserción se asignó el id autogenerado $miConexion->insert_id
 +
        <br />";
 
}
 
}
  
Línea 463: Línea 231:
 
{{MRM_Pregunta|
 
{{MRM_Pregunta|
 
'''''Qué pasa si en nombre de la tienda es por ejemplo Technology's house'''''
 
'''''Qué pasa si en nombre de la tienda es por ejemplo Technology's house'''''
*Habría que escapar ese caracter}}
+
*Habría que escapar ese carácter}}
 +
{{MRM_Actividad|Title=Inserción de datos|
 +
*Realiza una aplicación para insertar datos en una tabla llamada usuarios
 +
*Insertaremos '''''Nombre''''', '''''Password'''''  y edad
 +
*Verificaremos la insercción accediendo a la base de datos con phpmyadmin
 +
*El password que esté cifrada
 +
}}
 +
 
 
====Escapar caracteres====
 
====Escapar caracteres====
 
Consiste en que de una forma automática si una cadena de caracteres tiene comillas, que estás queden escapadas para que formen parte de la cadena de caracteres y no especifique delimitación de la cadena.<br />
 
Consiste en que de una forma automática si una cadena de caracteres tiene comillas, que estás queden escapadas para que formen parte de la cadena de caracteres y no especifique delimitación de la cadena.<br />
Línea 469: Línea 244:
 
*Es un método de la clase '''''mysqli'''''
 
*Es un método de la clase '''''mysqli'''''
 
<source lang=php>
 
<source lang=php>
string cadena_escapada ( string $cadena_a_escapar )
+
 
 +
string mysqli_real_scape_string ( mysqli $conexion, string $cadena_a_escapar )
 +
 
 +
</source>
 +
También se puede usar como método de la clase
 +
<source lang=php>
 +
$conexion = new mysqli(..);
 +
$cadena = $conexion->real_scape_string(....);
 
</source>
 
</source>
 
}}
 
}}
Línea 491: Línea 273:
 
*Esto a la hora de insertar me generará un error, ya que el gestor interpreta que el contenido para el campo '''''descripcion''''' es 'I don'
 
*Esto a la hora de insertar me generará un error, ya que el gestor interpreta que el contenido para el campo '''''descripcion''''' es 'I don'
 
*Para evitar esto yo querría que el valor de '''''$descripcion''''' estuviera escapado
 
*Para evitar esto yo querría que el valor de '''''$descripcion''''' estuviera escapado
 +
 +
 
<source lang= php>
 
<source lang= php>
 
INSERT INTO acciones VALUES (1, 'I don\'t want go animal\'s house')
 
INSERT INTO acciones VALUES (1, 'I don\'t want go animal\'s house')
 
</source>
 
</source>
}}
+
se puede conseguir
 +
<source lang = php>
 +
//...
 +
$descripción  = $conexion->real_scape_string("I don't want go animal's house");
 +
//...
 +
$consulta = "INSERT INTO acciones VALUES (1, '$descripcion')"
 +
//...
  
 +
</source>
 +
 +
}}
 +
{{Tip|Alternativamente al método de la clase mysqli, podemos usar con metodología estructurada la función '''''mysql_real_scape_string()}}
 +
{{MRM_Web|
 +
https://www.php.net/manual/es/mysqli.real-escape-string.php
 +
}}
  
observa el tema de las comillas, los valores de las instrucciones sql  sin son de tipo varchar deben de ir entre comillas}}
+
{{Tip|Observa el tema de las comillas, los valores de las instrucciones '''sql''' sin son de tipo '''''varchar''''' deben de ir entre comillas}}
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
Línea 555: Línea 352:
 
<div class="slide">
 
<div class="slide">
  
===Clausula SELECT con query===
+
====Clausula SELECT con query====
 
*Tenemos dos maneras de realizar consultas con mysqli
 
*Tenemos dos maneras de realizar consultas con mysqli
 
#query
 
#query
 
#real_query
 
#real_query
*En el primero caso el método nos retorna un cursor que será de la clase mysqli_result
+
*En el primero caso el método nos retorna un cursor que será de la clase '''''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.
 
*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.
 
</div>
 
</div>
 +
*El método '''''query''''' con una sentencia de tipo  '''''select''''' como parámetro, nos retorna un objeto de la clase mysqli_result. Esta clase (recurso) implemente la interfaz '''''Traversable''''', lo que le hace iterable en los datos que contiene.
 +
*Esta clase contiene el resultado de la consulta como un conjunto de filas, pero no lo tiene como un atributo visible, si no como parte de los métodos que tenemos disponibles para obtenerlo (los metodos fetch_xxxx)
 
<div class="slide">
 
<div class="slide">
===Método query===
+
 
 +
====Método query====
 
*Una vez que tenemos los datos almacenados debemos saber acceder.
 
*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
+
*Tenemos 4 formas de poder acceder a los datos según usemos un método u otro.
 +
*Cuando hablamos de acceder a los datos, estamos estableciendo la forma de extraer cada fila, registro o tupla  resultado de ejecutar la consulta.
 
;fetch_array()
 
;fetch_array()
 
:Va obteniendo cada registro como un array
 
:Va obteniendo cada registro como un array
Línea 582: Línea 383:
 
<div class="slide">
 
<div class="slide">
  
{{Actividad|
+
{{MRM_Actividad|
*Optén todos los registros de la tabla familia  
+
*Obtén todos los registros de la tabla familia  
*visualizalos en una tabla usando los tres modos de lectura de datos vistos anteriormente
+
*visualízalos 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()''''';
 
*Para liberar un recurso del tipo '''''mysqli_result''''', usamos el método '''''free()''''';
Línea 600: Línea 401:
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
{{Resumen|
+
{{MRM_Resumen|
 
<source lang=php>
 
<source lang=php>
 
$conexion= new mysqli($host,$user,$pass,$bd);
 
$conexion= new mysqli($host,$user,$pass,$bd);
Línea 620: Línea 421:
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
{{Actividad|
+
{{MRM_Actividad|
 
Haciendo una consulta del tipo select * from producto where pvp < 200, realiza un código que visualizce en una tabla los resultados }}
 
Haciendo una consulta del tipo select * from producto where pvp < 200, realiza un código que visualizce en una tabla los resultados }}
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
  
===Transacciones===
+
====Transacciones====
 
<br/>
 
<br/>
{{Definicion|
+
{{MRM_Definicion|
 
*Una transacción es un conjunto de acciones u operaciones que  
 
*Una transacción es un conjunto de acciones u operaciones que  
 
*Esta se realizan contra una base de datos de modo que o bien se realizan correctamente todas  
 
*Esta se realizan contra una base de datos de modo que o bien se realizan correctamente todas  
Línea 653: Línea 454:
  
 
  if (CondicionOK){
 
  if (CondicionOK){
     //Terminamos la transacción confirmando todas las acciones sobre la base de datos desde que se inició la    
+
     //Terminamos la transacción confirmando todas las acciones sobre la base de  
      transaccion
+
    //datos desde que se inició la transacción
 
     $conexion->commit();
 
     $conexion->commit();
 
  }else{
 
  }else{
     //Terminamos la transacción desaciendo todas las acciones sobre la base de datos desde que se inició la     
+
     //Terminamos la transacción deshaciendo todas  
      transaccion, y dejando la base de datos igual que estaba al principio
+
    //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();
 
   $conexion->rollback();
 
   }
 
   }
Línea 665: Línea 467:
 
<div class="slide">
 
<div class="slide">
  
{{Actividad|
+
{{MRM_Actividad|
 
Ejercicio de transacciones
 
Ejercicio de transacciones
 
}}
 
}}
Línea 671: Línea 473:
 
<div class="slide">
 
<div class="slide">
  
===Injecciones SQL===
+
====Injecciones SQL====
 
*Es un problema de seguridad importante, que hay que conocer y evitar
 
*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.
 
*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.
Línea 677: Línea 479:
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
{{Recursos de la Web|
+
{{MRM_Recursos de la Web|
 
#http://php.net/manual/es/security.database.sql-injection.php
 
#http://php.net/manual/es/security.database.sql-injection.php
 
#http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL
 
#http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL
Línea 685: Línea 487:
 
<div class="slide">
 
<div class="slide">
 
;Otras entradas un poco cuestionables por finalidad ???
 
;Otras entradas un poco cuestionables por finalidad ???
{{Recursos de la web|
+
{{MRM_Recursos de la Web|
 
#http://foro.elhacker.net/tutoriales_documentacion/tutorial_de_inyeccion_sql_sql_injection-t98448.0.html
 
#http://foro.elhacker.net/tutoriales_documentacion/tutorial_de_inyeccion_sql_sql_injection-t98448.0.html
  
Línea 698: Línea 500:
 
#Entrar en la plataforma sin tener acceso
 
#Entrar en la plataforma sin tener acceso
  
===Entrar en la plataforma sin tener acceso===
+
=====Entrar en la plataforma sin tener acceso=====
 
*Entramos en una página y vemos el siguiente acceso
 
*Entramos en una página y vemos el siguiente acceso
 
[[Archivo:miAcceso.png]]
 
[[Archivo:miAcceso.png]]
Línea 734: Línea 536:
 
[[Archivo:miAccesoInjeccion.png]]
 
[[Archivo:miAccesoInjeccion.png]]
 
*Entramos al sistema sin conocer usuario y contraseña
 
*Entramos al sistema sin conocer usuario y contraseña
[[Archivo:accesoInjectado.png]]
+
[[Archivo:accesoInjectado.png|800px]]
  
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
===Consultas preparadas===
+
 
 +
====Consultas preparadas====
 
*Una consulta preparada consiste en establecer una consulta como si fuera una variable y ejecutarla posteriormente tantas veces como sea necesario.
 
*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
 
*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
Línea 767: Línea 570:
 
<div class="slide">
 
<div class="slide">
  
===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.
 
*La idea es preapara la consulta sin indicar los valores.
 
*La idea es preapara la consulta sin indicar los valores.
Línea 793: Línea 596:
 
#'''''i''''': número entero
 
#'''''i''''': número entero
 
#'''''d''''': número float
 
#'''''d''''': número float
#'''''b''''': valor binario (BLOB)
+
#'''''b''''': valor binario (BLOB ('''binary large object'''))
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
Línea 818: Línea 621:
 
$consulta->bind_param('ss', 'TABLET', 'Tablet PC');  // Genera un error
 
$consulta->bind_param('ss', 'TABLET', 'Tablet PC');  // Genera un error
 
</source>
 
</source>
{{Resumen|
+
{{MRM_Resumen|
 
<source lang=php>
 
<source lang=php>
 
$conexion = new mysqli(...);
 
$conexion = new mysqli(...);
 
$consulta = $conexion->stmt_init();
 
$consulta = $conexion->stmt_init();
 
$consulta->prepare(...sentencia ... con ???)
 
$consulta->prepare(...sentencia ... con ???)
$consulta->bind_param('s-i-b-d(tipo_de_valores)',valores_en_variables_respectivos_a_????');
+
$consulta->bind_param('s-i-b-d(tipo_de_valores)',
 +
            valores_en_variables_respectivos_a_????');
 
$consulta->execute();
 
$consulta->execute();
 
$consulta->close();
 
$consulta->close();
Línea 832: Línea 636:
 
<div class="slide">
 
<div class="slide">
  
===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
Línea 856: Línea 660:
 
*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|
+
{{MRM_Actividad|
 
*Modifica el ejercicio anterior usando consultas parametrizadas
 
*Modifica el ejercicio anterior usando consultas parametrizadas
 
}}
 
}}
 
</div>
 
</div>
 
<div class="slide">
 
<div class="slide">
{{Actividad|Title=Práctica de tienda|
+
{{MRM_Actividad|Title=Práctica de tienda|
 
*Vamos a trabajar con la base de datos de la tienda
 
*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
 
*Lo primero usando la herramienta workbench generamos el modelo de tablas de la base de datos dwes y la analizamos
Línea 870: Línea 674:
 
<div class="slide">
 
<div class="slide">
  
{{Actividad|Title=Práctica de tienda|
+
{{MRM_Actividad|Title=Práctica de tienda|
 
*Puedes usar como base los siguientes ficheros css y plantilla adjuntos.
 
*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.  
 
*Añade la opción de modificar el número de unidades del producto en cada una de las tiendas.  
Línea 881: Línea 685:
 
<div class="slide">
 
<div class="slide">
 
<!--
 
<!--
 
===Definición de funiones=
 
function  ‘’’nombre_de_funcion’’’ (’’’’lista_de_parametros’’’’){
 
’’’’codigo a ejecutar ’’’’
 
}
 
</div>
 
<div class="slide">
 
===Ejemplo de funcion===
 
*Realiza una función que convierta de mayúsculas a minúsculas
 
</div>
 
<div class="slide">
 
 
 
 
===Generar pdf desde el código php===
 
pdf=new mPDF();
 
$mpdf->WriteHTML('<p>Hello World</p>');
 
$mpdf->Output();
 
</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étodo '''''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 = $conexion->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 = $conexion->query("SELECT producto, unidades FROM stock");
 
while ($registro = $resultado->fetch(PDO::FETCH_ASSOC)) {
 
    echo "Producto ".$registro['producto'].": ".$registro['unidades']."<br />";
 
}
 
</source>
 
<source lang=php>
 
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123.");
 
$resultado = $conexion->query("SELECT producto, unidades FROM stock");
 
while ($registro = $resultado->fetch(PDO::FETCH_NUM)) {
 
    echo "Producto ".$registro[0].": ".$registro[1]."<br />";
 
}
 
</source>
 
 
<source lang=php>
 
$conexion = new PDO("mysql:host=localhost;dbname=dwes", "dwes", "abc123.");
 
$resultado = $conexion->query("SELECT producto, unidades FROM stock");
 
while ($registro = $resultado->fetch(PDO::FETCH_OBJ)) {
 
    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 programa 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ón
 
 
}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===
 
  
  
-->
 
 
;Resetear la password de root
 
;Resetear la password de root
 
https://www.howtoforge.com/reset-forgotten-mysql-root-password
 
https://www.howtoforge.com/reset-forgotten-mysql-root-password
 
</div>
 
</div>

Última revisión de 17:03 7 abr 2022

Uso básico de un recurso de tipo mysqli
  • 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, usamos el operador de indirección ->
 $miObjeto->metodo($parametros);



Icon key points.gif

Acciones básicas que hemos de aprender

Para trabajar con una base de datos, siempre hemos de seguir una serie de acciones
1.- Concetarnos a la base de datos
Esto será crear una instancia de un objeto de conexión
2.- Verificar que la conexión se ha realizado
Si, por el motivo que fuera, no nos hemos podido conectar,generalmente:
  1.- Informaremos de ello
  2.- Cerraremos la conexión 
3.- Realizaremos las operativas que necesitemos
Ejecutaremos sentencias SQL y recogeremos el resultado de la consulta
Generalmente informaremos de algo al usuario de la aplicación  
4.- Cerraremos la conexión
Un aspecto que puede pasar desapercibido, pero muy importante



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(....);
Extensión 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
Ejemplo new mysqli(...)
 $host="localhost"
 $usuario="manolo";
 $pass="romero";
 $nombreBD="alumnos";
 
 $miConexion = new mysqli ($host,$usuario,$pass,$nombreBD);
 if ($miConexion==null)
     echo"No se ha podido crear el objeto. 
          Seguramente no tiene instalada la extensión mysqli.
          Prueba a instalar apt install php-mysql   ";
 else
     echo "Objeto creado";

(Comment.gif: Pruena a ver el contenido del objeto con var_dump, así podrás observar los atributos que tenemos disponibles. Son todos muy intuitivos y los iremos viendo a lo largo de este tema.)


var_dump($miConexion);
mysqli(...)
  • Esta función retorna el recurso de la conexión.
Icon present.gif
Tip: Aunque hablemos de mysqli como una clase, en realidad es una clase especial conocida como recurso.

Un recurso a diferencia de una clase no se puede serializar para pasar entre scripts.


  • Para gestionar los errores de la conexión, debemos de usar los atributos:
  1. connect_errno: Número o códiog del error que se ha producido en la conexión. 0 implica que no hay error.
  2. connect_error:Descripción del error en forma de string. "" (cadena vacía) es la descripción cuando no ha habido error en la conexión.

de la clase mysqli.

  • El echo de que se pueda instanciar o el objeto de la clase, no implica que se haya realizado la conexión.
  • 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;
 echo "Error: Fallo al conectarse a MySQL debido a: \n";
 echo "Errno: " . $mysqli->connect_errno . "\n";
 echo "Error: " . $mysqli->connect_error . "\n";
}
  • 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);
$conesion->conect_error
$conesion->conect_errno
$conesion->server_info
$conesion->host_info


Opciones por defecto

  • Hay muchas opciones de mysqli que se pueden configurar en el fichero php.ini, no es algo que normalmente se modifique, pero por curiosidad las comentamos aquí.
  • 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 :)


Cerrar una base de datos

Cerrar conexión
  • Cuando ya no vamos a utilizar más la conexión la cerramos para liberar recursos.
  • Es importante hacer esta acción de forma explícita
$miConexion->close();
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();
Icon present.gif
Tip: Es muy importante liberar un recurso reservado una vez que ya no se vaya a usar mas.


Ejecutando sentencias SQL: DML (insert, delete, update, select)

  • En SQL sabemos que tenmos tres tipos de lenguajes DDL, DML, DCL
  • Nos vamos a centrar en el DML, Leguane de maniputació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
DML
  1. 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: Método query(...)

El método query, es un método de la clase mysqli que permite enviar una sentencia sql a la base de datos con la que tengamos conexión. En función del tipo de consulta, el método nos puede devolver los siguientes valores:

  1. Booleano (con las sentencias Insert, Update, Delete); indica si la acción se realizó o no correctamente.
  2. mysqli_result (con la sentencia Select); si la consulta es de tipo select, el método retornará un conjunto de filas (0 o más); Dispondremos de esta información en un objeto del la clase mysql_result. Esta clase la estudiamos posteriormente.

Hay que tener en cuenta que este método modifica el objeto de la clase mysqli pudiendo afectar a los siguiente atributos:


Icon key points.gif

Atributos que puede modificar query()

  1. $affected_rows. Número de filas modificadas por la acción.
  2. $error, $errno. En caso de producir un error la sentencia.
  3. $insert_id Devuelve el id autogenerado que se utilizó en la última inserción.




Icon summary.gif
Resumen
//Me conecto a la base de datos
$miConexion = new mysqli("localhost", "root", "root", "dwes");
 
//Me preparo sentencias
//Actuaré sobre la tabla tienda (ver BD anterior)
//Tiene los campos cod (autogenerado de forma incremental), 
//nombre y tlf (ambos de tipo varchar)
$sentenciaInsert="INSERT INTO tienda (nombre, tlf) 
  VALUES ('Tienda centro', '111-155226')";
$sentenciaDelete="DELETE FROM tienda
  WHERE nombre = 'Tienda centro' ";
$sentenciaUpdate="UPDATE tabla tienda 
 SET nombre = 'Tienda principal'  
 WHERE  nombre = 'Tienda centro'";
 
 
//Hago una consulta de tipo insert
$resultado=miConexion->query($sentenciaInsert)
if($resultado){
   echo"Se han insertado  $miConexion->affected_rows 
        filas en esta acción <br />";
   echo "en la inserción se asignó el id autogenerado $miConexion->insert_id
        <br />";
}


Icon present.gif
Tip: Muy importante observa el tema de las comillas, los valores de las instrucciones sql sin son de tipo varchar deben de ir entre comillas


Icon present.gif
'Tip: Muy importante para la BD es igual comilla simple '''''' que comillas dobles "




Icon qmark.gif
Pregunta

Qué pasa si en nombre de la tienda es por ejemplo Technology's house

  • Habría que escapar ese carácter



Icon activity.jpg
Inserción de datos
  • Realiza una aplicación para insertar datos en una tabla llamada usuarios
  • Insertaremos Nombre, Password y edad
  • Verificaremos la insercción accediendo a la base de datos con phpmyadmin
  • El password que esté cifrada




Escapar caracteres

Consiste en que de una forma automática si una cadena de caracteres tiene comillas, que estás queden escapadas para que formen parte de la cadena de caracteres y no especifique delimitación de la cadena.


Icon define.gif
Método para escapar cadenas
  • Es un método de la clase mysqli
string mysqli_real_scape_string ( mysqli $conexion, string $cadena_a_escapar )

También se puede usar como método de la clase

$conexion = new mysqli(..);
$cadena = $conexion->real_scape_string(....);




Icon casestudy.gif
Escapar caracteres
  • suponemos que tenemos una tabla llamada acciones que tiene el campo descripcion y cod_usuario
  • Quiero insertar este valor para descripcion como muestra el siguiente código:
//...
$descripción  = "I don't want go animal's house"
//Esta asignación es correcta
//...
$consulta = "INSERT INTO acciones VALUES (1, '$descripcion')"
//...

si yo miro el contenido de la variable $consulta que es lo que pasare al método query()

INSERT INTO acciones VALUES (1, 'I don't want go animal's house')
  • Esto a la hora de insertar me generará un error, ya que el gestor interpreta que el contenido para el campo descripcion es 'I don'
  • Para evitar esto yo querría que el valor de $descripcion estuviera escapado


INSERT INTO acciones VALUES (1, 'I don\'t want go animal\'s house')
se puede conseguir
//...
$descripción  = $conexion->real_scape_string("I don't want go animal's house");
//...
$consulta = "INSERT INTO acciones VALUES (1, '$descripcion')"
//...


Icon present.gif
'Tip: Alternativamente al método de la clase mysqli, podemos usar con metodología estructurada la función mysql_real_scape_string()





Icon present.gif
Tip: Observa el tema de las comillas, los valores de las instrucciones sql sin son de tipo varchar deben de ir entre comillas


$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 ";
}
</sourece>
</div>
<div class="slide">
 
<source lang=php>
$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 clase 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.
  • El método query con una sentencia de tipo select como parámetro, nos retorna un objeto de la clase mysqli_result. Esta clase (recurso) implemente la interfaz Traversable, lo que le hace iterable en los datos que contiene.
  • Esta clase contiene el resultado de la consulta como un conjunto de filas, pero no lo tiene como un atributo visible, si no como parte de los métodos que tenemos disponibles para obtenerlo (los metodos fetch_xxxx)

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.
  • Cuando hablamos de acceder a los datos, estamos estableciendo la forma de extraer cada fila, registro o tupla resultado de ejecutar la consulta.
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
  • visualízalos 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 where 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
  • Esta 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
Transacciones
  • 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->autocommit(false);
 .....
  • Si se ha desactivado el autocommit, para terminar una transacción debemos usar los métodos commit o rollback
 $conexion = new mysqli(..);
 $conexion->autocommit(false);
 .....
 
 if (CondicionOK){
    //Terminamos la transacción confirmando todas las acciones sobre la base de 
    //datos desde que se inició la  transacción
    $conexion->commit();
 }else{
    //Terminamos la transacción deshaciendo  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);
  • Si todo fuera normal y nombre fuera por ejemplo "maría" la consulta que se envía al servidor sería
      select * from usuarios where nombre = "maria"
  • Esta consulta si existe el usuario maría nos retornará una tupla, si no no devolverá ninguna.
Inyecciones sql
  • 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 (?,?);
  • Ahora habría que asigar los valores. Para ello usamos el método bind_param'
bind_param(tipoDatos, variables_con_los_valores)
  • Este método recibe dos tipos de parámetros
  1. 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 :
  1. s: cadena de caracteres
  2. i: número entero
  3. d: número float
  4. b: valor binario (BLOB (binary large object))
Consultas preparadas
  • En nuestro caso como va a recibir en los dos parámetros cada uno una cadena de caracteres sería "ss"
  1. El segundo grupo sería cada uno de los valores.SIEMPRE hay que especificar variables
  • En el ejemplo que estamos siguiendo
$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);
  • Insisto en que siempre hay que especificar variables, nunca directamente valores.
  • Vemos el siguiente ejemplo:
$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()
  • Vemos el siguiente ejemplo
Consultas preparadas que generan valores
$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
Práctica de tienda
  • 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.





Icon activity.jpg
Práctica de tienda
  • 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)
  • Tampoco las de borrado (si el número final de unidades es cero).